DDS: approvals tab, vouchers, payout & close, Sundry GL search, closure tab, fixes

This commit is contained in:
tarunmalviya
2026-10-01 13:08:52 +05:30
parent d47e0860f6
commit 885b39d970
48 changed files with 5878 additions and 374 deletions
@@ -26,7 +26,9 @@
<div class="pm-section__header">
<i class="fas fa-id-card"></i>
<h3>Customer &amp; Scheme</h3>
<span class="pm-section__sub">Who this account is for, which scheme it runs under, and which agent collects for it</span>
<span class="pm-section__sub"
>Who this account is for, which scheme it runs under, and which agent collects for it</span
>
</div>
<div class="pm-grid">
<div class="pm-f">
@@ -42,7 +44,11 @@
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<mat-autocomplete #clientAuto="matAutocomplete" panelWidth="min(30rem, 92vw)" [displayWith]="displayClient">
<mat-autocomplete
#clientAuto="matAutocomplete"
panelWidth="min(30rem, 92vw)"
[displayWith]="displayClient"
>
@for (client of clientOptions; track client.id) {
<mat-option [value]="client">
<div class="pm-opt">
@@ -81,7 +87,11 @@
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<mat-autocomplete #subTypeAuto="matAutocomplete" panelWidth="min(30rem, 92vw)" [displayWith]="displaySubType">
<mat-autocomplete
#subTypeAuto="matAutocomplete"
panelWidth="min(30rem, 92vw)"
[displayWith]="displaySubType"
>
@for (type of subTypeOptions; track type.id) {
<mat-option [value]="type.accountTypeCode">
<div class="pm-opt">
@@ -114,7 +124,11 @@
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<mat-autocomplete #agentAuto="matAutocomplete" panelWidth="min(30rem, 92vw)" [displayWith]="displayAgent">
<mat-autocomplete
#agentAuto="matAutocomplete"
panelWidth="min(30rem, 92vw)"
[displayWith]="displayAgent"
>
@for (agent of agentOptions; track agent.id) {
<mat-option [value]="agent">
<div class="pm-opt">
@@ -163,20 +177,37 @@
</mat-form-field>
</div>
<!--
<!--
The customer's real deposit account. Three states, and the difference matters: an
account is open, this party predates DDS opening them, or the party is new and the
account is about to be opened. It used to read "Linked (id 36)", which is a number
only the database means anything by.
-->
@if (savingsAccountNo) {
@if (accountNo) {
<!-- The party is the DDS account now, so its number, scheme and balance are its own. -->
<div class="pm-f">
<label class="pm-f-lbl">DDS Account</label>
<div class="pm-account">
<span class="pm-account-no">{{ accountNo }}</span>
<span class="pm-account-meta">
{{ accountSchemeName }} ·
<span [class.pm-account-live]="partyStatus === 'ACTIVE'">{{
partyStatus === 'ACTIVE' ? 'Active' : partyStatus
}}</span>
· {{ accountBalance | number: '1.2-2' }}
</span>
</div>
</div>
} @else if (savingsAccountNo) {
<div class="pm-f">
<label class="pm-f-lbl">DDS Account</label>
<div class="pm-account">
<span class="pm-account-no">{{ savingsAccountNo }}</span>
<span class="pm-account-meta">
{{ savingsProductName }} ·
<span [class.pm-account-live]="savingsAccountStatus === 'Active'">{{ savingsAccountStatus }}</span>
<span [class.pm-account-live]="savingsAccountStatus === 'Active'">{{
savingsAccountStatus
}}</span>
· {{ savingsAccountBalance | number: '1.2-2' }}
</span>
</div>
@@ -224,7 +255,7 @@
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Party Name<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="partyName" />
<input matInput required formControlName="partyName" [readonly]="isFromClient('partyName')" />
</mat-form-field>
</div>
@@ -234,39 +265,45 @@
<input matInput formControlName="partyName1" />
</mat-form-field>
</div>
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Address 1<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="address1" />
<input matInput required formControlName="address1" [readonly]="isFromClient('address1')" />
</mat-form-field>
</div>
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Address 2</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="address2" />
<input matInput formControlName="address2" [readonly]="isFromClient('address2')" />
</mat-form-field>
</div>
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Address 3</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="address3" />
<input matInput formControlName="address3" [readonly]="isFromClient('address3')" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">City<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="city" />
<input matInput required formControlName="city" [readonly]="isFromClient('city')" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Pincode<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="pincode" mifosxRestrictInput="digits" />
<input
matInput
required
formControlName="pincode"
[readonly]="isFromClient('pincode')"
mifosxRestrictInput="digits"
/>
</mat-form-field>
</div>
@@ -284,35 +321,61 @@
<div class="pm-f">
<label class="pm-f-lbl">Telephone</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="telephone" mifosxRestrictInput="phone" />
<input
matInput
formControlName="telephone"
[readonly]="isFromClient('telephone')"
mifosxRestrictInput="phone"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Mobile No (SMS)<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="mobileNoSms" mifosxRestrictInput="digits" />
<input
matInput
required
formControlName="mobileNoSms"
[readonly]="isFromClient('mobileNoSms')"
mifosxRestrictInput="digits"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Aadhar No</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="aadharNo" mifosxRestrictInput="aadhaar" />
<input
matInput
formControlName="aadharNo"
[readonly]="isFromClient('aadharNo')"
mifosxRestrictInput="aadhaar"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">PAN Card No</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="panCardNo" mifosxRestrictInput="pan" />
<input
matInput
formControlName="panCardNo"
[readonly]="isFromClient('panCardNo')"
mifosxRestrictInput="pan"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">CKYC ID</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="ckycId" mifosxRestrictInput="digits" />
<input
matInput
formControlName="ckycId"
[readonly]="isFromClient('ckycId')"
mifosxRestrictInput="digits"
/>
</mat-form-field>
</div>
@@ -330,7 +393,12 @@
<div class="pm-f">
<label class="pm-f-lbl">Birth Date</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="birthPicker" formControlName="birthDate" />
<input
matInput
[matDatepicker]="birthPicker"
formControlName="birthDate"
[readonly]="isFromClient('birthDate')"
/>
<mat-datepicker-toggle matIconSuffix [for]="birthPicker"></mat-datepicker-toggle>
<mat-datepicker #birthPicker></mat-datepicker>
</mat-form-field>
@@ -364,7 +432,9 @@
<div class="pm-section__header">
<i class="fas fa-user-friends"></i>
<h3>Minor / Guardian</h3>
<span class="pm-section__sub">Only for a minor's account — the guardian who operates it until they come of age</span>
<span class="pm-section__sub"
>Only for a minor's account — the guardian who operates it until they come of age</span
>
</div>
<div class="pm-grid">
<div class="pm-f">
@@ -382,7 +452,13 @@
<div class="pm-f">
<label class="pm-f-lbl">Minor Date<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required [matDatepicker]="minorPicker" formControlName="minorDate" />
<input
matInput
required
[matDatepicker]="minorPicker"
formControlName="minorDate"
[readonly]="isFromClient('minorDate')"
/>
<mat-datepicker-toggle matIconSuffix [for]="minorPicker"></mat-datepicker-toggle>
<mat-datepicker #minorPicker></mat-datepicker>
<mat-hint>Turns 18 on</mat-hint>
@@ -396,12 +472,17 @@
matInput
required
formControlName="guardianClientId"
[readonly]="isFromClient('guardianClientId')"
[matAutocomplete]="guardianAuto"
placeholder="Type an ID or search by name…"
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<mat-autocomplete #guardianAuto="matAutocomplete" panelWidth="min(30rem, 92vw)" [displayWith]="displayClient">
<mat-autocomplete
#guardianAuto="matAutocomplete"
panelWidth="min(30rem, 92vw)"
[displayWith]="displayClient"
>
@for (client of guardianOptions; track client.id) {
<mat-option [value]="client">
<div class="pm-opt">
@@ -428,7 +509,7 @@
<div class="pm-f">
<label class="pm-f-lbl">Relation<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="relation" />
<input matInput required formControlName="relation" [readonly]="isFromClient('relation')" />
<mat-hint>To the minor</mat-hint>
</mat-form-field>
</div>
@@ -535,24 +616,8 @@
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Interest Rate</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput type="number" formControlName="interestRate" />
<span matTextSuffix>%</span>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Withdraw Type</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="withdrawType">
@for (type of withdrawTypes; track type) {
<mat-option [value]="type">{{ type }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<!-- Interest Rate is the product's (Sub Type), not typed here. -->
<!-- Withdraw Type is decided when the account is paid out, not when it is opened. -->
</div>
</div>
@@ -610,7 +675,13 @@
<div class="pm-f">
<label class="pm-f-lbl">Please specify<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required maxlength="200" formControlName="lienReasonOther" placeholder="e.g. Loan #1234" />
<input
matInput
required
maxlength="200"
formControlName="lienReasonOther"
placeholder="e.g. Loan #1234"
/>
<mat-hint>Write the reason in your own words</mat-hint>
</mat-form-field>
</div>
@@ -687,17 +758,7 @@
</mat-select>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Adv Code</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="advCode">
@for (code of advCodes; track code) {
<mat-option [value]="code">{{ code }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<!-- Adv Code is decided when the account is paid out, not when it is opened. -->
</div>
</div>
@@ -723,7 +784,7 @@
</mat-form-field>
</div>
<!--
<!--
Picked from the customer's own savings accounts, never typed. The whole matured
amount lands here, and a number that exists only as text is a payout with
nowhere to go - which is what one party was already carrying.
@@ -790,7 +851,10 @@
@if (splitByPercentage && nominees.length > 0) {
<span class="pm-share-total" [class.pm-share-total-bad]="nomineeShareError">
{{ nomineeShareTotal }}% of 100% allocated@if (nomineeShareError) { — {{ nomineeShareError }} }
{{ nomineeShareTotal }}% of 100% allocated
@if (nomineeShareError) {
— {{ nomineeShareError }}
}
</span>
} @else if (splitBySequence && nominees.length > 0) {
<span class="pm-share-total" [class.pm-share-total-bad]="nomineeOrderError">
@@ -865,7 +929,10 @@
</div>
<div class="pm-f">
<label class="pm-f-lbl">
Guar. Name@if (isNomineeMinor(nominee)) {<b>*</b>}
Guar. Name
@if (isNomineeMinor(nominee)) {
<b>*</b>
}
</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [required]="isNomineeMinor(nominee)" formControlName="guardianName" />
@@ -878,7 +945,15 @@
<div class="pm-f pm-f--tight">
<label class="pm-f-lbl">Share %<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput type="number" min="0.01" max="100" step="0.01" required formControlName="sharePercent" />
<input
matInput
type="number"
min="0.01"
max="100"
step="0.01"
required
formControlName="sharePercent"
/>
</mat-form-field>
</div>
} @else {
@@ -922,8 +997,9 @@
<i class="fas fa-user-clock"></i>
<span>
This account was opened for a minor who came of age on
<strong>{{ majorOn | dateFormat }}</strong>. The guardian can no longer
operate it — take fresh KYC, a signature and a new mandate from the account holder.
<strong>{{ majorOn | dateFormat }}</strong
>. The guardian can no longer operate it — take fresh KYC, a signature and a new mandate from the account
holder.
</span>
</div>
}