Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: business central beta bugfixes #1122

Merged
merged 5 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading