DDS: agent collection entry screen, per-agent GL account, maturity auto close

The Daily Transaction Entry screen no longer composes a Party Tran. An agent records their own round
elsewhere; this screen reads back what they wrote down, shows what it adds up to, and settles the
day once a clerk has counted the cash against it. Nothing is typed here and nothing is edited - what
settles is what the entries say, to the rupee.

Agent Master now asks which ledger account the agent's collections pass through, one agent to an
account, and offers only the accounts that can carry them. The DDS scheme product is kept out of the
agent's own savings list for the same reason the server refuses it: debits are blocked on those
accounts, so commission paid into one would go in and never come out.

The DDS product carries a Maturity Auto Close setting, asked as Yes/No to match the Auto Interest
Post question directly above it, and Batch Processing offers the run that applies it.

Also: the report viewer stops printing two money columns ungrouped and stops totalling a column that
holds a word, and an agent's birth date cannot be picked later than eighteen years ago.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
tarunmalviya
2026-09-23 11:54:49 +05:30
co-authored by Claude Opus 5
parent 57a61b3057
commit e2eff9914f
114 changed files with 10259 additions and 15955 deletions
@@ -53,7 +53,18 @@
<ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Value' | translate }}</th>
<td mat-cell *matCellDef="let configuration">{{ configuration.value }}</td>
<td mat-cell *matCellDef="let configuration">
{{ configuration.value }}
<!--
A setting that points at a ledger account holds only its id, which means nothing to the
officer checking that money is posting where it should. Named the way the product screens
name one, and shown beside the value rather than instead of it - the id is what gets
typed when the setting is edited.
-->
@if (glAccountLabel(configuration); as glAccount) {
<span class="gc-gl-name">{{ glAccount }}</span>
}
</td>
</ng-container>
<ng-container matColumnDef="stringValue">
@@ -9,3 +9,14 @@
table {
width: 100%;
}
/*
* The ledger account a setting points at. Quieter than the value itself, because the id is what the
* setting actually holds and what gets typed when it is edited - the name is here to say what that
* id means, not to replace it.
*/
.gc-gl-name {
margin-left: 8px;
color: rgb(0 0 0 / 60%);
font-size: 0.82rem;
}
@@ -29,6 +29,7 @@ import { ActivatedRoute, Router, RouterLink } from '@angular/router';
/** Custom Services */
import { SystemService } from '../../system.service';
import { AccountingService } from 'app/accounting/accounting.service';
import { PopoverService } from '../../../configuration-wizard/popover/popover.service';
import { ConfigurationWizardService } from '../../../configuration-wizard/configuration-wizard.service';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
@@ -71,9 +72,22 @@ export class GlobalConfigurationsTabComponent implements OnInit, AfterViewInit {
private router = inject(Router);
private configurationWizardService = inject(ConfigurationWizardService);
private popoverService = inject(PopoverService);
private accountingService = inject(AccountingService);
/** Configuration data. */
configurationData: any;
/**
* The chart of accounts, so a setting that holds a ledger account's id can be shown by its name.
*
* Several settings store nothing but a number - "44" says which account the money moves through,
* and says it only to the database. An officer checking that the scheme is posting where it should
* would otherwise have to carry the number to the Chart of Accounts and look it up.
*
* Left empty if the list cannot be read - a user without permission on the chart of accounts still
* sees every setting and its value, just without the name beside it.
*/
private glAccountsById = new Map<number, any>();
/** Columns to be displayed in configurations table. */
displayedColumns: string[] = [
'name',
@@ -119,6 +133,36 @@ export class GlobalConfigurationsTabComponent implements OnInit, AfterViewInit {
*/
ngOnInit() {
this.setConfigurationData();
this.loadGlAccounts();
}
private loadGlAccounts(): void {
this.accountingService.getGlAccounts().subscribe({
next: (accounts: any) => {
for (const account of accounts || []) {
this.glAccountsById.set(Number(account.id), account);
}
},
// The settings are the point of this screen; a chart of accounts that will not load must not
// take them down with it. The values still show, only the names beside them are missing.
error: () => this.glAccountsById.clear()
});
}
/**
* The ledger account a setting points at, as "name (code)" - the same way the product screens show
* one. Empty for every setting that does not hold a ledger account id, which is most of them.
*
* Only settings whose name marks them as an account mapping are resolved. Reading every numeric
* setting as an account id would put a name against figures that are nothing of the sort - a
* retry count of 3 would come back as whatever account 3 happens to be.
*/
glAccountLabel(configuration: any): string {
if (!configuration?.name?.endsWith('-account')) {
return '';
}
const account = this.glAccountsById.get(Number(configuration.value));
return account ? `${account.name} (${account.glCode})` : '';
}
/**