Files
cbsnexora/src/app/shares/shares-account-actions/apply-shares/apply-shares.component.html
T
2026-09-23 15:51:10 +05:30

373 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
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="dialog-wrapper">
<div class="dialog-header">
<div class="header-icon">
<mat-icon>trending_up</mat-icon>
</div>
<div class="header-text">
<h2>Apply Additional Shares</h2>
<p>
Share account <strong class="mono">{{ data.accountNo }}</strong>
</p>
</div>
<button type="button" mat-icon-button class="header-close" [mat-dialog-close]="false" aria-label="Close">
<mat-icon>close</mat-icon>
</button>
</div>
<!-- ── Shares / Price / Amount strip — outside scroll area so always visible ── -->
<div class="shares-subheader">
<div class="shares-strip">
<div class="shares-cell shares-cell-input">
<span class="shares-label">Shares</span>
<input
class="req-input mono"
type="number"
min="1"
step="1"
inputmode="numeric"
placeholder="0"
[(ngModel)]="requestedShares"
(ngModelChange)="onSharesChange()"
/>
</div>
<div class="shares-cell">
<span class="shares-label">Unit Price</span>
<span class="shares-value mono">{{ unitPrice | number: '1.2-2' }}</span>
</div>
<div class="shares-cell shares-cell-total">
<span class="shares-label">Total Amount</span>
<span class="shares-value mono">{{ amount | number: '1.2-2' }}</span>
</div>
</div>
</div>
<mat-dialog-content class="dialog-body">
<!-- ── Step 1: Board Resolution ──────────────────────────────────────── -->
<section class="slot">
<header class="slot-head">
<span class="slot-step">1</span>
<div class="slot-title">
<h3>Board Resolution</h3>
<p>The meeting that authorised this tranche, not the one the account was opened under.</p>
</div>
</header>
<div class="field-row">
<label class="field">
<span>Resolution No.</span>
<input type="text" [(ngModel)]="resolutionNumber" placeholder="e.g. BR/2026/14" autocomplete="off" />
</label>
<label class="field">
<span>Meeting Date</span>
<input type="date" [(ngModel)]="resolutionDate" />
</label>
<label class="field">
<span>Request Date</span>
<input type="date" [(ngModel)]="requestedDate" />
</label>
</div>
</section>
<!-- ── Step 2: Funding ───────────────────────────────────────────────── -->
<section class="slot">
<header class="slot-head">
<span class="slot-step">2</span>
<div class="slot-title">
<h3>Funding</h3>
<p>Approval posts Dr Sundry / Cr Share Capital either way.</p>
</div>
@if (funding === 'CASH') {
<button type="button" class="slot-search" (click)="openSearch()">
<mat-icon>search</mat-icon>
<span>Find by voucher</span>
</button>
}
</header>
<div class="funding-choice">
<button
type="button"
class="funding-btn"
[class.funding-on]="funding === 'CASH'"
(click)="chooseFunding('CASH')"
>
<mat-icon>payments</mat-icon>
<span class="funding-name">Cash</span>
<span class="funding-hint">Already paid at the counter</span>
</button>
<button
type="button"
class="funding-btn"
[class.funding-on]="funding === 'SAVINGS'"
(click)="chooseFunding('SAVINGS')"
>
<mat-icon>savings</mat-icon>
<span class="funding-name">Savings</span>
<span class="funding-hint">Debited on submit</span>
</button>
</div>
@if (funding === 'CASH') {
@if (loadingReceipts) {
<div class="state-block">
<mat-spinner diameter="24"></mat-spinner>
<span>Loading receipts…</span>
</div>
} @else if (receipt) {
<div class="chosen" [class.chosen-short]="shortfall > 0">
<div class="chosen-badge">
<mat-icon>{{ shortfall > 0 ? 'warning' : 'check_circle' }}</mat-icon>
</div>
<div class="chosen-main">
<span class="chosen-voucher mono">{{ receipt.voucherNo }}</span>
<span class="chosen-gl">{{ glLabel(receipt) }}</span>
</div>
<span class="chosen-amount mono">{{ receipt.amount | number: '1.2-2' }}</span>
<button type="button" class="chosen-clear" (click)="clearReceipt()" aria-label="Change receipt">
<mat-icon>close</mat-icon>
</button>
</div>
@if (shortfall > 0) {
<p class="slot-note note-bad">
Short by {{ shortfall | number: '1.2-2' }} — this receipt does not cover {{ amount | number: '1.2-2' }}.
</p>
} @else {
<p class="slot-note note-good">Covers the {{ amount | number: '1.2-2' }} tranche.</p>
}
} @else if (available.length) {
<ul class="options">
@for (option of available; track option.key) {
<li class="option" [class.option-busy]="attaching === option.key" (click)="pick(option)">
<span class="option-radio"></span>
<div class="option-main">
<span class="option-voucher mono">{{ option.voucherNo }}</span>
<span class="option-meta">{{ option.date }} · {{ glLabel(option) }}</span>
@if (option.description) {
<span class="option-desc">{{ option.description }}</span>
}
</div>
<span class="option-amount mono">{{ option.amount | number: '1.2-2' }}</span>
@if (attaching === option.key) {
<mat-spinner diameter="16"></mat-spinner>
} @else if (option.collectionId !== null) {
<button
type="button"
class="option-info"
(click)="openDetail(option, $event)"
aria-label="GL entries"
>
<mat-icon>receipt_long</mat-icon>
</button>
}
</li>
}
</ul>
} @else {
<p class="slot-empty">
No Share Collection receipt is waiting. Collect the cash at <em>Cashier › Transaction Entry</em> with entry
type <strong>Share Collection</strong>, or find an earlier voucher by number.
</p>
}
}
@if (funding === 'SAVINGS') {
@if (checkingSavings) {
<div class="state-block">
<mat-spinner diameter="24"></mat-spinner>
<span>Checking the linked savings account…</span>
</div>
} @else if (savings) {
<div class="chosen" [class.chosen-short]="!savings.eligible">
<div class="chosen-badge">
<mat-icon>{{ savings.eligible ? 'check_circle' : 'warning' }}</mat-icon>
</div>
<div class="chosen-main">
<span class="chosen-voucher">
@if (savings.savingsAccountNo) {
Savings <span class="mono">{{ savings.savingsAccountNo }}</span>
} @else {
Linked savings account
}
</span>
<span class="chosen-gl">
{{ savings.eligible ? 'Debited into Share Sundry on submit.' : savings.reason }}
</span>
</div>
@if (savings.savingsBalance !== null) {
<span class="chosen-amount mono">{{ savings.savingsBalance | number: '1.2-2' }}</span>
}
</div>
} @else {
<p class="slot-note note-muted">Enter the number of shares to check the member's balance.</p>
}
}
</section>
@if (errorMsg) {
<div class="alert">
<mat-icon>error_outline</mat-icon>
<span>{{ errorMsg }}</span>
</div>
}
</mat-dialog-content>
<mat-dialog-actions class="dialog-actions">
<button type="button" mat-stroked-button [mat-dialog-close]="false" [disabled]="submitting">Cancel</button>
<button type="button" mat-flat-button color="primary" [disabled]="!canSubmit" (click)="submit()">
@if (submitting) {
<mat-spinner diameter="16"></mat-spinner>
<span>Submitting…</span>
} @else {
<mat-icon>check</mat-icon>
<span>Submit Request</span>
}
</button>
</mat-dialog-actions>
</div>
<!-- ── Find a voucher the list does not carry ───────────────────────────────── -->
@if (searchOpen) {
<div class="overlay" (click)="closeSearch()">
<div class="popup" (click)="$event.stopPropagation()">
<header class="popup-head">
<h3>Find a receipt</h3>
<button type="button" mat-icon-button (click)="closeSearch()" aria-label="Close">
<mat-icon>close</mat-icon>
</button>
</header>
<div class="popup-body">
<label class="field">
<span>GL Account</span>
<select [(ngModel)]="searchGlAccountNo" [disabled]="loadingGlAccounts">
<option value="">{{ loadingGlAccounts ? 'Loading…' : 'Select the account it was paid into' }}</option>
@for (gl of glAccounts; track gl.id) {
<option [value]="gl.gl_code">{{ gl.gl_code }} — {{ gl.name }}</option>
}
</select>
</label>
<label class="field">
<span>Voucher No.</span>
<input
type="text"
[(ngModel)]="searchVoucherNo"
placeholder="CR/18092026/0004"
(keyup.enter)="runSearch()"
autocomplete="off"
/>
</label>
@if (errorMsg) {
<div class="alert">
<mat-icon>error_outline</mat-icon>
<span>{{ errorMsg }}</span>
</div>
}
</div>
<footer class="popup-foot">
<button type="button" mat-stroked-button (click)="closeSearch()">Cancel</button>
<button
type="button"
mat-flat-button
color="primary"
[disabled]="!searchVoucherNo.trim() || !searchGlAccountNo.trim() || searching"
(click)="runSearch()"
>
@if (searching) {
<mat-spinner diameter="16"></mat-spinner>
} @else {
<span>Find &amp; Use</span>
}
</button>
</footer>
</div>
</div>
}
<!-- ── A receipt's own GL entries ───────────────────────────────────────────── -->
@if (viewing) {
<div class="overlay" (click)="closeDetail()">
<div class="popup" (click)="$event.stopPropagation()">
<header class="popup-head">
<h3>
Voucher <span class="mono">{{ viewing.voucherNo }}</span>
</h3>
<button type="button" mat-icon-button (click)="closeDetail()" aria-label="Close">
<mat-icon>close</mat-icon>
</button>
</header>
<div class="popup-body">
<dl class="detail-list">
<div>
<dt>Date</dt>
<dd class="mono">{{ viewing.date }}</dd>
</div>
<div>
<dt>Amount</dt>
<dd class="mono">{{ viewing.amount | number: '1.2-2' }}</dd>
</div>
<div>
<dt>GL Account</dt>
<dd>{{ glLabel(viewing) }}</dd>
</div>
@if (viewing.cashierName) {
<div>
<dt>Collected By</dt>
<dd>{{ viewing.cashierName }}</dd>
</div>
}
@if (viewing.description) {
<div>
<dt>Description</dt>
<dd>{{ viewing.description }}</dd>
</div>
}
</dl>
<h4 class="detail-heading">Journal Entries</h4>
@if (loadingGlEntries) {
<div class="state-block"><mat-spinner diameter="22"></mat-spinner></div>
} @else if (viewingGlEntries?.length) {
<table class="gl-table">
<thead>
<tr>
<th>Account</th>
<th class="num">Debit</th>
<th class="num">Credit</th>
</tr>
</thead>
<tbody>
@for (entry of viewingGlEntries; track $index) {
<tr>
<td>
<span class="mono">{{ entry.glCode }}</span> {{ entry.accountName }}
</td>
<td class="num mono">{{ entry.drCr === 'Dr' ? (entry.amount | number: '1.2-2') : '' }}</td>
<td class="num mono">{{ entry.drCr === 'Cr' ? (entry.amount | number: '1.2-2') : '' }}</td>
</tr>
}
</tbody>
</table>
} @else {
<p class="slot-empty">No journal entries are recorded against this receipt.</p>
}
</div>
<footer class="popup-foot">
<button type="button" mat-stroked-button (click)="closeDetail()">Close</button>
</footer>
</div>
</div>
}