Skip to content

Commit

Permalink
fix: business central beta bugfixes (#1122)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Nilesh Pant <[email protected]>
Co-authored-by: Dhaarani <[email protected]>
Co-authored-by: Anish Kr Singh <[email protected]>

---------

Co-authored-by: Ashwin Thanaraj <[email protected]>
Co-authored-by: Nilesh Pant <[email protected]>
Co-authored-by: Dhaarani <[email protected]>
Co-authored-by: Anish Kr Singh <[email protected]>

---------

Co-authored-by: Ashwin Thanaraj <[email protected]>
Co-authored-by: Nilesh Pant <[email protected]>
Co-authored-by: Dhaarani <[email protected]>
Co-authored-by: Anish Kr Singh <[email protected]>
  • Loading branch information
5 people authored Dec 12, 2024
1 parent d1d596e commit 6dd0a7c
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
Expand Down
3 changes: 1 addition & 2 deletions src/app/core/models/enum/enum.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<div *ngIf="!isIncorrectQBOConnectedDialogVisible">
<div *ngIf="!isIncorrectBCConnectedDialogVisible">
<div>
<app-landing-page-header [logoWidth]="'65px'" [logoStyleClasses]="'tw-p-0'" [logoSectionStyleClasses]="''" [iconPath]="'assets/logos/BusinessCentral-logo.svg'" [appName]="'Dynamics 365 Business Central'" [appDescription]="'Import data from Dynamics 365 Business Central to ' + brandingConfig.brandName + ' and Export expenses from ' + brandingConfig.brandName + ' to Dynamics 365 Business Central. '" [isLoading]="false" [isIntegrationSetupInProgress]="businessCentralConnectionInProgress" [isIntegrationConnected]="isIntegrationConnected" [redirectLink]="redirectLink" [buttonText]="'Connect'" [postConnectionRoute]="'business_central/onboarding/connector'" (connectIntegration)="connectBusinessCentral()"></app-landing-page-header>
</div>
<div>
<app-landing-page-body [headlineText]="'Guide to setup your Integrations'" [headerText]="'A quick guide to help you set up the integration quick and easy.'" [svgPath]="'assets/flow-charts/ms-dynamics-flow-chart.svg'" [appName]="appName"></app-landing-page-body>
</div>
</div>
<app-configuration-confirmation-dialog *ngIf="isIncorrectQBOConnectedDialogVisible"
<app-configuration-confirmation-dialog *ngIf="isIncorrectBCConnectedDialogVisible"
(warningAccepted)="acceptWarning($event)"
[isWarningVisible]="isIncorrectQBOConnectedDialogVisible"
[isWarningVisible]="isIncorrectBCConnectedDialogVisible"
[headerText]="'Incorrect account selected'"
[contextText]="'You had previously set up the integration with a different Dynamic 365 Business Central account. Please choose the same to restore the settings'"
[confirmBtnText]="'Re connect'"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class BusinessCentralOnboardingLandingComponent implements OnInit, OnDest

private oauthCallbackSubscription: Subscription;

isIncorrectQBOConnectedDialogVisible: boolean;
isIncorrectBCConnectedDialogVisible: boolean;

constructor(
private helperService: HelperService,
Expand All @@ -45,9 +45,9 @@ export class BusinessCentralOnboardingLandingComponent implements OnInit, OnDest
) { }

acceptWarning(data: ConfigurationWarningOut): void {
this.isIncorrectQBOConnectedDialogVisible = false;
this.isIncorrectBCConnectedDialogVisible = false;
if (data.hasAccepted) {
this.router.navigate([`/integrations/qbo/onboarding/landing`]);
this.router.navigate([`/integrations/business_central/onboarding/landing`]);
}
}

Expand All @@ -72,7 +72,7 @@ export class BusinessCentralOnboardingLandingComponent implements OnInit, OnDest
}, (error) => {
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`]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand All @@ -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">
</app-configuration-select-field>
</div>
<div *ngIf="exportSettingForm?.value.reimbursableExportType" class="tw-mt-16-px tw-bg-white tw-border tw-border-solid tw-border-separator tw-rounded-12-px">
Expand Down Expand Up @@ -172,21 +173,21 @@
[exportTypeIconPathArray]="previewImagePaths">
</app-configuration-select-field>
</div>
<div *ngIf="exportSettingForm.get('cccExportType')?.value && exportSettingForm.get('reimbursableExportType')?.value !== BusinessCentralExportType.JOURNAL_ENTRY" class="tw-mt-16-px tw-bg-white tw-border tw-border-solid tw-border-separator tw-rounded-12-px">
<div *ngIf="exportSettingForm.get('cccExportType')?.value === BusinessCentralExportType.JOURNAL_ENTRY" class="tw-mt-16-px tw-bg-white tw-border tw-border-solid tw-border-separator tw-rounded-12-px">
<app-configuration-select-field
[form]="exportSettingForm"
[isFieldMandatory]="true"
[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]="bankOptions"
[destinationOptionKey]="BCExportSettingDestinationOptionKey.ACCOUNT"
[destinationAttributes]="bankAccountOptions"
[destinationOptionKey]="BCExportSettingDestinationOptionKey.BANK_ACCOUNT"
[isOptionSearchInProgress]="isOptionSearchInProgress"
[isAdvanceSearchEnabled]="true"
(searchOptionsDropdown)="searchOptionsDropdown($event)"
[iconPath]="'list'"
[placeholder]="'Select default Bank Account'"
[formControllerName]="'defaultBankName'">
[formControllerName]="'cccDefaultBankName'">
</app-configuration-select-field>
</div>
<div *ngIf="exportSettingForm.get('cccExportType')?.value" class="tw-mt-16-px tw-bg-white tw-border tw-border-solid tw-border-separator tw-rounded-12-px">
Expand Down Expand Up @@ -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">
</app-configuration-select-field>
</div>
<div *ngIf="!exportSettingForm.get('reimbursableExpense')?.value" class="tw-mt-16-px tw-bg-white tw-border tw-border-solid tw-border-separator tw-rounded-12-px">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,7 @@ export class BusinessCentralExportSettingsComponent implements OnInit {

exportSettingForm: FormGroup;

bankOptions: DestinationAttribute[];

reimbursableBankOptions: DestinationAttribute[];
bankAccountOptions: DestinationAttribute[];

vendorOptions: DestinationAttribute[];

Expand Down Expand Up @@ -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') {
Expand All @@ -161,16 +169,25 @@ 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 {
this.optionSearchUpdate.pipe(
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(
Expand All @@ -182,22 +199,19 @@ 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;
});

} else {

let existingOptions: DestinationAttribute[];
switch (event.destinationOptionKey) {
case BCExportSettingDestinationOptionKey.ACCOUNT:
existingOptions = this.bankOptions;
break;
case BCExportSettingDestinationOptionKey.VENDOR:
existingOptions = this.vendorOptions;
break;
Expand All @@ -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 || ''));
Expand All @@ -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 = {
Expand All @@ -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];

Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 6dd0a7c

Please sign in to comment.