Implement organization maker-checker workflows

This commit is contained in:
2026-09-24 17:22:50 +05:30
parent 08a427467a
commit 7b9a6394c8
30 changed files with 787 additions and 90 deletions
@@ -41,6 +41,7 @@ import { AccountingService } from 'app/accounting/accounting.service';
import { UsersService } from 'app/users/users.service';
import { FixedDepositsService } from 'app/deposits/fixed-deposits/fixed-deposits.service';
import { RecurringDepositsService } from 'app/deposits/recurring-deposits/recurring-deposits.service';
import { OrganizationService } from 'app/organization/organization.service';
/**
* One row of the rendered Command payload. The dialog turns the parsed command JSON into a tree of
@@ -148,6 +149,7 @@ export class ViewCheckerInboxComponent {
private usersService = inject(UsersService);
private fixedDepositsService = inject(FixedDepositsService);
private recurringDepositsService = inject(RecurringDepositsService);
private organizationService = inject(OrganizationService);
/** Bundle handed to the shared entity lookup, so that table stays free of Angular injection. */
private get entityFetchServices(): EntityFetchServices {
@@ -159,7 +161,8 @@ export class ViewCheckerInboxComponent {
accounting: this.accountingService,
users: this.usersService,
fixedDeposits: this.fixedDepositsService,
recurringDeposits: this.recurringDepositsService
recurringDeposits: this.recurringDepositsService,
organization: this.organizationService
};
}
/** Present only when opened as a popup from the Checker Inbox list; absent when reached by direct
@@ -375,6 +378,9 @@ export class ViewCheckerInboxComponent {
this.loadDeleteSummary(detail);
} else if (action === 'CREATE') {
this.createSections = this.buildCreateSections(this.jsondata);
if ((detail?.entityName ?? '').toUpperCase() === 'GLACCOUNT') {
this.resolveGlAccountCreateLabels(detail, this.jsondata);
}
}
}
@@ -461,6 +467,91 @@ export class ViewCheckerInboxComponent {
}));
}
/**
* GL Account CREATE: `type`, `usage`, `parentId` and `tagId` arrive as raw numeric ids - meaningless
* to a checker without the chart-of-accounts template, which is the same lookup data the create-GL
* form itself already uses (`create-gl-account.component.ts`). Fetched once, purely for display: the
* stored command payload (`jsondata`) and the already-rendered raw sections are left as they are
* unless the lookup succeeds, so a slow or failed template call never blocks or breaks this screen.
*/
private resolveGlAccountCreateLabels(detail: any, payload: Record<string, any>): void {
this.accountingService.getChartOfAccountsTemplate().subscribe({
next: (template: any) => {
// A slow response for a request the checker has already navigated away from must not overwrite
// whatever is now on screen.
if (!this.isCurrent(detail)) {
return;
}
const resolved = { ...payload };
const typeId = payload.type;
const typeOption = (template?.accountTypeOptions ?? []).find((option: any) => option.id === typeId);
if (typeOption) {
resolved.type = this.translateService.instant(`labels.inputs.accounting.${typeOption.value}`);
}
const usageOption = (template?.usageOptions ?? []).find((option: any) => option.id === payload.usage);
if (usageOption) {
resolved.usage = usageOption.value;
}
const parentAccount = this.glHeaderAccountOptions(template, typeId).find(
(account: any) => account.id === payload.parentId
);
if (parentAccount) {
resolved.parentId = parentAccount.glCode
? `${parentAccount.name} (${parentAccount.glCode})`
: parentAccount.name;
}
const tagOption = this.glTagOptions(template, typeId).find((tag: any) => tag.id === payload.tagId);
if (tagOption) {
resolved.tagId = tagOption.name;
}
this.createSections = this.buildCreateSections(resolved);
},
// Lookup failed - the raw ids already on screen from buildCreateSections() above stay as they are.
error: () => undefined
});
}
/** Header/parent account options are partitioned by GL account type, same as the create-GL form. */
private glHeaderAccountOptions(template: any, typeId: number): any[] {
switch (typeId) {
case 1:
return template?.assetHeaderAccountOptions ?? [];
case 2:
return template?.liabilityHeaderAccountOptions ?? [];
case 3:
return template?.equityHeaderAccountOptions ?? [];
case 4:
return template?.incomeHeaderAccountOptions ?? [];
case 5:
return template?.expenseHeaderAccountOptions ?? [];
default:
return [];
}
}
/** Allowed tag options are partitioned by GL account type, same as the create-GL form. */
private glTagOptions(template: any, typeId: number): any[] {
switch (typeId) {
case 1:
return template?.allowedAssetsTagOptions ?? [];
case 2:
return template?.allowedLiabilitiesTagOptions ?? [];
case 3:
return template?.allowedEquityTagOptions ?? [];
case 4:
return template?.allowedIncomeTagOptions ?? [];
case 5:
return template?.allowedExpensesTagOptions ?? [];
default:
return [];
}
}
/**
* A role permission update posts the role's *entire* permission map - over 1,100 entries, of which
* a handful are actually being changed. Rendering that as-is buries the change completely, so this