From 6dd0a7c2ad1d29700b8f49f2fdb8068e39901db5 Mon Sep 17 00:00:00 2001 From: Viswas Haridas <37623357+JustARatherRidiculouslyLongUsername@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:07:19 +0530 Subject: [PATCH] fix: business central beta bugfixes (#1122) * fix: initialize chart of accounts multiselect when there is no api response (#1110) * fix: remove the posted at date option for ccc expenses grouped by report (#1105) * fix: update login error flow and fix redirect url (#1117) * fix: restrict JE modules to group by expense only (#1113) * fix: restrict JE modules to group by expense only * fix: add a default bank account field for CCC expenses (#1114) * fix: remove validation temporarily (#1111) * fix: add a default bank account field for CCC expenses * fix: add missing options to bank accounts on page init * fix: dynamic content for xero customize settings (#1112) * fix: update sublabel key to avoid build fail (#1116) * fix: Prod fixes of QBD direct (#1118) * fix bugs (#1119) * refactor: capitalization * fix: only ccc exports not being saved (#1121) --------- Co-authored-by: Ashwin Thanaraj <37061471+ashwin1111@users.noreply.github.com> Co-authored-by: Nilesh Pant <58652823+NileshPant1999@users.noreply.github.com> Co-authored-by: Dhaarani <55541808+DhaaraniCIT@users.noreply.github.com> Co-authored-by: Anish Kr Singh <116036738+anishfyle@users.noreply.github.com> --------- Co-authored-by: Ashwin Thanaraj <37061471+ashwin1111@users.noreply.github.com> Co-authored-by: Nilesh Pant <58652823+NileshPant1999@users.noreply.github.com> Co-authored-by: Dhaarani <55541808+DhaaraniCIT@users.noreply.github.com> Co-authored-by: Anish Kr Singh <116036738+anishfyle@users.noreply.github.com> --------- Co-authored-by: Ashwin Thanaraj <37061471+ashwin1111@users.noreply.github.com> Co-authored-by: Nilesh Pant <58652823+NileshPant1999@users.noreply.github.com> Co-authored-by: Dhaarani <55541808+DhaaraniCIT@users.noreply.github.com> Co-authored-by: Anish Kr Singh <116036738+anishfyle@users.noreply.github.com> --- .../business-central-export-setting.model.ts | 5 ++ .../business-central-import-settings.model.ts | 2 +- src/app/core/models/enum/enum.model.ts | 3 +- ...-central-onboarding-landing.component.html | 6 +- ...ss-central-onboarding-landing.component.ts | 8 +- ...ess-central-export-settings.component.html | 18 +++-- ...iness-central-export-settings.component.ts | 78 +++++++++++++------ .../business-central.fixture.ts | 2 + 8 files changed, 82 insertions(+), 40 deletions(-) diff --git a/src/app/core/models/business-central/business-central-configuration/business-central-export-setting.model.ts b/src/app/core/models/business-central/business-central-configuration/business-central-export-setting.model.ts index 6fca3f7e9..d809fe8f8 100644 --- a/src/app/core/models/business-central/business-central-configuration/business-central-export-setting.model.ts +++ b/src/app/core/models/business-central/business-central-configuration/business-central-export-setting.model.ts @@ -15,6 +15,8 @@ export type BusinessCentralExportSetting = { credit_card_expense_date: ExportDateType, default_bank_account_name: string, default_bank_account_id: string, + default_ccc_bank_account_name: string, + default_ccc_bank_account_id: string, name_in_journal_entry: string, employee_field_mapping: string, auto_map_employees: string, @@ -184,6 +186,7 @@ export class BusinessCentralExportSettingModel { cccExportDate: new FormControl(exportSettings?.credit_card_expense_date ? exportSettings?.credit_card_expense_date.toLowerCase() : null), cccExportGroup: new FormControl(exportSettings?.credit_card_expense_grouped_by ? exportSettings?.credit_card_expense_grouped_by: null), defaultBankName: new FormControl(exportSettings?.default_bank_account_name ? findObjectByDestinationId(accounts, exportSettings?.default_bank_account_id) : null), + cccDefaultBankName: new FormControl(exportSettings?.default_ccc_bank_account_name ? findObjectByDestinationId(accounts, exportSettings?.default_ccc_bank_account_id) : null), reimbursableEmployeeMapping: new FormControl(exportSettings?.employee_field_mapping ? exportSettings?.employee_field_mapping : null, Validators.required), journalEntryNamePreference: new FormControl(exportSettings?.name_in_journal_entry ? exportSettings?.name_in_journal_entry : null), autoMapEmployee: new FormControl(exportSettings?.auto_map_employees ? exportSettings?.auto_map_employees : null), @@ -204,6 +207,8 @@ export class BusinessCentralExportSettingModel { credit_card_expense_date: exportSettingsForm.get('cccExportDate')?.value ? exportSettingsForm.get('cccExportDate')?.value.toUpperCase() : null, default_bank_account_name: exportSettingsForm.get('defaultBankName')?.value ? exportSettingsForm.get('defaultBankName')?.value.value : null, default_bank_account_id: exportSettingsForm.get('defaultBankName')?.value ? exportSettingsForm.get('defaultBankName')?.value.destination_id : null, + default_ccc_bank_account_name: exportSettingsForm.get('cccDefaultBankName')?.value ? exportSettingsForm.get('cccDefaultBankName')?.value.value : null, + default_ccc_bank_account_id: exportSettingsForm.get('cccDefaultBankName')?.value ? exportSettingsForm.get('cccDefaultBankName')?.value.destination_id : null, name_in_journal_entry: exportSettingsForm.get('journalEntryNamePreference')?.value ? exportSettingsForm.get('journalEntryNamePreference')?.value : null, employee_field_mapping: exportSettingsForm.get('reimbursableEmployeeMapping')?.value ? exportSettingsForm.get('reimbursableEmployeeMapping')?.value : null, auto_map_employees: exportSettingsForm.get('autoMapEmployee')?.value ? exportSettingsForm.get('autoMapEmployee')?.value : null, diff --git a/src/app/core/models/business-central/business-central-configuration/business-central-import-settings.model.ts b/src/app/core/models/business-central/business-central-configuration/business-central-import-settings.model.ts index 4a149bc2c..cc92f71c7 100644 --- a/src/app/core/models/business-central/business-central-configuration/business-central-import-settings.model.ts +++ b/src/app/core/models/business-central/business-central-configuration/business-central-import-settings.model.ts @@ -26,7 +26,7 @@ export class BusinessCentralImportSettingsModel extends ImportSettingsModel { const expenseFieldsArray = importSettings?.mapping_settings ? this.constructFormArray(importSettings.mapping_settings, businessCentralFields) : [] ; return new FormGroup({ importCategories: new FormControl(importSettings?.import_settings?.import_categories ?? false), - chartOfAccountTypes: new FormControl(importSettings?.import_settings.charts_of_accounts ? importSettings?.import_settings.charts_of_accounts : ['Expense']), + chartOfAccountTypes: new FormControl(importSettings?.import_settings?.charts_of_accounts ? importSettings?.import_settings?.charts_of_accounts : ['Expense']), importVendorAsMerchant: new FormControl(importSettings?.import_settings?.import_vendors_as_merchants ?? false ), expenseFields: new FormArray(expenseFieldsArray) }); diff --git a/src/app/core/models/enum/enum.model.ts b/src/app/core/models/enum/enum.model.ts index 861f6cf26..5104c7f28 100644 --- a/src/app/core/models/enum/enum.model.ts +++ b/src/app/core/models/enum/enum.model.ts @@ -702,9 +702,8 @@ export enum Sage300ExportSettingDestinationOptionKey { } export enum BCExportSettingDestinationOptionKey { - ACCOUNT = 'ACCOUNT', VENDOR = 'VENDOR', - REIMBURSABLE_BANK_ACCOUNT = 'REIMBURSABLE_BANK_ACCOUNT' + BANK_ACCOUNT = 'BANK_ACCOUNT' } export enum QbdDirectExportSettingDestinationOptionKey { diff --git a/src/app/integrations/business-central/business-central-onboarding/business-central-onboarding-landing/business-central-onboarding-landing.component.html b/src/app/integrations/business-central/business-central-onboarding/business-central-onboarding-landing/business-central-onboarding-landing.component.html index a8428cf09..264ebdc7a 100644 --- a/src/app/integrations/business-central/business-central-onboarding/business-central-onboarding-landing/business-central-onboarding-landing.component.html +++ b/src/app/integrations/business-central/business-central-onboarding/business-central-onboarding-landing/business-central-onboarding-landing.component.html @@ -1,4 +1,4 @@ -
+
@@ -6,9 +6,9 @@
- { const errorMessage = 'message' in error.error ? error.error.message : 'Failed to connect to Dynamic 365 Business Central. Please try again'; if (errorMessage === 'Please choose the correct Dynamic 365 Business Central account') { - this.isIncorrectQBOConnectedDialogVisible = false; + this.isIncorrectBCConnectedDialogVisible = true; } else { this.toastService.displayToastMessage(ToastSeverity.ERROR, errorMessage); this.router.navigate([`/integrations/business_central/onboarding/landing`]); diff --git a/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.html b/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.html index d4ec92e13..214b445e3 100644 --- a/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.html +++ b/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.html @@ -91,8 +91,8 @@ [mandatoryErrorListName]="'Default Bank Account Name'" [label]="'Set the Default Bank Account as?'" [subLabel]="'The integration will assign the Expenses that is exported as Journal Entry to the Bank Account selected here.'" - [destinationAttributes]="reimbursableBankOptions" - [destinationOptionKey]="BCExportSettingDestinationOptionKey.REIMBURSABLE_BANK_ACCOUNT" + [destinationAttributes]="bankAccountOptions" + [destinationOptionKey]="BCExportSettingDestinationOptionKey.BANK_ACCOUNT" [isOptionSearchInProgress]="isOptionSearchInProgress" [isAdvanceSearchEnabled]="true" (searchOptionsDropdown)="searchOptionsDropdown($event)" @@ -113,7 +113,8 @@ [iconPath]="'question-square-outline'" [placeholder]="'Select expense grouping'" [formControllerName]="'reimbursableExportGroup'" - [appName]="appName"> + [appName]="appName" + [isDisabled]="exportSettingForm.get('reimbursableExportType')?.value === BusinessCentralExportType.JOURNAL_ENTRY">
@@ -172,21 +173,21 @@ [exportTypeIconPathArray]="previewImagePaths">
-
+
+ [formControllerName]="'cccDefaultBankName'">
@@ -217,7 +218,8 @@ [iconPath]="'question-square-outline'" [placeholder]="'Select expense grouping'" [formControllerName]="'cccExportGroup'" - [appName]="appName"> + [appName]="appName" + [isDisabled]="exportSettingForm.get('cccExportType')?.value === BusinessCentralExportType.JOURNAL_ENTRY">
diff --git a/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.ts b/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.ts index 438b0cac2..87c43b1a0 100644 --- a/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.ts +++ b/src/app/integrations/business-central/business-central-shared/business-central-export-settings/business-central-export-settings.component.ts @@ -29,9 +29,7 @@ export class BusinessCentralExportSettingsComponent implements OnInit { exportSettingForm: FormGroup; - bankOptions: DestinationAttribute[]; - - reimbursableBankOptions: DestinationAttribute[]; + bankAccountOptions: DestinationAttribute[]; vendorOptions: DestinationAttribute[]; @@ -142,13 +140,23 @@ export class BusinessCentralExportSettingsComponent implements OnInit { if (this.exportSettingForm.controls[formControllerName].value === ExpenseGroupedBy.EXPENSE) { return options.filter(option => option.value !== ExportDateType.LAST_SPENT_AT); } - return options.filter(option => option.value !== ExportDateType.SPENT_AT); + return options.filter(option => (option.value !== ExportDateType.SPENT_AT && option.value !== ExportDateType.POSTED_AT)); } refreshDimensions(isRefresh: boolean): void{ this.businessCentralHelperService.importAttributes(isRefresh); } + updateExpenseGroupingValues() { + if (this.exportSettingForm.get('cccExportType')?.value === BusinessCentralExportType.JOURNAL_ENTRY) { + this.exportSettingForm.get('cccExportGroup')?.setValue(ExpenseGroupedBy.EXPENSE); + } + + if (this.exportSettingForm.get('reimbursableExportType')?.value === BusinessCentralExportType.JOURNAL_ENTRY) { + this.exportSettingForm.get('reimbursableExportGroup')?.setValue(ExpenseGroupedBy.EXPENSE); + } + } + private setupCustomWatchers(): void { this.exportSettingForm.controls.reimbursableExportGroup.valueChanges.subscribe((reimbursableExportGroup) => { if (brandingConfig.brandId==='fyle') { @@ -161,8 +169,17 @@ export class BusinessCentralExportSettingsComponent implements OnInit { if (brandingConfig.brandId==='fyle') { this.cccExpenseGroupingDateOptions = BusinessCentralExportSettingModel.getCCCExpenseGroupingDateOptions(); this.cccExpenseGroupingDateOptions = ExportSettingModel.constructGroupingDateOptions(cccExportGroup, this.cccExpenseGroupingDateOptions); + + // If the selected value is not valid after the export group change, reset the field + const visibleValues = this.getExportDate(this.cccExpenseGroupingDateOptions, 'cccExportGroup').map(option => option.value); + if (!visibleValues.includes(this.exportSettingForm.get('cccExportDate')?.value)) { + this.exportSettingForm.get('cccExportDate')?.reset(); + } } }); + + this.exportSettingForm.get('reimbursableExportType')?.valueChanges.subscribe(() => this.updateExpenseGroupingValues()); + this.exportSettingForm.get('cccExportType')?.valueChanges.subscribe(() => this.updateExpenseGroupingValues()); } private optionSearchWatcher(): void { @@ -170,7 +187,7 @@ export class BusinessCentralExportSettingsComponent implements OnInit { debounceTime(1000) ).subscribe((event: ExportSettingOptionSearch) => { - if (event.destinationOptionKey === BCExportSettingDestinationOptionKey.REIMBURSABLE_BANK_ACCOUNT) { + if (event.destinationOptionKey === BCExportSettingDestinationOptionKey.BANK_ACCOUNT) { const observables = [ this.mappingService.getPaginatedDestinationAttributes('BANK_ACCOUNT', event.searchTerm), this.mappingService.getPaginatedDestinationAttributes( @@ -182,12 +199,12 @@ export class BusinessCentralExportSettingsComponent implements OnInit { // Insert new options (if any) to existing options, and sort them const newOptions = [...bankAccounts.results, ...accounts.results]; newOptions.forEach((newOption) => { - if (!this.reimbursableBankOptions.find((existingOption) => existingOption.destination_id === newOption.destination_id)) { - this.reimbursableBankOptions.push(newOption); + if (!this.bankAccountOptions.find((existingOption) => existingOption.destination_id === newOption.destination_id)) { + this.bankAccountOptions.push(newOption); } }); - this.reimbursableBankOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); + this.bankAccountOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); this.isOptionSearchInProgress = false; }); @@ -195,9 +212,6 @@ export class BusinessCentralExportSettingsComponent implements OnInit { let existingOptions: DestinationAttribute[]; switch (event.destinationOptionKey) { - case BCExportSettingDestinationOptionKey.ACCOUNT: - existingOptions = this.bankOptions; - break; case BCExportSettingDestinationOptionKey.VENDOR: existingOptions = this.vendorOptions; break; @@ -214,10 +228,6 @@ export class BusinessCentralExportSettingsComponent implements OnInit { switch (event.destinationOptionKey) { - case BCExportSettingDestinationOptionKey.ACCOUNT: - this.bankOptions = existingOptions.concat(); - this.bankOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); - break; case BCExportSettingDestinationOptionKey.VENDOR: this.vendorOptions = existingOptions.concat(); this.vendorOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); @@ -237,6 +247,29 @@ export class BusinessCentralExportSettingsComponent implements OnInit { } } + addMissingOptions() { + // Since pagination API response is a subset of all options, we're making use of the export settings response to fill in options + + if (this.exportSettings) { + this.helperService.addDestinationAttributeIfNotExists({ + options: this.bankAccountOptions, + value: this.exportSettings.default_ccc_bank_account_name, + destination_id: this.exportSettings.default_ccc_bank_account_id + }); + this.helperService.addDestinationAttributeIfNotExists({ + options: this.bankAccountOptions, + value: this.exportSettings.default_bank_account_name, + destination_id: this.exportSettings.default_bank_account_id + }); + + this.helperService.addDestinationAttributeIfNotExists({ + options: this.vendorOptions, + value: this.exportSettings.default_vendor_name, + destination_id: this.exportSettings.default_vendor_id + }); + } + } + private setupPage(): void { this.isOnboarding = this.router.url.includes('onboarding'); const exportSettingValidatorRule: ExportSettingValidatorRule = { @@ -254,11 +287,11 @@ export class BusinessCentralExportSettingsComponent implements OnInit { { 'formController': 'cccExportType', 'requiredValue': { - 'JOURNAL_ENTRY': ['defaultBankName', 'journalEntryNamePreference'] + 'JOURNAL_ENTRY': ['cccDefaultBankName', 'journalEntryNamePreference'] } } ]; - const commonFormFields: string[] = ['defaultBankName']; + const commonFormFields: string[] = []; const destinationAttributes = [BusinessCentralField.ACCOUNT, FyleField.VENDOR]; @@ -295,14 +328,15 @@ export class BusinessCentralExportSettingsComponent implements OnInit { }); } - this.exportSettingForm = BusinessCentralExportSettingModel.mapAPIResponseToFormGroup(this.exportSettings, accounts.results, vendors.results); + this.vendorOptions = vendors.results; + this.bankAccountOptions = [...reimbursableBankAccounts.results, ...reimbursableAccounts.results]; + this.bankAccountOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); + this.addMissingOptions(); + this.exportSettingForm = BusinessCentralExportSettingModel.mapAPIResponseToFormGroup(this.exportSettings, this.bankAccountOptions, vendors.results); + this.helperService.addExportSettingFormValidator(this.exportSettingForm); this.helper.setConfigurationSettingValidatorsAndWatchers(exportSettingValidatorRule, this.exportSettingForm); this.helper.setExportTypeValidatorsAndWatchers(exportModuleRule, this.exportSettingForm, commonFormFields); - this.bankOptions = accounts.results; - this.vendorOptions = vendors.results; - this.reimbursableBankOptions = [...reimbursableBankAccounts.results, ...reimbursableAccounts.results]; - this.reimbursableBankOptions.sort((a, b) => (a.value || '').localeCompare(b.value || '')); this.setupCustomWatchers(); this.optionSearchWatcher(); diff --git a/src/app/integrations/business-central/business-central-shared/business-central.fixture.ts b/src/app/integrations/business-central/business-central-shared/business-central.fixture.ts index 8af0c393e..07c1a755d 100644 --- a/src/app/integrations/business-central/business-central-shared/business-central.fixture.ts +++ b/src/app/integrations/business-central/business-central-shared/business-central.fixture.ts @@ -12,6 +12,8 @@ export const exportSettingsResponse: BusinessCentralExportSettingGet = { "reimbursable_expenses_export_type": BusinessCentralExportType.JOURNAL_ENTRY, "default_bank_account_name": "XYZ", "default_bank_account_id": "1232", + "default_ccc_bank_account_name": "ABC", + "default_ccc_bank_account_id": "2321", "reimbursable_expense_state": ExpenseState.PAYMENT_PROCESSING, "reimbursable_expense_date": ExportDateType.LAST_SPENT_AT, "reimbursable_expense_grouped_by": ExpenseGroupedBy.EXPENSE,