Files
cbsnexora/src/app/deposits/party-master/create-party/create-party.component.html
T

1052 lines
49 KiB
HTML

<!--
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="pm-container">
<div class="pm-header">
<button mat-stroked-button [routerLink]="['/accounts/dds']" class="pm-back">
<i class="fas fa-arrow-left"></i> Party Master
</button>
<h2 class="pm-header__title">{{ partyId ? 'Edit Party' : 'Party Master Entry' }}</h2>
@if (isClosed) {
<span class="pm-closed-badge">Closed — view only</span>
}
</div>
<div class="pm-card">
<form [formGroup]="partyForm">
<mat-tab-group class="pm-tabs" [(selectedIndex)]="selectedTabIndex" animationDuration="200ms">
<mat-tab label="Main Detail">
<div class="pm-tab-content">
<div class="pm-section">
<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
>
</div>
<div class="pm-grid">
<div class="pm-f">
<label class="pm-f-lbl">Client ID or Name<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input
matInput
required
formControlName="clientId"
[matAutocomplete]="clientAuto"
(focus)="onClientFocus()"
placeholder="Click to see customers, or type a name or ID…"
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<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">
<span class="pm-opt-id">{{ client.id }}</span>
<span class="pm-opt-main">{{ client.displayName }}</span>
<span class="pm-opt-sub">{{ client.officeName }}</span>
</div>
</mat-option>
}
<!-- Says so when the list is only the first page, so a customer missing from
it reads as "keep typing" rather than "not a customer here". -->
@if (clientListIsPartial) {
<mat-option disabled class="pm-opt-more">
Showing {{ clientOptions.length }} of {{ clientTotal }} — type a name to find the rest
</mat-option>
}
</mat-autocomplete>
@if (loadedClientName) {
<mat-hint class="pm-hint--found">{{ loadedClientName }}</mat-hint>
} @else if (clientLookupFailed) {
<mat-hint class="pm-hint--missing">No client with this ID</mat-hint>
}
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Sub Type (Scheme)<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input
matInput
required
formControlName="subType"
[matAutocomplete]="subTypeAuto"
(focus)="showAllSubTypes()"
placeholder="Type to search schemes…"
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<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">
<span class="pm-opt-id">{{ type.accountTypeCode }}</span>
<span class="pm-opt-main">{{ type.accountTypeDescription }}</span>
<span class="pm-opt-sub">{{ type.accountTypeGroup }}</span>
</div>
</mat-option>
}
@if (subTypeOptions.length === 0) {
<mat-option disabled><em>No scheme matches that.</em></mat-option>
}
</mat-autocomplete>
@if (subTypes.length === 0) {
<mat-hint class="pm-hint--missing">No active account type — create one first</mat-hint>
}
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Agent<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input
matInput
required
formControlName="agentId"
[matAutocomplete]="agentAuto"
(focus)="onAgentFocus()"
placeholder="Click to see agents, or type a code or name…"
autocomplete="off"
/>
<fa-icon matSuffix icon="search" class="pm-search-ic"></fa-icon>
<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">
<span class="pm-opt-id">{{ agent.agentCode }}</span>
<span class="pm-opt-main">{{ agent.agentNameId }}</span>
<!-- A stopped agent is still shown, marked: hiding one would silently
drop a party's own collector from the list. -->
<span class="pm-opt-sub">
{{ agent.active ? agent.homeBranch : 'not collecting' }}
</span>
</div>
</mat-option>
}
@if (agentOptions.length === 0) {
<mat-option disabled><em>No agent matches that.</em></mat-option>
}
</mat-autocomplete>
@if (loadedAgentName && !agentLookupFailed) {
<mat-hint class="pm-hint--found">{{ loadedAgentName }}</mat-hint>
} @else if (loadedAgentName && agentLookupFailed) {
<mat-hint class="pm-hint--missing">{{ loadedAgentName }} is deactivated</mat-hint>
} @else if (agentLookupFailed) {
<mat-hint class="pm-hint--missing">No agent with this ID</mat-hint>
}
</mat-form-field>
</div>
<!--
The branch this account belongs to. Asked for, not taken from the agent: an agent
working out of one branch can hold accounts for customers of another, and an
account that silently inherits its agent's branch is counted at the wrong one.
-->
<div class="pm-f">
<label class="pm-f-lbl">Branch<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="officeId">
@for (office of offices; track office.id) {
<mat-option [value]="office.id">{{ office.name }}</mat-option>
}
</mat-select>
@if (officesError) {
<mat-hint class="pm-hint--missing">{{ officesError }}</mat-hint>
} @else {
<mat-hint>The branch this account belongs to</mat-hint>
}
</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 (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>
· {{ savingsAccountBalance | number: '1.2-2' }}
</span>
</div>
</div>
} @else if (partyId) {
<div class="pm-f">
<label class="pm-f-lbl">DDS Account</label>
<div class="pm-account">
<span class="pm-account-missing">No account — opened before DDS started opening them</span>
</div>
</div>
} @else {
<div class="pm-f">
<label class="pm-f-lbl">DDS Account</label>
<div class="pm-account">
<span class="pm-account-meta">Opens automatically when this party is saved</span>
</div>
</div>
}
<div class="pm-f">
<label class="pm-f-lbl">Party Code</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="partyCode" placeholder="Auto-generated" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Last A/c</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="lastAccount" placeholder="—" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Nominal<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="nominal">
<mat-option value="Yes">Yes</mat-option>
<mat-option value="No">No</mat-option>
</mat-select>
</mat-form-field>
</div>
<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" [readonly]="isFromClient('partyName')" />
</mat-form-field>
</div>
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Party Name 1</label>
<mat-form-field appearance="outline" class="pm-field">
<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" [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" [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" [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" [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"
[readonly]="isFromClient('pincode')"
mifosxRestrictInput="digits"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Gender</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="gender">
<mat-option value="Male">Male</mat-option>
<mat-option value="Female">Female</mat-option>
<mat-option value="Other">Other</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Telephone</label>
<mat-form-field appearance="outline" class="pm-field">
<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"
[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"
[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"
[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"
[readonly]="isFromClient('ckycId')"
mifosxRestrictInput="digits"
/>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Operation<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="operation">
@for (op of operations; track op) {
<mat-option [value]="op">{{ op }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<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"
[readonly]="isFromClient('birthDate')"
/>
<mat-datepicker-toggle matIconSuffix [for]="birthPicker"></mat-datepicker-toggle>
<mat-datepicker #birthPicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Occupation</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="occupation">
@for (occ of occupations; track occ) {
<mat-option [value]="occ">{{ occ }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Risk</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="risk">
@for (r of riskLevels; track r) {
<mat-option [value]="r">{{ r }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
</div>
<div class="pm-section">
<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
>
</div>
<div class="pm-grid">
<div class="pm-f">
<label class="pm-f-lbl">Adult / Minor<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="adultMinor">
@for (opt of adultMinorOptions; track opt) {
<mat-option [value]="opt">{{ opt }}</mat-option>
}
</mat-select>
</mat-form-field>
</div>
@if (isMinorAccount) {
<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"
[readonly]="isFromClient('minorDate')"
/>
<mat-datepicker-toggle matIconSuffix [for]="minorPicker"></mat-datepicker-toggle>
<mat-datepicker #minorPicker></mat-datepicker>
<mat-hint>Turns 18 on</mat-hint>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Guardian Client ID or Name<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input
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"
>
@for (client of guardianOptions; track client.id) {
<mat-option [value]="client">
<div class="pm-opt">
<span class="pm-opt-id">{{ client.id }}</span>
<span class="pm-opt-main">{{ client.displayName }}</span>
<span class="pm-opt-sub">{{ client.officeName }}</span>
</div>
</mat-option>
}
</mat-autocomplete>
@if (loadedGuardianName) {
<mat-hint class="pm-hint--found">{{ loadedGuardianName }}</mat-hint>
}
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Min. A/c Opt</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="minAccountOpt" />
</mat-form-field>
</div>
<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" [readonly]="isFromClient('relation')" />
<mat-hint>To the minor</mat-hint>
</mat-form-field>
</div>
}
</div>
@if (!isMinorAccount) {
<p class="pm-note">An adult's account needs no guardian details.</p>
}
</div>
<div class="pm-section">
<div class="pm-section__header">
<i class="fas fa-calendar-day"></i>
<h3>Scheme Terms</h3>
<span class="pm-section__sub">How much is collected daily, for how long, and what it matures to</span>
</div>
<div class="pm-grid">
<div class="pm-f">
<label class="pm-f-lbl">Opening Date<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<!--
A new account opens today, so yesterday is greyed out - a date in the past would
make the scheme look older than it is, with its lock-in further along and its
maturity falling before the money was collected for it. No floor while editing:
an account already on the books opened in the past by definition, and a floor of
today would make every one of them unsaveable.
-->
<input
matInput
required
[matDatepicker]="openingPicker"
[min]="minOpeningDate"
formControlName="openingDate"
/>
<mat-datepicker-toggle matIconSuffix [for]="openingPicker"></mat-datepicker-toggle>
<mat-datepicker #openingPicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Month</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput type="number" formControlName="month" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Maturity Date</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="maturityPicker" formControlName="maturityDate" />
<mat-datepicker #maturityPicker></mat-datepicker>
<mat-hint>Calculated</mat-hint>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Reopen Date</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="reopenPicker" formControlName="reopenDate" />
<mat-datepicker-toggle matIconSuffix [for]="reopenPicker"></mat-datepicker-toggle>
<mat-datepicker #reopenPicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Deposit Amt</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput type="number" formControlName="depositAmount" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Daily Deposit Amt<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required type="number" formControlName="dailyDepositAmount" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Days<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required type="number" formControlName="days" />
@if (partyForm.get('days')?.hasError('exceedsTerm')) {
<mat-error>Only {{ termDays }} days in this term</mat-error>
} @else if (termDays) {
<mat-hint>Term is {{ termDays }} days</mat-hint>
}
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Ledger No</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="ledgerNo" />
<mat-hint>Collection book no.</mat-hint>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Mat. Amt</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput disabled class="pm-money" [value]="money('maturityAmount')" />
<mat-hint>Calculated</mat-hint>
</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>
<div class="pm-section">
<div class="pm-section__header">
<i class="fas fa-exclamation-triangle"></i>
<h3>Balances &amp; Status</h3>
<span class="pm-section__sub">Kept by collections and the nightly batch — shown here, never typed</span>
</div>
<div class="pm-grid">
<div class="pm-checkbox-field">
<mat-checkbox formControlName="od1Flag">OD1 Flag</mat-checkbox>
</div>
<div class="pm-checkbox-field">
<mat-checkbox formControlName="od2Flag">OD2 Flag</mat-checkbox>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Lien</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="lien">
<mat-option value="Yes">Yes</mat-option>
<mat-option value="No">No</mat-option>
</mat-select>
@if (lienHeld) {
<mat-hint>Nothing can leave this account until it is released</mat-hint>
}
</mat-form-field>
</div>
<!--
Why the money is held. Asked for only when it is: the flag alone says an account is
frozen and never says what for, which is how a lien outlives the loan it secured -
months later nobody can tell whether it has been repaid, so nobody will release it
and nobody can justify keeping it.
-->
@if (lienHeld) {
<div class="pm-f">
<label class="pm-f-lbl">Lien Reason<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="lienReason">
@for (reason of lienReasons; track reason) {
<mat-option [value]="reason">{{ reason }}</mat-option>
}
</mat-select>
<mat-hint>What this money is being held for</mat-hint>
</mat-form-field>
</div>
<!--
Only where the list genuinely does not cover it. Picking "Other" and leaving
this blank would say no more than leaving the whole reason blank did.
-->
@if (lienReasonIsOther) {
<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"
/>
<mat-hint>Write the reason in your own words</mat-hint>
</mat-form-field>
</div>
}
}
<div class="pm-f">
<label class="pm-f-lbl">Pay Date</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="payDatePicker" formControlName="payDate" />
<mat-datepicker-toggle matIconSuffix [for]="payDatePicker"></mat-datepicker-toggle>
<mat-datepicker #payDatePicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Payment Amount</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput disabled class="pm-money" [value]="money('paymentAmount')" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Current Bal</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput disabled class="pm-money" [value]="money('currentBalance')" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Opening Bal</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput disabled class="pm-money" [value]="money('openingBalance')" />
</mat-form-field>
</div>
<div class="pm-checkbox-field">
<mat-checkbox formControlName="isSmsActive">Is SMS Active</mat-checkbox>
</div>
<div class="pm-checkbox-field">
<mat-checkbox formControlName="isEmailActive">Is Email Active</mat-checkbox>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Int.Calc</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput disabled class="pm-money" [value]="money('interestCalc')" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Interest Date</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="interestDatePicker" formControlName="interestDate" />
<mat-datepicker-toggle matIconSuffix [for]="interestDatePicker"></mat-datepicker-toggle>
<mat-datepicker #interestDatePicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f pm-f--wide">
<label class="pm-f-lbl">Sp.Description</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="spDescription" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Fr'z CD</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="freezeCode">
@for (code of freezeCodes; 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>
@if (creditToRequired) {
<div class="pm-section">
<div class="pm-section__header">
<i class="fas fa-exchange-alt"></i>
<h3>Maturity Payout Routing</h3>
</div>
<p class="pm-note">Transfer To Saving — say where the maturity proceeds should land.</p>
<div class="pm-grid">
<div class="pm-f">
<label class="pm-f-lbl">Credit To Branch<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="creditToBranch">
@for (office of offices; track office.id) {
<mat-option [value]="office.name">{{ office.name }}</mat-option>
}
</mat-select>
@if (officesError) {
<mat-hint class="pm-hint--missing">{{ officesError }}</mat-hint>
}
</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.
-->
<div class="pm-f">
<label class="pm-f-lbl">Credit To A/C<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select
required
formControlName="creditToAccount"
panelWidth="min(30rem, 92vw)"
(selectionChange)="onCreditToAccountPicked($event.value)"
>
@for (account of creditToAccounts; track account.id) {
<mat-option [value]="account.accountNo">
{{ account.accountNo }} · {{ account.productName }}
</mat-option>
}
</mat-select>
@if (creditToAccounts.length === 0) {
<mat-hint class="pm-hint--missing">
{{ loadedClientName || 'This customer' }} has no other savings account to credit
</mat-hint>
}
</mat-form-field>
</div>
<!-- Read off the chosen account rather than asked for separately. -->
<div class="pm-f">
<label class="pm-f-lbl">Credit To A/C Type<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput readonly formControlName="creditToAccountType" />
</mat-form-field>
</div>
</div>
</div>
}
</div>
</mat-tab>
<mat-tab label="Nominee's Detail">
<div class="pm-tab-content">
<div class="pm-section">
<div class="pm-grid">
<div class="pm-f">
<label class="pm-f-lbl">Nominee</label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select formControlName="nomineeApplicable">
<mat-option value="Yes">Yes</mat-option>
<mat-option value="No">No</mat-option>
</mat-select>
</mat-form-field>
</div>
@if (nomineesRequired) {
<mat-radio-group formControlName="nomineeSplitMode" class="pm-radio-group">
<mat-radio-button value="Percentage">Percentage</mat-radio-button>
<mat-radio-button value="Sequence">Sequence</mat-radio-button>
</mat-radio-group>
<button mat-stroked-button type="button" class="pm-add-nominee" (click)="addNominee()">
<i class="fas fa-plus"></i> Add Nominee
</button>
@if (splitByPercentage && nominees.length > 0) {
<span class="pm-share-total" [class.pm-share-total-bad]="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">
@if (nomineeOrderError) {
{{ nomineeOrderError }}
} @else {
Paid in the order numbered, 1 first
}
</span>
}
}
</div>
@if (!nomineesRequired) {
<p class="pm-note">Set Nominee to Yes to nominate someone for this account.</p>
}
@for (nominee of nominees.controls; track nominee; let i = $index) {
<div class="pm-nominee-row" [formGroup]="$any(nominee)">
<div class="pm-f pm-f--date">
<label class="pm-f-lbl">Nom.Dt<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required [matDatepicker]="nomDatePicker" formControlName="nominationDate" />
<mat-datepicker-toggle matIconSuffix [for]="nomDatePicker"></mat-datepicker-toggle>
<mat-datepicker #nomDatePicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Name<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput required formControlName="name" />
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">Mobile No</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput formControlName="mobileNo" mifosxRestrictInput="digits" />
</mat-form-field>
</div>
<div class="pm-f pm-f--date">
<label class="pm-f-lbl">Birth Dt</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [matDatepicker]="nomBirthPicker" formControlName="birthDate" />
<mat-datepicker-toggle matIconSuffix [for]="nomBirthPicker"></mat-datepicker-toggle>
<mat-datepicker #nomBirthPicker></mat-datepicker>
</mat-form-field>
</div>
<div class="pm-f pm-f--tight">
<!-- Read from the date of birth, not asked: the two arriving separately is how
a ten-year-old came to be recorded as not a minor. -->
<label class="pm-f-lbl">Minor</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput readonly [value]="isNomineeMinor(nominee) ? 'Yes' : 'No'" />
<mat-hint>From date of birth</mat-hint>
</mat-form-field>
</div>
<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" />
</mat-form-field>
</div>
<div class="pm-f pm-f--tight">
<label class="pm-f-lbl">Gender<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<mat-select required formControlName="gender">
<mat-option value="Male">Male</mat-option>
<mat-option value="Female">Female</mat-option>
<mat-option value="Other">Other</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="pm-f">
<label class="pm-f-lbl">
Guar. Name
@if (isNomineeMinor(nominee)) {
<b>*</b>
}
</label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput [required]="isNomineeMinor(nominee)" formControlName="guardianName" />
@if (isNomineeMinor(nominee)) {
<mat-hint>Required for a minor</mat-hint>
}
</mat-form-field>
</div>
@if (splitByPercentage) {
<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"
/>
</mat-form-field>
</div>
} @else {
<div class="pm-f pm-f--tight">
<label class="pm-f-lbl">Order<b>*</b></label>
<mat-form-field appearance="outline" class="pm-field">
<input matInput type="number" min="1" step="1" required formControlName="sequenceNo" />
</mat-form-field>
</div>
}
<button
mat-icon-button
type="button"
class="pm-remove-nominee"
(click)="removeNominee(i)"
matTooltip="Remove nominee"
>
<i class="fas fa-trash"></i>
</button>
</div>
}
</div>
</div>
</mat-tab>
</mat-tab-group>
@if (isClosed) {
<div class="pm-callout">
<i class="fas fa-lock"></i>
<span>This account is closed. No further collections or edits are possible.</span>
</div>
}
<!--
A minor who has come of age. The guardian's authority to operate the account ended on that
day, so this is something the branch has to act on rather than a detail on a tab - which is
why it sits beside the action bar where a closed account's notice does.
-->
@if (minorTurnedMajor) {
<div class="pm-callout pm-callout--action">
<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.
</span>
</div>
}
<div class="pm-action-bar">
<button mat-raised-button type="button" (click)="exit()">Exit</button>
<button mat-stroked-button type="button" (click)="cancel()">Cancel</button>
<!--
Closing before the term is up. Kept here beside the ordinary close rather than on the party
list: it cannot be undone and it changes what the customer is owed, so it belongs on the
screen where the officer has the account open in front of them, not one click from a row.
Hidden once the account has matured - that one is paid out and closed on its own terms, and
the server refuses this on it.
-->
@if (partyId && !isClosed && canCloseEarly) {
<button
mat-stroked-button
type="button"
class="pm-early-btn"
matTooltip="Close this account before its term ends, settling the shortfall"
(click)="closeEarly()"
>
<i class="fas fa-times" style="margin-right: 6px"></i> Close Early
</button>
}
@if (partyId && !isClosed) {
<button
mat-stroked-button
type="button"
color="warn"
matTooltip="Balance must be zero before closing"
(click)="closeAccount()"
>
<i class="fas fa-lock" style="margin-right: 6px"></i> Close Account
</button>
}
<button
mat-raised-button
color="primary"
type="button"
[disabled]="partyForm.invalid || isClosed || !!nomineeShareError || !!nomineeOrderError"
(click)="save()"
>
Save
</button>
</div>
</form>
</div>
</div>