feat(dds): DDS product creation in tabs with an Accounting tab

- DDS Product Creation split into Details / Interest & Maturity /
  Premature Closure / Accounting tabs, like the savings product
- Accounting tab picks Customer Deposits (liability), Interest Expense
  and Agent Commission Expense (expense) GLs; product view shows them
- Approval review shows the product's GLs, old -> new on edits
- Agent master no longer reads the removed dds-deposit-product setting

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 12:43:51 +05:30
co-authored by Claude Opus 5.5
parent 293b671966
commit 53bb97d6ed
9 changed files with 885 additions and 218 deletions
@@ -25,7 +25,6 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/** Custom Services */
import { OrganizationService } from 'app/organization/organization.service';
import { AccountingService } from 'app/accounting/accounting.service';
import { SystemService } from 'app/system/system.service';
import { ClientsService } from 'app/clients/clients.service';
import { SavingsService } from 'app/savings/savings.service';
import { SettingsService } from 'app/settings/settings.service';
@@ -90,7 +89,6 @@ export class CreateAgentComponent implements OnInit {
private clientsService = inject(ClientsService);
private savingsService = inject(SavingsService);
private accountingService = inject(AccountingService);
private systemService = inject(SystemService);
private settingsService = inject(SettingsService);
private dateUtils = inject(Dates);
private alertService = inject(AlertService);
@@ -286,17 +284,6 @@ export class CreateAgentComponent implements OnInit {
);
}
/**
* The savings product a DDS customer's own scheme account is opened under, read from the setting
* that names it rather than guessed from a product name a bank is free to change.
*
* Held so those accounts can be kept out of the agent's own list. They are savings accounts and
* pass every other test, but they belong to a customer's scheme: commission paid into one would be
* counted as that customer's deposits by every interest run afterwards. The server refuses it
* either way - this is so the choice is never offered rather than taken and then thrown back.
*/
private ddsProductId: number | null = null;
/**
* The accounts on offer once a type has been chosen. Type is asked first, as the legacy screen
* did, so the officer narrows to a kind of account and then picks one of that kind.
@@ -420,19 +407,6 @@ export class CreateAgentComponent implements OnInit {
error: () => (this.offices = [])
});
this.systemService.getConfigurationByName('dds-deposit-product').subscribe({
next: (config: any) => {
this.ddsProductId = config?.enabled && config?.value ? Number(config.value) : null;
// The client may already have been keyed while this was in flight, so the list is rebuilt
// rather than left showing an account this now knows to exclude.
const clientId = this.agentForm.get('clientId')?.value;
if (clientId) {
this.loadClientSavingsAccounts(String(clientId));
}
},
error: () => (this.ddsProductId = null)
});
this.accountingService.getChartOfAccounts().subscribe({
next: (accounts: any) => {
const rows = Array.isArray(accounts) ? accounts : accounts?.pageItems || [];
@@ -751,11 +725,8 @@ export class CreateAgentComponent implements OnInit {
// Savings only. Commission is credited whenever a run posts, and a fixed deposit is a
// single sum placed for a term while a recurring one takes only its own instalments -
// neither accepts the credit, so the posting would fail rather than the choice.
// A DDS scheme account is a savings account too and so passes the test above. It is
// dropped by the product the setting names - not by a product called "DDS", which is a
// name the bank may change - so the list offers only accounts the agent can be paid in.
// A DDS customer's scheme account would pass this too; the server refuses one on save.
account.depositType?.id === CreateAgentComponent.SAVINGS_DEPOSIT_TYPE &&
(this.ddsProductId === null || account.productId !== this.ddsProductId) &&
(account.status?.active || account.status?.submittedAndPendingApproval || account.status?.approved)
);
this.savingsAccountTypes = [