From 15aabb7954ea09e58de05bb6cf382ea4cd8f0917 Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Fri, 30 Oct 2026 12:43:08 +0530 Subject: [PATCH] feat(dds): premature payout calculation, back to agent, income and TDS GLs on products - Premature closure dialog: interest still to credit through yesterday, total interest earned, a day-by-day interest table, and the agent penalty worked out by the server on this account's collection (with its cap). Dates follow the bank's business date rather than the computer's clock, and 'yyyy-MM-dd' strings are read as local days. - DDS account page: Back returns to the agent the account was opened from. - DDS product Accounting tab: Premature Closure Income (income) and TDS Payable (194H, liability); the agent penalty field is relabelled as a percentage of the account's collection. - Agent top-up transactions use the stored PREMATURE_AGENT_TOPUP type. Co-Authored-By: Claude Opus 5.5 --- .../dds-account-view.component.ts | 3 +- .../premature-close-dialog.component.html | 131 +++++++++++--- .../premature-close-dialog.component.scss | 113 +++++++++++++ .../premature-close-dialog.component.ts | 160 ++++++++++++++---- src/app/organization/organization.service.ts | 8 + .../create-dds-account-type.component.html | 7 +- .../create-dds-account-type.component.scss | 5 + .../create-dds-account-type.component.ts | 55 +++++- 8 files changed, 422 insertions(+), 60 deletions(-) diff --git a/src/app/deposits/dds-accounts/dds-account-view/dds-account-view.component.ts b/src/app/deposits/dds-accounts/dds-account-view/dds-account-view.component.ts index 8f9e097ba..e27d63091 100644 --- a/src/app/deposits/dds-accounts/dds-account-view/dds-account-view.component.ts +++ b/src/app/deposits/dds-accounts/dds-account-view/dds-account-view.component.ts @@ -666,7 +666,8 @@ export class DdsAccountViewComponent implements OnInit { id: account.id, agentId: account.agentId, interestCalc: account.interestCalc, - collectedToDate: account.collectedToDate + collectedToDate: account.collectedToDate, + openingBalance: account.openingBalance }, width: '960px', maxWidth: '96vw', diff --git a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.html b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.html index cff4b29bb..c675c3c3f 100644 --- a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.html +++ b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.html @@ -62,16 +62,6 @@ } - @if (pendingInterest > 0) { -
- - ₹{{ pendingInterest | number: '1.2-2' }} interest is calculated but not posted yet. Run - Interest Posting first — the closure is refused until it is in the balance. -
- } -
@@ -131,7 +121,8 @@ Either way, {{ data.agentCode }} is charged {{ scheme.prematureAgentCommissionPenalty | number: '1.0-2' }}% - of the commission owed to them — the round was not kept going.

} @@ -258,7 +249,12 @@ ₹{{ deposits | number: '1.2-2' }}
- Interest credited so far + Interest credited so far + @if (creditedThrough) { + till {{ creditedThrough | dateFormat }} + } + @if (interestCredited === null) { … @@ -267,18 +263,107 @@ }
+ + @if (interestDue > 0) { +
+ Interest still to credit + @if (interestThrough) { + till {{ interestThrough | dateFormat }} — added at closing + } + + + ₹{{ interestDue | number: '1.2-2' }} +
+ } @else if (interestThrough) { +
+ Interest is up to date + credited till {{ interestThrough | dateFormat }} +
+ } + +
+ Total interest earned + @if (interestThrough) { + {{ data.openingDate | dateFormat }} to {{ interestThrough | dateFormat }} + } + + ₹{{ totalInterest | number: '1.2-2' }} +
- Current balance + Balance on closing day + {{ businessDate | dateFormat }} — this day earns no interest, the money leaves today ₹{{ balance | number: '1.2-2' }}
+ + @if (interestDays.length > 0) { + + @if (showDays) { +
+ + + + + + + + + + + @for (day of interestDays; track day.date.getTime()) { + + + + + + + } + + + + + + + @if (interestDue > 0) { + + + + + } + + + + + +
DateBalanceInterest
{{ day.date | dateFormat }}₹{{ day.balance | number: '1.2-2' }}₹{{ day.interest | number: '1.4-4' }} + {{ + day.credited ? 'Credited' : 'To credit' + }} +
Credited so far₹{{ interestCredited ?? 0 | number: '1.2-2' }}
Added at closing+ ₹{{ interestDue | number: '1.2-2' }}
Total interest₹{{ totalInterest | number: '1.2-2' }}
+

+ Balance × {{ data.interestRate | number: '1.0-2' }}% ÷ 365 for each day. Each run's total is rounded to + paise, so the totals can differ from the day figures by a paisa. {{ businessDate | dateFormat }}, the + closing day, earns nothing. +

+
+ } + } + @if (borneBy === 'CUSTOMER') {
Interest taken back ₹{{ interestCredited ?? 0 | number: '1.2-2' }} × - {{ data.interestRate - reducedRate | number: '1.0-2' }}% ÷ + >₹{{ totalInterest | number: '1.2-2' }} × {{ data.interestRate - reducedRate | number: '1.0-2' }}% ÷ {{ data.interestRate | number: '1.0-2' }}% @@ -319,13 +404,19 @@
Commission penalty - @if (scheme?.prematureAgentCommissionPenalty > 0) { + @if (agentPenalty && (agentPenalty.penaltyRate ?? 0) > 0) { {{ scheme.prematureAgentCommissionPenalty | number: '1.0-2' }}% of ₹{{ - agentCommission ?? 0 | number: '1.2-2' - }} - owed₹{{ agentPenalty.collection ?? 0 | number: '1.2-2' }} collected on this account × + {{ agentPenalty.penaltyRate | number: '1.0-2' }}% + @if (agentPenalty.commissionEarned !== null && agentPenalty.commissionEarned !== undefined) { + {{ penaltyCapped ? 'Capped at' : 'Never more than' }} ₹{{ + agentPenalty.commissionEarned | number: '1.2-2' + }} + this account earned them ({{ agentPenalty.commissionRate | number: '1.0-2' }}% commission) + } } ₹{{ commissionPenalty | number: '1.2-2' }} diff --git a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.scss b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.scss index 1044fbddf..ee0803ede 100644 --- a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.scss +++ b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.scss @@ -449,6 +449,23 @@ font-variant-numeric: tabular-nums; } + &--ok { + color: #15803d; + } + + &--interest { + margin: 4px 0; + padding: 8px 10px; + border-radius: 8px; + background: #f0fdf4; + color: #15803d; + font-weight: 600; + + b { + font-size: 0.95rem; + } + } + &--sum { margin-top: 2px; border-top: 1px dashed #cbd5e1; @@ -526,6 +543,102 @@ } } +/* The interest day by day, opened from the calculation panel */ +.pcd-days { + max-height: 260px; + margin: 2px 0 6px; + overflow: auto; + border: 1px solid #e2e8f0; + border-radius: 8px; + background: #fff; + + &__toggle { + display: inline-flex; + align-items: center; + gap: 6px; + margin: 4px 0 6px; + padding: 0; + border: none; + background: none; + color: #4338ca; + font: inherit; + font-size: 0.78rem; + font-weight: 600; + cursor: pointer; + + &:hover { + text-decoration: underline; + } + } + + table { + width: 100%; + border-collapse: collapse; + font-size: 0.76rem; + } + + th, + td { + padding: 5px 8px; + border-bottom: 1px solid #f1f5f9; + text-align: left; + white-space: nowrap; + } + + th { + position: sticky; + top: 0; + background: #f8fafc; + font-size: 0.68rem; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + color: #64748b; + } + + .num { + text-align: right; + font-variant-numeric: tabular-nums; + } + + tfoot td { + font-weight: 600; + color: #334155; + } + + &__due td { + color: #15803d; + } + + &__sum td { + border-top: 1px solid #cbd5e1; + color: #0f172a; + } + + &__tag { + padding: 1px 7px; + border-radius: 999px; + background: #f1f5f9; + font-size: 0.68rem; + font-weight: 600; + color: #475569; + + &--due { + background: #dcfce7; + color: #15803d; + } + } + + &__note { + margin: 0; + padding: 6px 8px 8px; + font-size: 0.7rem; + line-height: 1.5; + color: #94a3b8; + white-space: normal; + } +} + @media (width <= 760px) { .pcd-grid { grid-template-columns: minmax(0, 1fr); diff --git a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.ts b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.ts index 69d895c57..31d2be321 100644 --- a/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.ts +++ b/src/app/deposits/party-master/premature-close-dialog/premature-close-dialog.component.ts @@ -23,6 +23,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome'; /** Custom Services */ import { OrganizationService } from 'app/organization/organization.service'; import { ProductsService } from 'app/products/products.service'; +import { SettingsService } from 'app/settings/settings.service'; /** Custom Pipes */ import { DateFormatPipe } from 'app/pipes/date-format.pipe'; @@ -66,6 +67,7 @@ import { DateFormatPipe } from 'app/pipes/date-format.pipe'; export class PrematureCloseDialogComponent implements OnInit { private organizationService = inject(OrganizationService); private productsService = inject(ProductsService); + private settingsService = inject(SettingsService); private dialogRef = inject(MatDialogRef); data = inject(MAT_DIALOG_DATA); @@ -183,6 +185,7 @@ export class PrematureCloseDialogComponent implements OnInit { this.organizationService.getPartyTransactionsOfParty(this.data.id).subscribe({ next: (txns: any) => { const list: any[] = Array.isArray(txns) ? txns : txns?.pageItems || []; + this.transactions = list; this.interestCredited = list .filter((t) => PrematureCloseDialogComponent.INTEREST_TYPES.includes(t.transactionType)) .reduce((sum, t) => sum + (t.direction === 'DEBIT' ? -1 : 1) * Number(t.amount || 0), 0); @@ -190,11 +193,18 @@ export class PrematureCloseDialogComponent implements OnInit { error: () => (this.interestCredited = null) }); } - // The commission the agent is owed now, which the scheme's penalty is a share of. - if (this.data.agentId) { - this.organizationService.getAgent(this.data.agentId).subscribe({ - next: (agent: any) => (this.agentCommission = Number(agent?.commission || 0)), - error: () => (this.agentCommission = null) + // Interest earned through yesterday but not yet credited. The closure credits it first, so the + // figures below start from it rather than from a balance that is a few days behind. + if (this.data.id) { + this.organizationService.getPartyInterestDue(this.data.id).subscribe({ + next: (due: any) => { + this.interestDue = Number(due?.interestDue || 0); + this.interestThrough = due?.through ?? null; + this.creditedThrough = due?.creditedThrough ?? null; + // The agent's penalty as the server works it out: on this account's collection alone. + this.agentPenalty = due?.agentPenalty ?? null; + }, + error: () => (this.interestDue = 0) }); } } @@ -207,33 +217,113 @@ export class PrematureCloseDialogComponent implements OnInit { /** Interest credited to the account so far; null until read (or if it could not be). */ interestCredited: number | null = null; - /** What the agent is owed in commission today; null until read. */ - agentCommission: number | null = null; + /** Interest earned through the day before closing but not yet credited - credited by the closure itself. */ + interestDue = 0; + /** The last day that earns (the day before the business date), and the day interest is credited through now. */ + interestThrough: string | null = null; + creditedThrough: string | null = null; + + /** Everything posted to the account, for the day-by-day interest table. */ + private transactions: any[] = []; + + /** Whether the day-by-day interest table is open. */ + showDays = false; + + private static dayKey(date: Date): string { + return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; + } + + /** + * Each earning day from opening to the day before closing: the balance at the end of that day - every + * movement up to it, interest postings included, as the server's daily product counts it - and the + * interest it earns (balance × rate ÷ 365). Days up to the last credited day are marked credited; the + * rest are what the closure credits first. The server rounds each run's total, not each day, so the + * per-day figures are shown to four places and the totals come from the server. + */ + get interestDays(): { date: Date; balance: number; interest: number; credited: boolean }[] { + const opened = PrematureCloseDialogComponent.toDate(this.data.openingDate); + const rate = Number(this.data.interestRate || 0); + if (!opened || rate <= 0) { + return []; + } + const last = new Date(this.businessDate); + last.setDate(last.getDate() - 1); + const creditedTo = this.creditedThrough ? PrematureCloseDialogComponent.toDate(this.creditedThrough) : null; + const byDay = new Map(); + for (const t of this.transactions) { + const on = PrematureCloseDialogComponent.toDate(t.transactionDate); + if (on) { + const key = PrematureCloseDialogComponent.dayKey(on); + byDay.set(key, (byDay.get(key) || 0) + (t.direction === 'DEBIT' ? -1 : 1) * Number(t.amount || 0)); + } + } + const rows: { date: Date; balance: number; interest: number; credited: boolean }[] = []; + let balance = Number(this.data.openingBalance || 0); + for ( + let day = new Date(opened); + day.getTime() <= last.getTime() && rows.length < 400; + day.setDate(day.getDate() + 1) + ) { + balance += byDay.get(PrematureCloseDialogComponent.dayKey(day)) || 0; + rows.push({ + date: new Date(day), + balance, + interest: (balance * rate) / 36500, + credited: !!creditedTo && day.getTime() <= creditedTo.getTime() + }); + } + return rows; + } + + /** + * The agent's penalty on this account, from the server: its collection, the scheme's penalty rate, + * the agent's commission rate and what the account earned them (the cap), and the penalty itself. + */ + agentPenalty: { + collection?: number; + penaltyRate?: number; + commissionRate?: number | null; + commissionEarned?: number | null; + penalty?: number; + } | null = null; private static round2(value: number): number { return Math.round((value + Number.EPSILON) * 100) / 100; } - get balance(): number { + /** The balance today, before the interest still owed is credited. */ + get currentBalance(): number { return Number(this.data.currentBalance || 0); } - /** Interest calculated but not posted - the server refuses to close until it is posted. */ - get pendingInterest(): number { - return Number(this.data.interestCalc || 0); + /** The balance on the closing day, once the interest owed through yesterday is credited. */ + get balance(): number { + return PrematureCloseDialogComponent.round2(this.currentBalance + this.interestDue); + } + + /** All interest the account will have earned by closing - credited so far plus what is still owed. */ + get totalInterest(): number { + return PrematureCloseDialogComponent.round2((this.interestCredited ?? 0) + this.interestDue); + } + + /** The bank's working day, which the server closes on - not the computer's clock. */ + get businessDate(): Date { + const date = new Date(this.settingsService.businessDate || new Date()); + date.setHours(0, 0, 0, 0); + return date; } /** What the customer paid in: the balance less the interest credited on it. */ get deposits(): number { const collected = Number(this.data.collectedToDate || 0); - return collected > 0 ? collected : Math.max(0, this.balance - (this.interestCredited ?? 0)); + return collected > 0 ? collected : Math.max(0, this.currentBalance - (this.interestCredited ?? 0)); } /** Customer bears it: credited interest scaled by the share of the rate given up. */ get customerRecovery(): number { const rate = Number(this.data.interestRate || 0); const reduction = Number(this.scheme?.prematureInterestReduction || 0); - const credited = this.interestCredited ?? 0; + const credited = this.totalInterest; if (rate <= 0 || reduction <= 0 || credited <= 0) { return 0; } @@ -244,9 +334,9 @@ export class PrematureCloseDialogComponent implements OnInit { return PrematureCloseDialogComponent.round2(this.balance - this.customerRecovery); } - /** Days from today to the month's end, today counted - the days the agent funds. */ + /** Days from the closing day to the month's end, the closing day counted - the days the agent funds. */ get agentTopUpDays(): number { - const today = new Date(); + const today = this.businessDate; const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0).getDate(); return lastDay - today.getDate() + 1; } @@ -264,13 +354,16 @@ export class PrematureCloseDialogComponent implements OnInit { return PrematureCloseDialogComponent.round2(this.balance + this.agentTopUp); } - /** The share of the agent's commission taken whichever way it is settled. */ + /** The agent's penalty on this account, taken whichever way it is settled. */ get commissionPenalty(): number { - const rate = Number(this.scheme?.prematureAgentCommissionPenalty || 0); - if (rate <= 0 || !this.agentCommission) { - return 0; - } - return PrematureCloseDialogComponent.round2((this.agentCommission * rate) / 100); + return Number(this.agentPenalty?.penalty || 0); + } + + /** Whether the penalty was cut down to what the account earned the agent. */ + get penaltyCapped(): boolean { + const earned = this.agentPenalty?.commissionEarned; + const uncapped = (Number(this.agentPenalty?.collection || 0) * Number(this.agentPenalty?.penaltyRate || 0)) / 100; + return earned !== null && earned !== undefined && uncapped > Number(earned); } /** What the customer receives on the option picked, or null before one is picked. */ @@ -294,13 +387,21 @@ export class PrematureCloseDialogComponent implements OnInit { /** The API sends dates as [year, month, day]; month is 1-based there and 0-based in Date. */ private static toDate(value: any): Date | null { - const date = - Array.isArray(value) && value.length >= 3 - ? new Date(value[0], value[1] - 1, value[2]) - : value - ? new Date(value) - : null; - return date && !isNaN(date.getTime()) ? date : null; + if (Array.isArray(value) && value.length >= 3) { + return new Date(value[0], value[1] - 1, value[2]); + } + // A bare 'yyyy-MM-dd' is a calendar day: read in local time, not as UTC midnight - which in India is + // 05:30 the same day and would push every day-by-day comparison off by one. + const day = typeof value === 'string' ? /^(\d{4})-(\d{2})-(\d{2})$/.exec(value) : null; + if (day) { + return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3])); + } + const date = value ? new Date(value) : null; + if (!date || isNaN(date.getTime())) { + return null; + } + date.setHours(0, 0, 0, 0); + return date; } private static readonly DAY_MS = 24 * 60 * 60 * 1000; @@ -320,8 +421,7 @@ export class PrematureCloseDialogComponent implements OnInit { if (!opened) { return 0; } - const today = new Date(); - today.setHours(0, 0, 0, 0); + const today = this.businessDate; const run = Math.round((today.getTime() - opened.getTime()) / PrematureCloseDialogComponent.DAY_MS) + 1; return Math.min(this.termDays, Math.max(0, run)); } diff --git a/src/app/organization/organization.service.ts b/src/app/organization/organization.service.ts index 2e861671f..92f281ea7 100644 --- a/src/app/organization/organization.service.ts +++ b/src/app/organization/organization.service.ts @@ -490,6 +490,14 @@ export class OrganizationService { * @param {string | number} partyId DDS account (party) id. * @returns {Observable} Everything posted to that DDS account, most recent first. */ + /** + * Interest a DDS account has earned through the day before the business date but not yet been + * credited - what an early closure today credits before it settles. + */ + getPartyInterestDue(partyId: string | number): Observable { + return this.http.get(`/dds/parties/${partyId}/interestdue`); + } + getPartyTransactionsOfParty(partyId: string | number): Observable { return this.http.get('/dds/partytransactions', { params: new HttpParams().set('partyId', String(partyId)) diff --git a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.html b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.html index bb58777ab..a4522dc3b 100644 --- a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.html +++ b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.html @@ -165,7 +165,7 @@ - Agent: commission reduced by (%) + Agent penalty (% of this account's collection) - Charged whoever bears the interest — the round was not kept going. + Taken off the agent's next commission, whoever bears the interest - never more than the commission the + account earned them.
diff --git a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.scss b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.scss index fe521eece..651fe48b2 100644 --- a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.scss +++ b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.scss @@ -285,6 +285,11 @@ $text-soft: #94a3b8; background: #fef3c7; color: #92400e; } + + &--green { + background: #dcfce7; + color: #166534; + } } // ── Footer ─────────────────────────────────────────────────────────────────────────────────────────── diff --git a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.ts b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.ts index 17cb0a873..fc3be0c26 100644 --- a/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.ts +++ b/src/app/products/dds-account-types/create-dds-account-type/create-dds-account-type.component.ts @@ -24,8 +24,9 @@ import { SettingsService } from 'app/settings/settings.service'; import { AccountingService } from 'app/accounting/accounting.service'; import { announceHeldForApproval, heldForApproval } from 'app/deposits/dds-approvals/dds-approval-notice'; -/** acc_gl_account classification: 2 liability, 5 expense. */ +/** acc_gl_account classification: 2 liability, 4 income, 5 expense. */ const GL_LIABILITY = 2; +const GL_INCOME = 4; const GL_EXPENSE = 5; /** One ledger account the product names, as a row on the Accounting tab. */ @@ -34,7 +35,7 @@ interface AccountingRow { label: string; inputLabel: string; hint: string; - pill: 'blue' | 'amber'; + pill: 'blue' | 'amber' | 'green'; pillLabel: string; required: boolean; options: GLAccount[]; @@ -93,7 +94,9 @@ export class CreateDdsAccountTypeComponent implements OnInit { readonly accountingControls = [ 'depositLiabilityGlId', 'interestExpenseGlId', - 'commissionExpenseGlId' + 'commissionExpenseGlId', + 'prematureIncomeGlId', + 'tdsPayableGlId' ]; /** The Accounting tab's rows, grouped by kind as the savings product's are. */ @@ -196,6 +199,16 @@ export class CreateDdsAccountTypeComponent implements OnInit { commissionExpenseGlId: [ null, Validators.required + ], + /** What an early closure earns the bank: the customer's interest given back and the agent's penalty. */ + prematureIncomeGlId: [ + null, + Validators.required + ], + /** Where TDS withheld from the agents' commission (Section 194H) is owed until it is paid over. */ + tdsPayableGlId: [ + null, + Validators.required ] }); @@ -226,7 +239,9 @@ export class CreateDdsAccountTypeComponent implements OnInit { prematureAgentCommissionPenalty: accountType.prematureAgentCommissionPenalty ?? 1, depositLiabilityGlId: accountType.depositLiabilityGlId ?? null, interestExpenseGlId: accountType.interestExpenseGlId ?? null, - commissionExpenseGlId: accountType.commissionExpenseGlId ?? null + commissionExpenseGlId: accountType.commissionExpenseGlId ?? null, + prematureIncomeGlId: accountType.prematureIncomeGlId ?? null, + tdsPayableGlId: accountType.tdsPayableGlId ?? null }); }); } @@ -258,16 +273,16 @@ export class CreateDdsAccountTypeComponent implements OnInit { (a: any) => a.usage?.id === 1 && !a.disabled ); const ofType = (...types: number[]) => rows.filter((a: any) => types.includes(a.type?.id)); - this.buildAccountingSections(ofType(GL_LIABILITY), ofType(GL_EXPENSE)); + this.buildAccountingSections(ofType(GL_LIABILITY), ofType(GL_EXPENSE), ofType(GL_INCOME)); }, error: () => { this.glLoadFailed = true; - this.buildAccountingSections([], []); + this.buildAccountingSections([], [], []); } }); } - private buildAccountingSections(liabilities: GLAccount[], expenses: GLAccount[]): void { + private buildAccountingSections(liabilities: GLAccount[], expenses: GLAccount[], incomes: GLAccount[]): void { this.accountingSections = [ { key: 'liabilities', @@ -282,6 +297,16 @@ export class CreateDdsAccountTypeComponent implements OnInit { pillLabel: 'Liability', required: true, options: liabilities + }, + { + controlName: 'tdsPayableGlId', + label: 'TDS Payable (194H)', + inputLabel: 'TDS payable account', + hint: "TDS withheld from the agents' commission on this product - credited when the commission is paid, until it is paid over to the tax department.", + pill: 'blue', + pillLabel: 'Liability', + required: true, + options: liabilities } ] }, @@ -310,6 +335,22 @@ export class CreateDdsAccountTypeComponent implements OnInit { options: expenses } ] + }, + { + key: 'income', + title: 'Income', + rows: [ + { + controlName: 'prematureIncomeGlId', + label: 'Premature Closure Income', + inputLabel: 'Premature closure income account', + hint: 'What closing early earns the bank: the interest a customer gives back (Premature Closure tab), on the day of closing. The agent penalty is not booked here - it comes off their commission, which reverses that much commission expense.', + pill: 'green', + pillLabel: 'Income', + required: true, + options: incomes + } + ] } ]; }