feat: update TDS config, RBI reserve returns, current products, and dormancy reports
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
<!--
|
||||
Copyright since 2025 Mifos Initiative
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
-->
|
||||
|
||||
<div class="rrc-container">
|
||||
<div class="rrc-header">
|
||||
<button mat-stroked-button [routerLink]="['/organization']" class="rrc-back">
|
||||
<i class="fas fa-arrow-left"></i> Organization
|
||||
</button>
|
||||
<h2 class="rrc-header__title">TDS Configuration</h2>
|
||||
</div>
|
||||
<p class="rrc-sub">
|
||||
Thresholds, rates and statutory references for TDS on deposit interest, per financial year, and the GL account
|
||||
deducted tax is credited to. The TDS reports, the Form 121 register and each customer's Form 121 tab compute from
|
||||
these figures only — a year not set up here is a year they refuse to compute.
|
||||
</p>
|
||||
|
||||
@if (errorMsg) {
|
||||
<div class="rrc-alert rrc-alert--error">{{ errorMsg }}</div>
|
||||
}
|
||||
@if (successMsg) {
|
||||
<div class="rrc-alert rrc-alert--success">{{ successMsg }}</div>
|
||||
}
|
||||
|
||||
@if (loading) {
|
||||
<div class="rrc-loading">Loading…</div>
|
||||
} @else {
|
||||
<!-- ═══ GL ═══ -->
|
||||
<div class="rrc-card">
|
||||
<h3 class="rrc-card__title">GL account</h3>
|
||||
<p class="rrc-card__hint">
|
||||
Only postable liability accounts are listed. Nothing is preselected: the right account differs per chart of
|
||||
accounts.
|
||||
</p>
|
||||
|
||||
@for (role of glRoles; track role.configKey) {
|
||||
<div class="rrc-role" [class.rrc-role--unmapped]="!role.glAccountId">
|
||||
<div class="rrc-role__head">
|
||||
<div>
|
||||
<span class="rrc-role__name">{{ role.label }}</span>
|
||||
<span class="rrc-key">{{ role.configKey }}</span>
|
||||
</div>
|
||||
@if (role.glAccountId) {
|
||||
<span class="rrc-badge rrc-badge--mapped">{{ role.glCode }} · {{ role.glAccountName }}</span>
|
||||
} @else {
|
||||
<span class="rrc-badge rrc-badge--unmapped">Not mapped</span>
|
||||
}
|
||||
</div>
|
||||
<p class="rrc-role__desc">{{ role.description }}</p>
|
||||
<div class="tdc-gl">
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="tdc-gl__field">
|
||||
<mat-label>GL account</mat-label>
|
||||
<mat-select [(ngModel)]="glSelection[role.configKey]" [disabled]="savingGl">
|
||||
<mat-option [value]="null">— Not mapped —</mat-option>
|
||||
@for (o of glAccountOptions; track o.id) {
|
||||
<mat-option [value]="o.id">{{ o.glCode }} · {{ o.name }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
[disabled]="savingGl || !isGlDirty(role)"
|
||||
(click)="saveGl(role)"
|
||||
>
|
||||
{{ savingGl ? 'Saving…' : 'Save' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- ═══ Financial years ═══ -->
|
||||
<div class="rrc-card">
|
||||
<h3 class="rrc-card__title">Financial years</h3>
|
||||
<p class="rrc-card__hint">
|
||||
One entry per year, because the Finance Act fixes TDS per year and a return for an earlier year must keep quoting
|
||||
that year's figures. Add the next year before 01 April, or TDS screens stop computing on that date.
|
||||
</p>
|
||||
|
||||
<div class="rrc-tabs" role="tablist">
|
||||
@for (y of years; track y.fy) {
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
class="rrc-tab"
|
||||
[class.rrc-tab--active]="!isNew && draft?.fy === y.fy"
|
||||
(click)="select(y)"
|
||||
>
|
||||
FY {{ y.fy }}
|
||||
@if (y.seedDefault) {
|
||||
<span class="rrc-tab__badge">confirm</span>
|
||||
}
|
||||
</button>
|
||||
}
|
||||
@if (isNew) {
|
||||
<button type="button" role="tab" class="rrc-tab rrc-tab--active">New year</button>
|
||||
} @else {
|
||||
<button type="button" class="rrc-tab" (click)="startNewYear()">
|
||||
<i class="fas fa-plus"></i> Add financial year
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (draft) {
|
||||
@if (draft.seedDefault && !isNew) {
|
||||
<div class="rrc-alert rrc-alert--warn">
|
||||
These figures were carried over from the values previously built into the application. Check them against
|
||||
the Finance Act for FY {{ draft.fy }} and save to confirm.
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (isNew) {
|
||||
<div class="tdc-grid">
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-label>Financial year</mat-label>
|
||||
<input matInput [(ngModel)]="draft.fy" placeholder="2027-28" />
|
||||
@if (!fyValid) {
|
||||
<mat-hint>Format: 2027-28</mat-hint>
|
||||
} @else if (fyTaken) {
|
||||
<mat-hint>FY {{ draft.fy }} is already configured</mat-hint>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
}
|
||||
|
||||
<h4 class="tdc-section">Thresholds & rates</h4>
|
||||
<div class="tdc-grid">
|
||||
@for (f of rateFields; track f.key) {
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-label>{{ f.label }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
type="number"
|
||||
[min]="0"
|
||||
[max]="f.kind === 'percent' ? 100 : null"
|
||||
[step]="f.kind === 'percent' ? 0.0001 : 1"
|
||||
[(ngModel)]="$any(draft)[f.key]"
|
||||
/>
|
||||
@if (f.hint) {
|
||||
<mat-hint>{{ f.hint }}</mat-hint>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
</div>
|
||||
@if (noPanBelowRate) {
|
||||
<div class="rrc-alert rrc-alert--warn">The rate without PAN cannot be lower than the rate with PAN.</div>
|
||||
}
|
||||
|
||||
<h4 class="tdc-section">Declaration (Form 121 / 15G / 15H)</h4>
|
||||
<div class="tdc-grid">
|
||||
@for (f of declarationFields; track f.key) {
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-label>{{ f.label }}</mat-label>
|
||||
@if (f.kind === 'select') {
|
||||
<mat-select [(ngModel)]="$any(draft)[f.key]">
|
||||
@for (o of f.options; track o.value) {
|
||||
<mat-option [value]="o.value">{{ o.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
} @else {
|
||||
<input matInput type="number" [min]="0" [(ngModel)]="$any(draft)[f.key]" />
|
||||
}
|
||||
@if (f.hint) {
|
||||
<mat-hint>{{ f.hint }}</mat-hint>
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
</div>
|
||||
|
||||
<h4 class="tdc-section">Statutory references</h4>
|
||||
<p class="rrc-card__hint">Printed on the reports, certificates and returns for this year.</p>
|
||||
<div class="tdc-grid">
|
||||
@for (f of statuteFields; track f.key) {
|
||||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||||
<mat-label>{{ f.label }}</mat-label>
|
||||
@if (f.kind === 'select') {
|
||||
<mat-select [(ngModel)]="$any(draft)[f.key]">
|
||||
@for (o of f.options; track o.value) {
|
||||
<mat-option [value]="o.value">{{ o.label }}</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
} @else {
|
||||
<input matInput [(ngModel)]="$any(draft)[f.key]" />
|
||||
}
|
||||
</mat-form-field>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="rrc-role__controls">
|
||||
<button mat-raised-button color="primary" [disabled]="!canSave" (click)="save()">
|
||||
{{ saving ? 'Saving…' : isNew ? 'Add FY ' + draft.fy : 'Save FY ' + draft.fy }}
|
||||
</button>
|
||||
@if (isNew) {
|
||||
<button mat-button (click)="cancelNew()">Cancel</button>
|
||||
} @else if (years.length > 1) {
|
||||
<button mat-button class="rrc-remove" (click)="deleteYear()">
|
||||
<i class="fas fa-trash"></i> Remove FY {{ draft.fy }}
|
||||
</button>
|
||||
}
|
||||
@if (draft.updatedOn && !isNew) {
|
||||
<span class="rrc-card__hint">Last saved {{ draft.updatedOn | slice: 0 : 16 }}</span>
|
||||
}
|
||||
</div>
|
||||
} @else {
|
||||
<div class="rrc-alert rrc-alert--warn">
|
||||
No financial year is configured. Every TDS screen is unable to compute until one is added.
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
Reference in New Issue
Block a user