Skip to content

Comments

feat: quickbooks export-settings generalise validators#1761

Open
vignesh05904 wants to merge 2 commits intomasterfrom
qbo-validators-improvements
Open

feat: quickbooks export-settings generalise validators#1761
vignesh05904 wants to merge 2 commits intomasterfrom
qbo-validators-improvements

Conversation

@vignesh05904
Copy link
Contributor

@vignesh05904 vignesh05904 commented Feb 23, 2026

Description

quickbooks export-settings generalise validators

Clickup

https://app.clickup.com

Summary by CodeRabbit

Release Notes

  • New Features

    • QuickBooks export settings form now features intelligent field visibility—fields dynamically appear or disappear based on your selections and employee mapping context.
    • Field requirements are now context-aware, automatically adjusting which settings are mandatory based on your configuration choices.
  • Refactor

    • Enhanced internal handling of form validation logic for improved performance and maintainability.

@github-actions github-actions bot added the size/L Large PR label Feb 23, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 23, 2026

Walkthrough

This PR introduces a centralized field visibility and mandatory-field validation system for QBO export settings. It adds a new form model type, validation constants and dependency checkers, then refactors the component and template to use centralized showField() and isFieldMandatory() methods instead of scattered conditional logic throughout the codebase.

Changes

Cohort / File(s) Summary
Form Model Type
src/app/core/models/qbo/qbo-configuration/qbo-export-setting.model.ts
Added new exported type QboExportSettingsForm defining a collection of FormControl fields for various QBO export settings (employee mapping, reimbursable/export type, bank/account mappings, expense state and grouping, credit card settings, journal entry name, default accounts, etc.).
Validation & Dependencies
src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts
Introduced new type alias QboDependencyChecker and exported constants QBO_REIMBURSABLE_FIELDS, QBO_FIELD_DEPENDENCIES, and QBO_MANDATORY_FIELD_RULES to standardize field visibility and mandatory-field logic. Extended mapAPIResponseToFormGroup() to accept optional getEmployeeMapping callback, enabling dynamic validation when present. FormGroup validators now ensure reimbursable/CCC selection rules and apply dependency-based visibility/mandatory checks.
Component Refactoring
src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.ts
Refactored constructor to include new service injections (toast, window, workspace, employee settings, export settings, branding, storage); added public showField() and isFieldMandatory() helper methods for centralized field control. Removed prior visibility/mandatoriness getters. Updated form initialization to pass employee-mapping callback and subscribe to employeeMapping changes for reactive validity updates. Replaced scattered validation wiring with simplified updateValueAndValidity approach.
Template Updates
src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.html
Replaced inline conditional checks of form control states with centralized showField() predicate for field visibility across multiple UI sections (reimbursable export type, bank/account mappings, journal entry, credit card settings, expense grouping, etc.). Updated isFieldMandatory binding to use dynamic predicate method call.

Sequence Diagram(s)

sequenceDiagram
    participant Component as QboExportSettingsComponent
    participant Service as QboExportSettingsService
    participant FormGroup as FormGroup+Validators
    participant Template as Template View
    
    Component->>Service: mapAPIResponseToFormGroup(settings, mapping, getEmployeeMapping callback)
    Service->>FormGroup: Create FormGroup with custom validators
    FormGroup->>FormGroup: Validators iterate QBO_FIELD_DEPENDENCIES
    FormGroup->>FormGroup: Check visibility & mandatory rules via QBO_MANDATORY_FIELD_RULES
    Service-->>Component: Return FormGroup with validation logic
    
    Component->>Component: Subscribe to employeeMapping.valueChanges
    Component->>FormGroup: On employeeMapping change: updateValueAndValidity()
    FormGroup->>FormGroup: Re-apply validators with updated mapping
    FormGroup-->>Component: Emit validity/validation errors
    
    Component->>Component: showField(field), isFieldMandatory(field) called by template
    Component-->>Template: Return field visibility & mandatory status
    Template->>Template: Render/hide fields based on showField() result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 Behold, a field-orchestration delight,
Dependencies dance in validation's bright light,
Show when you're ready, hide when you're not,
Centralized wisdom, beautifully wrought!
From scattered chaos to clarity pure—
QBO export settings, now cleaner for sure!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description is incomplete and vague. While it repeats the title and includes a ClickUp link, it lacks meaningful detail about the changes, their purpose, or technical context as suggested by the template. Expand the description to explain what validators are being generalized, why this change was necessary, and any key implementation details or breaking changes that reviewers should know about.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: generalizing validators for quickbooks export-settings, which aligns with the significant refactoring of validation logic across multiple files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch qbo-validators-improvements

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

🔁 Code Duplication Report - Angular

Format Files analyzed Total lines Total tokens Clones found Duplicated lines Duplicated tokens
typescript 786 58469 535953 347 5750 (9.83%) -0.03% 🚀 53959 (10.07%) -0.03% 🚀
scss 68 3795 20521 7 148 (3.90%) 769 (3.75%)
markup 352 17798 166908 155 2071 (11.64%) -0.19% 🚀 17525 (10.50%) -0.13% 🚀
python 4 727 5680 3 32 (4.40%) 368 (6.48%)
yaml 3 155 905 0 0 (0.00%) 0 (0.00%)
javascript 6 397 3497 0 0 (0.00%) 0 (0.00%)
markdown 2 96 366 0 0 (0.00%) 0 (0.00%)
bash 2 69 804 0 0 (0.00%) 0 (0.00%)
Total: 1223 81506 734634 512 8001 (9.82%) -0.06% 🚀 72621 (9.89%) -0.05% 🚀

🎉 This PR reduces duplicated code by 0.05%!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.html (1)

111-131: ⚠️ Potential issue | 🔴 Critical

accountsPayable may lose mandatory enforcement when reimbursable export type is BILL.

Line 121 uses [isFieldMandatory]="isFieldMandatory('accountsPayable')". The component's isFieldMandatory method delegates to QBO_MANDATORY_FIELD_RULES['accountsPayable'], which only returns true for JOURNAL_ENTRY + VENDOR. When the reimbursable export type is BILL, the override returns false — making accountsPayable appear optional in the UI.

Additionally, the form-level validator (service Lines 331-335) uses the same override, so the form will be considered valid without an accountsPayable value when BILL is selected. Previously, getMandatoryField returned true for BILL, meaning this is a regression.

The root cause is in QBO_MANDATORY_FIELD_RULES in the service file — the accountsPayable entry should also return true when reimbursable export type is BILL, or it should be removed entirely from QBO_MANDATORY_FIELD_RULES so visibility implies mandatoriness (the default).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.html`
around lines 111 - 131, QBO_MANDATORY_FIELD_RULES currently marks
accountsPayable as mandatory only for JOURNAL_ENTRY and VENDOR, causing
isFieldMandatory('accountsPayable') and the form validator to permit missing
accountsPayable when reimbursableExportType === BILL; update
QBO_MANDATORY_FIELD_RULES so the accountsPayable rule also returns true for BILL
(or remove the accountsPayable entry to inherit default-visible-is-mandatory
behavior), then verify isFieldMandatory, getMandatoryField (or the form-level
validator logic that references QBO_MANDATORY_FIELD_RULES) will treat
accountsPayable as required when reimbursableExportType is BILL.
🧹 Nitpick comments (3)
src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts (2)

66-72: Clarify the semantics of QBO_MANDATORY_FIELD_RULES vs. visibility.

The accountsPayable mandatory rule (Lines 67-69) returns true when reimbursableExportType === JOURNAL_ENTRY && employeeMapping === VENDOR. However, accountsPayable visibility (Lines 37-41) also includes reimbursableExportType === BILL. When BILL is selected, visibility is true but there's no mandatory override → the default in the validator is true (Line 332), making it mandatory. This works correctly but the dual-table lookup (visibility + mandatory override) can be confusing.

Consider adding a brief inline comment documenting the convention: "Fields not listed here default to mandatory when visible."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts`
around lines 66 - 72, The QBO_MANDATORY_FIELD_RULES map currently only overrides
specific fields (e.g., accountsPayable) and relies on the validator default that
a visible field is mandatory, which is confusing given the separate visibility
rules (see accountsPayable visibility using reimbursableExportType === BILL);
add a concise inline comment above the QBO_MANDATORY_FIELD_RULES declaration
explaining the convention: that this map contains only exceptions/overrides and
that any field not listed here is considered mandatory when visible by the
validator (mention QBO_MANDATORY_FIELD_RULES, accountsPayable,
reimbursableExportType and the validator default behavior to help locate the
logic).

7-14: Duplicate imports from @angular/forms and enum.model.

FormControl is imported on Line 12, and AbstractControl, FormGroup, ValidationErrors on Line 7 — both from @angular/forms. Similarly, SplitExpenseGrouping is imported on Line 11, and more enum members on Line 14 — both from src/app/core/models/enum/enum.model. Consolidate each into a single import statement.

♻️ Proposed consolidation
-import { AbstractControl, FormGroup, ValidationErrors } from '@angular/forms';
 ...
-import { SplitExpenseGrouping } from 'src/app/core/models/enum/enum.model';
-import { FormControl, Validators } from '@angular/forms';
 ...
-import { CCCExpenseState, ExpenseState, ExportDateType, NameInJournalEntry, ExpenseGroupingFieldOption, EmployeeFieldMapping, QBOReimbursableExpensesObject, QBOCorporateCreditCardExpensesObject } from 'src/app/core/models/enum/enum.model';
+import { AbstractControl, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms';
+import { CCCExpenseState, ExpenseState, ExportDateType, NameInJournalEntry, ExpenseGroupingFieldOption, EmployeeFieldMapping, QBOReimbursableExpensesObject, QBOCorporateCreditCardExpensesObject, SplitExpenseGrouping } from 'src/app/core/models/enum/enum.model';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts`
around lines 7 - 14, There are duplicate imports from '@angular/forms' and from
'src/app/core/models/enum/enum.model'; consolidate into single import statements
to avoid redundancy: merge AbstractControl, FormGroup, ValidationErrors,
FormControl, and Validators into one import from '@angular/forms' and merge
SplitExpenseGrouping together with CCCExpenseState, ExpenseState,
ExportDateType, NameInJournalEntry, ExpenseGroupingFieldOption,
EmployeeFieldMapping, QBOReimbursableExpensesObject, and
QBOCorporateCreditCardExpensesObject into one import from
'src/app/core/models/enum/enum.model'; update the import list at the top of
qbo-export-settings.service.ts so each module is imported only once while
preserving all referenced symbols (e.g., FormControl, AbstractControl,
SplitExpenseGrouping, CCCExpenseState, etc.).
src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.ts (1)

155-183: Duplicate injection of QboEmployeeSettingsService and duplicate option initialization.

  1. Both employeeSettingService (Line 164) and qboEmployeeSettingsService (Line 167) are of type QboEmployeeSettingsService. Use a single instance.

  2. Lines 172-182 (constructor) initialize the same option arrays that are re-initialized in ngOnInit (Lines 604-613). The constructor assignments are immediately overwritten and can be removed.

♻️ Remove duplicate injection and constructor initialization
 constructor(
   private translocoService: TranslocoService,
   private helperService: HelperService,
   private qboHelperService: QboHelperService,
   private mappingService: MappingService,
   private router: Router,
   private toastService: IntegrationsToastService,
   private windowService: WindowService,
   private workspaceService: WorkspaceService,
-  private employeeSettingService: QboEmployeeSettingsService,
   private qboExportSettingsService: QboExportSettingsService,
   private employeeSettingsService: EmployeeSettingsService,
   private qboEmployeeSettingsService: QboEmployeeSettingsService,
   public brandingService: BrandingService,
   private storageService: StorageService
 ) {
   this.windowReference = this.windowService.nativeWindow;
-  this.reimbursableExpenseGroupingDateOptions = this.qboExportSettingsService.getReimbursableExpenseGroupingDateOptions();
-  this.creditCardExportTypes = this.qboExportSettingsService.getCreditCardExportTypes();
-  this.cccExpenseStateOptions = this.qboExportSettingsService.getCCCExpenseStateOptions();
-  this.expenseStateOptions = this.qboExportSettingsService.getReimbursableExpenseStateOptions();
-  this.expenseGroupByOptions = this.qboExportSettingsService.getExpenseGroupByOptions();
-  this.cccExpenseGroupingDateOptions = this.reimbursableExpenseGroupingDateOptions.concat();
-  this.nameInJournalOptions = this.qboExportSettingsService.getNameInJournalOptions();
-  this.splitExpenseGroupingOptions = this.qboExportSettingsService.getSplitExpenseGroupingOptions();
-  this.employeeMappingOptions = this.employeeSettingsService.getEmployeeFieldMappingOptions();
-  this.autoMapEmployeeOptions = this.qboEmployeeSettingsService.getAutoMapEmployeeOptions();
   this.showWarningMessageAboutAutoExpenseCreation = this.storageService.get('showWarningMessageAboutAutoExpenseCreationInQBO') ?? true;
 }

Then update the postEmployeeSettings call on Line 243 to use qboEmployeeSettingsService instead of employeeSettingService.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.ts`
around lines 155 - 183, Remove the duplicate QboEmployeeSettingsService
injection (remove the employeeSettingService constructor parameter) and keep
qboEmployeeSettingsService; delete the constructor assignments that duplicate
ngOnInit (remove initialization of reimbursableExpenseGroupingDateOptions,
creditCardExportTypes, cccExpenseStateOptions, expenseStateOptions,
expenseGroupByOptions, cccExpenseGroupingDateOptions, nameInJournalOptions,
splitExpenseGroupingOptions, employeeMappingOptions, autoMapEmployeeOptions,
showWarningMessageAboutAutoExpenseCreation) so they are only initialized in
ngOnInit, and update the postEmployeeSettings call to use
qboEmployeeSettingsService instead of employeeSettingService (referencing the
constructor, ngOnInit, postEmployeeSettings, employeeSettingService,
qboEmployeeSettingsService and the listed option properties).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.html`:
- Around line 111-131: QBO_MANDATORY_FIELD_RULES currently marks accountsPayable
as mandatory only for JOURNAL_ENTRY and VENDOR, causing
isFieldMandatory('accountsPayable') and the form validator to permit missing
accountsPayable when reimbursableExportType === BILL; update
QBO_MANDATORY_FIELD_RULES so the accountsPayable rule also returns true for BILL
(or remove the accountsPayable entry to inherit default-visible-is-mandatory
behavior), then verify isFieldMandatory, getMandatoryField (or the form-level
validator logic that references QBO_MANDATORY_FIELD_RULES) will treat
accountsPayable as required when reimbursableExportType is BILL.

---

Nitpick comments:
In `@src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts`:
- Around line 66-72: The QBO_MANDATORY_FIELD_RULES map currently only overrides
specific fields (e.g., accountsPayable) and relies on the validator default that
a visible field is mandatory, which is confusing given the separate visibility
rules (see accountsPayable visibility using reimbursableExportType === BILL);
add a concise inline comment above the QBO_MANDATORY_FIELD_RULES declaration
explaining the convention: that this map contains only exceptions/overrides and
that any field not listed here is considered mandatory when visible by the
validator (mention QBO_MANDATORY_FIELD_RULES, accountsPayable,
reimbursableExportType and the validator default behavior to help locate the
logic).
- Around line 7-14: There are duplicate imports from '@angular/forms' and from
'src/app/core/models/enum/enum.model'; consolidate into single import statements
to avoid redundancy: merge AbstractControl, FormGroup, ValidationErrors,
FormControl, and Validators into one import from '@angular/forms' and merge
SplitExpenseGrouping together with CCCExpenseState, ExpenseState,
ExportDateType, NameInJournalEntry, ExpenseGroupingFieldOption,
EmployeeFieldMapping, QBOReimbursableExpensesObject, and
QBOCorporateCreditCardExpensesObject into one import from
'src/app/core/models/enum/enum.model'; update the import list at the top of
qbo-export-settings.service.ts so each module is imported only once while
preserving all referenced symbols (e.g., FormControl, AbstractControl,
SplitExpenseGrouping, CCCExpenseState, etc.).

In
`@src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.ts`:
- Around line 155-183: Remove the duplicate QboEmployeeSettingsService injection
(remove the employeeSettingService constructor parameter) and keep
qboEmployeeSettingsService; delete the constructor assignments that duplicate
ngOnInit (remove initialization of reimbursableExpenseGroupingDateOptions,
creditCardExportTypes, cccExpenseStateOptions, expenseStateOptions,
expenseGroupByOptions, cccExpenseGroupingDateOptions, nameInJournalOptions,
splitExpenseGroupingOptions, employeeMappingOptions, autoMapEmployeeOptions,
showWarningMessageAboutAutoExpenseCreation) so they are only initialized in
ngOnInit, and update the postEmployeeSettings call to use
qboEmployeeSettingsService instead of employeeSettingService (referencing the
constructor, ngOnInit, postEmployeeSettings, employeeSettingService,
qboEmployeeSettingsService and the listed option properties).
ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1417032 and 7f23ac7.

📒 Files selected for processing (4)
  • src/app/core/models/qbo/qbo-configuration/qbo-export-setting.model.ts
  • src/app/core/services/qbo/qbo-configuration/qbo-export-settings.service.ts
  • src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.html
  • src/app/integrations/qbo/qbo-shared/qbo-export-settings/qbo-export-settings.component.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Large PR

Development

Successfully merging this pull request may close these issues.

1 participant