- DDS Product Creation split into Details / Interest & Maturity / Premature Closure / Accounting tabs, like the savings product - Accounting tab picks Customer Deposits (liability), Interest Expense and Agent Commission Expense (expense) GLs; product view shows them - Approval review shows the product's GLs, old -> new on edits - Agent master no longer reads the removed dds-deposit-product setting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
722 lines
30 KiB
HTML
722 lines
30 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/.
|
|
-->
|
|
|
|
<!-- Laid out as Disbursement & Transfers reviews its requests, and styled by the same sheet. -->
|
|
<div class="dri dri--dialog">
|
|
<nav class="cashier-nav cashier-nav--clerk">
|
|
<span class="dri-header-title">DDS {{ entry.type }} Review</span>
|
|
<span class="cashier-nav__esc-hint" (click)="close()">✕ Close</span>
|
|
</nav>
|
|
|
|
@if (loading) {
|
|
<div class="dri-loading">
|
|
<mat-icon class="dri-loading__icon">hourglass_empty</mat-icon>
|
|
<span>Loading entry…</span>
|
|
</div>
|
|
} @else {
|
|
<div class="dri-body" [class.ddr-body]="isProductReview || isAgentReview || isPartyReview">
|
|
@if (isProductReview) {
|
|
<!--
|
|
A DDS product request reads as the product it creates or changes: who and what at the top,
|
|
the four terms a checker looks at first, then every term grouped as the Account Type screen
|
|
asks for them. An edit shows each changed term as old → new.
|
|
-->
|
|
<section class="ddr-hero">
|
|
<div class="ddr-hero__icon">
|
|
<mat-icon>{{ isEdit ? 'edit_note' : 'savings' }}</mat-icon>
|
|
</div>
|
|
<div class="ddr-hero__main">
|
|
<div class="ddr-hero__eyebrow">
|
|
<span class="ddr-chip" [class.ddr-chip--edit]="isEdit">{{
|
|
isEdit ? 'Edit request' : 'New product'
|
|
}}</span>
|
|
<span class="dri-status" [ngClass]="statusClass(entry.status)">{{ entry.status }}</span>
|
|
</div>
|
|
<h2 class="ddr-hero__title">{{ valueOf('accountTypeDescription') || entry.details || 'DDS Product' }}</h2>
|
|
<div class="ddr-hero__code">
|
|
<span class="ddr-mono">{{ valueOf('accountTypeCode') || '—' }}</span>
|
|
@if (valueOf('accountTypeGroup')) {
|
|
<span class="ddr-dot"></span>
|
|
<span>{{ valueOf('accountTypeGroup') }} group</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="ddr-hero__meta">
|
|
<span class="ddr-meta">
|
|
<mat-icon>person</mat-icon>
|
|
<span>
|
|
<b>{{ entry.makerName || entry.maker }}</b>
|
|
<small>{{ entry.maker }}</small>
|
|
</span>
|
|
</span>
|
|
<span class="ddr-meta">
|
|
<mat-icon>schedule</mat-icon>
|
|
<span>
|
|
<b>{{ formatDateTime(entry.madeOn) }}</b>
|
|
<small>Submitted</small>
|
|
</span>
|
|
</span>
|
|
@if (entry.status !== 'PENDING' && entry.checker) {
|
|
<span class="ddr-meta">
|
|
<mat-icon>verified_user</mat-icon>
|
|
<span>
|
|
<b>{{ entry.checkerName || entry.checker }}</b>
|
|
<small>{{ entry.status === 'APPROVED' ? 'Approved by' : 'Rejected by' }}</small>
|
|
</span>
|
|
</span>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- The terms a checker reads first. -->
|
|
<section class="ddr-stats">
|
|
<div class="ddr-stat ddr-stat--accent">
|
|
<span class="ddr-stat__label"><mat-icon>percent</mat-icon>Interest Rate</span>
|
|
<span class="ddr-stat__value">{{ valueOf('interestRate') || '—' }}</span>
|
|
<span class="ddr-stat__hint">p.a., worked out daily</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>event_repeat</mat-icon>Interest Posting</span>
|
|
<span class="ddr-stat__value">
|
|
{{ valueOf('autoInterestPost') === 'No' ? 'Manual' : valueOf('autoInterestPostWhen') || 'Monthly' }}
|
|
</span>
|
|
<span class="ddr-stat__hint">
|
|
{{ valueOf('autoInterestPost') === 'No' ? 'Posted from the batch screen' : 'Automatic, at period end' }}
|
|
</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>lock_clock</mat-icon>Lock-in</span>
|
|
<span class="ddr-stat__value">{{ valueOf('prematureLockinMonths') || '—' }}</span>
|
|
<span class="ddr-stat__hint">before early closure</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>event_available</mat-icon>Maturity</span>
|
|
<span class="ddr-stat__value">{{
|
|
valueOf('maturityAutoClose') === 'Yes' ? 'Auto close' : 'Manual payout'
|
|
}}</span>
|
|
<span class="ddr-stat__hint">on the maturity date</span>
|
|
</div>
|
|
</section>
|
|
|
|
@if (compareFields) {
|
|
<div class="ddr-banner" [class.ddr-banner--none]="!changedCount">
|
|
<mat-icon>{{ changedCount ? 'compare_arrows' : 'info' }}</mat-icon>
|
|
@if (changedCount) {
|
|
<span>
|
|
<b>{{ changedCount }} term{{ changedCount !== 1 ? 's' : '' }}</b> will change on approval - highlighted
|
|
below as current → proposed.
|
|
</span>
|
|
} @else {
|
|
<span>This edit changes nothing - every term matches the product as it stands.</span>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
@for (group of fieldGroups; track group.name) {
|
|
<section class="ddr-section">
|
|
<header class="ddr-section__head">
|
|
<span class="ddr-section__icon"
|
|
><mat-icon>{{ group.icon }}</mat-icon></span
|
|
>
|
|
<span class="ddr-section__title">{{ group.name }}</span>
|
|
@if (group.changed) {
|
|
<span class="ddr-chip ddr-chip--edit">{{ group.changed }} changed</span>
|
|
}
|
|
</header>
|
|
@if (group.name === 'Accounting') {
|
|
<!--
|
|
The ledger accounts the product posts through, laid out as the product's own Accounting
|
|
tab lays them out: the kind of account, what it is for, and the account by name and code.
|
|
-->
|
|
<div class="ddr-acct">
|
|
@for (field of group.fields; track field.key) {
|
|
<div class="ddr-acct__row" [class.ddr-acct__row--changed]="field.changed">
|
|
<div class="ddr-acct__meta">
|
|
<span class="ddr-acct__kind" [ngClass]="'ddr-acct__kind--' + glKind(field.key).toLowerCase()">{{
|
|
glKind(field.key)
|
|
}}</span>
|
|
<span class="ddr-acct__label">
|
|
{{ field.label }}
|
|
@if (field.changed) {
|
|
<span class="ddr-tile__flag">Changed</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
<div class="ddr-acct__value">
|
|
@if (field.changed) {
|
|
<span class="ddr-acct__gl ddr-acct__gl--old">
|
|
{{ glName(field.current) }}
|
|
@if (glCode(field.current)) {
|
|
<span class="ddr-acct__code">{{ glCode(field.current) }}</span>
|
|
}
|
|
</span>
|
|
<mat-icon class="ddr-acct__arrow">arrow_forward</mat-icon>
|
|
}
|
|
<span class="ddr-acct__gl" [class.ddr-acct__gl--none]="!field.value">
|
|
{{ glName(field.value) }}
|
|
@if (glCode(field.value)) {
|
|
<span class="ddr-acct__code">{{ glCode(field.value) }}</span>
|
|
}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
} @else {
|
|
<div class="ddr-grid">
|
|
@for (field of group.fields; track field.key) {
|
|
<div class="ddr-tile" [class.ddr-tile--changed]="field.changed">
|
|
<span class="ddr-tile__label">
|
|
{{ field.label }}
|
|
@if (field.changed) {
|
|
<span class="ddr-tile__flag">Changed</span>
|
|
}
|
|
</span>
|
|
@if (field.changed) {
|
|
<span class="ddr-tile__diff">
|
|
<span class="ddr-tile__old">{{ field.current || '—' }}</span>
|
|
<mat-icon>arrow_forward</mat-icon>
|
|
<ng-container *ngTemplateOutlet="valueTpl; context: { field: field }"></ng-container>
|
|
</span>
|
|
} @else {
|
|
<ng-container *ngTemplateOutlet="valueTpl; context: { field: field }"></ng-container>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</section>
|
|
}
|
|
|
|
<ng-template #valueTpl let-field="field">
|
|
@if (field.format === 'yesno' && field.value) {
|
|
<span class="ddr-pill" [class.ddr-pill--yes]="field.value === 'Yes'">
|
|
<mat-icon>{{ field.value === 'Yes' ? 'check_circle' : 'remove_circle_outline' }}</mat-icon>
|
|
{{ field.value }}
|
|
</span>
|
|
} @else {
|
|
<span class="ddr-tile__value" [class.ddr-mono]="field.key === 'accountTypeCode'">{{
|
|
field.value || '—'
|
|
}}</span>
|
|
}
|
|
</ng-template>
|
|
} @else if (isAgentReview) {
|
|
<!--
|
|
An agent request reads as the agent it opens or changes: who and when at the top, then the
|
|
client, address, branch and accounts - the branch, the ledger account and the client by name,
|
|
not number - and the guarantors named with it. An edit lists only what it changes.
|
|
-->
|
|
<section class="ddr-hero">
|
|
<div class="ddr-hero__icon">
|
|
<mat-icon>{{ isEdit ? 'manage_accounts' : 'person_add' }}</mat-icon>
|
|
</div>
|
|
<div class="ddr-hero__main">
|
|
<div class="ddr-hero__eyebrow">
|
|
<span class="ddr-chip" [class.ddr-chip--edit]="isEdit">{{ isEdit ? 'Edit request' : 'New agent' }}</span>
|
|
<span class="dri-status" [ngClass]="statusClass(entry.status)">{{ entry.status }}</span>
|
|
</div>
|
|
<h2 class="ddr-hero__title">{{ valueOf('agentNameId') || entry.details || 'DDS Agent' }}</h2>
|
|
<div class="ddr-hero__code">
|
|
@if (valueOf('clientId')) {
|
|
<span>Client {{ valueOf('clientId') }}</span>
|
|
}
|
|
@if (valueOf('agentSavingAccountNo')) {
|
|
<span class="ddr-dot"></span>
|
|
<span class="ddr-mono">{{ valueOf('agentSavingAccountNo') }}</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="ddr-hero__meta">
|
|
<span class="ddr-meta">
|
|
<mat-icon>person</mat-icon>
|
|
<span>
|
|
<b>{{ entry.makerName || entry.maker }}</b>
|
|
<small>{{ entry.maker }}</small>
|
|
</span>
|
|
</span>
|
|
<span class="ddr-meta">
|
|
<mat-icon>schedule</mat-icon>
|
|
<span>
|
|
<b>{{ formatDateTime(entry.madeOn) }}</b>
|
|
<small>Submitted</small>
|
|
</span>
|
|
</span>
|
|
@if (entry.status !== 'PENDING' && entry.checker) {
|
|
<span class="ddr-meta">
|
|
<mat-icon>verified_user</mat-icon>
|
|
<span>
|
|
<b>{{ entry.checkerName || entry.checker }}</b>
|
|
<small>{{ entry.status === 'APPROVED' ? 'Approved by' : 'Rejected by' }}</small>
|
|
</span>
|
|
</span>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
@for (group of fieldGroups; track group.name) {
|
|
<section class="ddr-section">
|
|
<header class="ddr-section__head">
|
|
<span class="ddr-section__icon"
|
|
><mat-icon>{{ group.icon }}</mat-icon></span
|
|
>
|
|
<span class="ddr-section__title">{{ group.name }}</span>
|
|
</header>
|
|
<div class="ddr-grid">
|
|
@for (field of group.fields; track field.key) {
|
|
<div class="ddr-tile">
|
|
<span class="ddr-tile__label">{{ field.label }}</span>
|
|
<span class="ddr-tile__value" [class.ddr-mono]="field.key === 'agentSavingAccountNo'">{{
|
|
field.value || '—'
|
|
}}</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
}
|
|
|
|
<section class="ddr-section">
|
|
<header class="ddr-section__head">
|
|
<span class="ddr-section__icon"><mat-icon>shield_person</mat-icon></span>
|
|
<span class="ddr-section__title">Guarantors</span>
|
|
<span class="ddr-chip ddr-chip--edit">{{ guarantors.length }}</span>
|
|
</header>
|
|
@if (guarantors.length) {
|
|
<table class="dri-cr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Client</th>
|
|
<th>Name</th>
|
|
<th>Telephone</th>
|
|
<th>Address</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (g of guarantors; track $index; let i = $index) {
|
|
<tr>
|
|
<td class="dri-cr-idx">{{ i + 1 }}</td>
|
|
<td>{{ g.client || '—' }}</td>
|
|
<td>{{ g.name || '—' }}</td>
|
|
<td class="cell-mono">{{ g.telephone || '—' }}</td>
|
|
<td>{{ g.address || '—' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
} @else {
|
|
<div class="ddr-tile">
|
|
<span class="ddr-tile__value">No guarantors named in this request.</span>
|
|
</div>
|
|
}
|
|
</section>
|
|
} @else if (isPartyReview) {
|
|
<!--
|
|
A DDS account request reads as the account it opens or changes: who it is for and when, the
|
|
terms a checker looks at first, then every detail in the sections the Party Master Entry screen
|
|
has - the client, scheme, agent and branch by name, not number - and the nominees named with it.
|
|
An edit lists only what it changes.
|
|
-->
|
|
<section class="ddr-hero">
|
|
<div class="ddr-hero__icon">
|
|
<mat-icon>{{ isEdit ? 'edit_note' : 'account_balance_wallet' }}</mat-icon>
|
|
</div>
|
|
<div class="ddr-hero__main">
|
|
<div class="ddr-hero__eyebrow">
|
|
<span class="ddr-chip" [class.ddr-chip--edit]="isEdit">{{
|
|
isEdit ? 'Edit request' : 'New DDS account'
|
|
}}</span>
|
|
<span class="dri-status" [ngClass]="statusClass(entry.status)">{{ entry.status }}</span>
|
|
</div>
|
|
<h2 class="ddr-hero__title">{{ valueOf('partyName') || entry.details || 'DDS Account' }}</h2>
|
|
<div class="ddr-hero__code">
|
|
@if (valueOf('subType')) {
|
|
<span>{{ valueOf('subType') }}</span>
|
|
}
|
|
@if (valueOf('clientId')) {
|
|
<span class="ddr-dot"></span>
|
|
<span>Client {{ valueOf('clientId') }}</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="ddr-hero__meta">
|
|
<span class="ddr-meta">
|
|
<mat-icon>person</mat-icon>
|
|
<span>
|
|
<b>{{ entry.makerName || entry.maker }}</b>
|
|
<small>{{ entry.maker }}</small>
|
|
</span>
|
|
</span>
|
|
<span class="ddr-meta">
|
|
<mat-icon>schedule</mat-icon>
|
|
<span>
|
|
<b>{{ formatDateTime(entry.madeOn) }}</b>
|
|
<small>Submitted</small>
|
|
</span>
|
|
</span>
|
|
@if (entry.status !== 'PENDING' && entry.checker) {
|
|
<span class="ddr-meta">
|
|
<mat-icon>verified_user</mat-icon>
|
|
<span>
|
|
<b>{{ entry.checkerName || entry.checker }}</b>
|
|
<small>{{ entry.status === 'APPROVED' ? 'Approved by' : 'Rejected by' }}</small>
|
|
</span>
|
|
</span>
|
|
}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- The terms a checker reads first. -->
|
|
<section class="ddr-stats">
|
|
<div class="ddr-stat ddr-stat--accent">
|
|
<span class="ddr-stat__label"><mat-icon>payments</mat-icon>Daily Deposit</span>
|
|
<span class="ddr-stat__value">{{ valueOf('dailyDepositAmount') || '—' }}</span>
|
|
<span class="ddr-stat__hint">collected every day</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>date_range</mat-icon>Term</span>
|
|
<span class="ddr-stat__value">{{ valueOf('days') ? valueOf('days') + ' days' : '—' }}</span>
|
|
<span class="ddr-stat__hint">{{ valueOf('month') ? valueOf('month') + ' months' : '' }}</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>event</mat-icon>Opening Date</span>
|
|
<span class="ddr-stat__value">{{ valueOf('openingDate') || '—' }}</span>
|
|
<span class="ddr-stat__hint">{{
|
|
valueOf('maturityDate') ? 'Matures ' + valueOf('maturityDate') : 'account opens'
|
|
}}</span>
|
|
</div>
|
|
<div class="ddr-stat">
|
|
<span class="ddr-stat__label"><mat-icon>support_agent</mat-icon>Agent</span>
|
|
<span class="ddr-stat__value ddr-stat__value--small">{{ valueOf('agentId') || '—' }}</span>
|
|
<span class="ddr-stat__hint">{{ valueOf('officeId') || '' }}</span>
|
|
</div>
|
|
</section>
|
|
|
|
@for (group of fieldGroups; track group.name) {
|
|
<section class="ddr-section">
|
|
<header class="ddr-section__head">
|
|
<span class="ddr-section__icon"
|
|
><mat-icon>{{ group.icon }}</mat-icon></span
|
|
>
|
|
<span class="ddr-section__title">{{ group.name }}</span>
|
|
</header>
|
|
<div class="ddr-grid">
|
|
@for (field of group.fields; track field.key) {
|
|
<div class="ddr-tile">
|
|
<span class="ddr-tile__label">{{ field.label }}</span>
|
|
@if (field.format === 'yesno') {
|
|
<span class="ddr-pill" [class.ddr-pill--yes]="field.value === 'Yes'">
|
|
<mat-icon>{{ field.value === 'Yes' ? 'check_circle' : 'remove_circle_outline' }}</mat-icon>
|
|
{{ field.value }}
|
|
</span>
|
|
} @else {
|
|
<span class="ddr-tile__value">{{ field.value || '—' }}</span>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
}
|
|
|
|
<section class="ddr-section">
|
|
<header class="ddr-section__head">
|
|
<span class="ddr-section__icon"><mat-icon>family_restroom</mat-icon></span>
|
|
<span class="ddr-section__title">Nominees</span>
|
|
@if (detail?.nomineeSplit && nominees.length) {
|
|
<span class="ddr-chip ddr-chip--edit">Split by {{ detail.nomineeSplit }}</span>
|
|
}
|
|
<span class="ddr-chip ddr-chip--edit">{{ nominees.length }}</span>
|
|
</header>
|
|
@if (nominees.length) {
|
|
<table class="dri-cr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Name</th>
|
|
<th>Relation</th>
|
|
<th>Gender</th>
|
|
<th>Mobile</th>
|
|
<th>Birth Date</th>
|
|
<th>Guardian</th>
|
|
<th class="num">Share</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (n of nominees; track $index; let i = $index) {
|
|
<tr>
|
|
<td class="dri-cr-idx">{{ i + 1 }}</td>
|
|
<td>{{ n.name || '—' }}</td>
|
|
<td>{{ n.relation || '—' }}</td>
|
|
<td>{{ n.gender || '—' }}</td>
|
|
<td class="cell-mono">{{ n.mobileNo || '—' }}</td>
|
|
<td>{{ n.birthDate || '—' }}</td>
|
|
<td>{{ n.guardianName || '—' }}</td>
|
|
<td class="num">{{ n.share || '—' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
} @else {
|
|
<div class="ddr-tile">
|
|
<span class="ddr-tile__value">No nominee named in this request.</span>
|
|
</div>
|
|
}
|
|
</section>
|
|
} @else {
|
|
<!-- Header card: the voucher it moves under, its status, who made it and when -->
|
|
<div class="dri-card dri-card--header">
|
|
<div class="dri-card-header">
|
|
<div class="dri-card-header__left">
|
|
<!-- No voucher slot for a change that moves no money - it would only ever read "—". -->
|
|
@if (voucherNo || movesMoney) {
|
|
<span class="dri-voucher">{{ voucherNo || '—' }}</span>
|
|
}
|
|
<span class="dri-status" [ngClass]="statusClass(entry.status)">
|
|
{{ entry.status }}{{ entry.voucherCancelled ? ' · VOUCHER CANCELLED' : '' }}
|
|
</span>
|
|
</div>
|
|
<div class="dri-card-header__meta">
|
|
<span class="dri-meta-item">
|
|
<mat-icon>person</mat-icon>
|
|
{{ entry.makerName || entry.maker }} ({{ entry.maker }})
|
|
</span>
|
|
<span class="dri-meta-item">
|
|
<mat-icon>schedule</mat-icon>
|
|
{{ formatDateTime(entry.madeOn) }}
|
|
</span>
|
|
@if (entry.status !== 'PENDING' && entry.checker) {
|
|
<span class="dri-meta-item">
|
|
<mat-icon>check_circle</mat-icon>
|
|
Actioned by: {{ entry.checkerName || entry.checker }}
|
|
</span>
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary -->
|
|
<div class="dri-card">
|
|
<div class="dri-section-title">
|
|
<mat-icon>swap_horiz</mat-icon>
|
|
{{ entry.type }} Summary
|
|
</div>
|
|
<div class="dri-detail-grid">
|
|
<!-- Amount and sides only for an entry that moves money; a product or agent change has neither. -->
|
|
@if (movesMoney) {
|
|
<div class="dri-detail-item">
|
|
<span class="dri-detail-label">Total Amount</span>
|
|
<span class="dri-detail-value dri-amount">
|
|
{{
|
|
entry.amount !== null && entry.amount !== undefined ? '₹' + (entry.amount | number: '1.2-2') : '—'
|
|
}}
|
|
</span>
|
|
</div>
|
|
<div class="dri-detail-item">
|
|
<span class="dri-detail-label">DR Accounts</span>
|
|
<span class="dri-detail-value"
|
|
>{{ debitLines.length }} account{{ debitLines.length !== 1 ? 's' : '' }}</span
|
|
>
|
|
</div>
|
|
<div class="dri-detail-item">
|
|
<span class="dri-detail-label">CR Accounts</span>
|
|
<span class="dri-detail-value"
|
|
>{{ creditLines.length }} account{{ creditLines.length !== 1 ? 's' : '' }}</span
|
|
>
|
|
</div>
|
|
}
|
|
<div class="dri-detail-item dri-detail-item--full">
|
|
<span class="dri-detail-label">Details</span>
|
|
<span class="dri-detail-value">{{ entry.details || '—' }}</span>
|
|
</div>
|
|
@if (detail?.description) {
|
|
<div class="dri-detail-item dri-detail-item--full">
|
|
<span class="dri-detail-label">Description</span>
|
|
<span class="dri-detail-value">{{ detail.description }}</span>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
<!-- Debit entries -->
|
|
@if (debitLines.length) {
|
|
<div class="dri-card">
|
|
<div class="dri-section-title">
|
|
<mat-icon>arrow_upward</mat-icon>
|
|
Debit Entries ({{ debitLines.length }} account{{ debitLines.length !== 1 ? 's' : '' }} — funds out)
|
|
</div>
|
|
<table class="dri-cr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Account No</th>
|
|
<th>Account Name</th>
|
|
<th>Type</th>
|
|
<th class="num">Amount (DR)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (line of debitLines; track $index; let i = $index) {
|
|
<tr>
|
|
<td class="dri-cr-idx">{{ i + 1 }}</td>
|
|
<td class="cell-mono">{{ line.accountNo || '—' }}</td>
|
|
<td>{{ line.accountName || '—' }}</td>
|
|
<td>
|
|
<span class="dri-type-badge">{{ line.type || '—' }}</span>
|
|
</td>
|
|
<td class="num dri-cr-amount">₹{{ line.amount | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
<tr class="dri-cr-total-row">
|
|
<td colspan="4" class="dri-cr-total-label">Total Debit</td>
|
|
<td class="num dri-cr-total-amount">₹{{ total(debitLines) | number: '1.2-2' }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- Credit entries -->
|
|
@if (creditLines.length) {
|
|
<div class="dri-card">
|
|
<div class="dri-section-title">
|
|
<mat-icon>arrow_downward</mat-icon>
|
|
Credit Entries ({{ creditLines.length }} account{{ creditLines.length !== 1 ? 's' : '' }} — funds in)
|
|
</div>
|
|
<table class="dri-cr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Account No</th>
|
|
<th>Account Name</th>
|
|
<th>Type</th>
|
|
<th class="num">Amount (CR)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (line of creditLines; track $index; let i = $index) {
|
|
<tr>
|
|
<td class="dri-cr-idx">{{ i + 1 }}</td>
|
|
<td class="cell-mono">{{ line.accountNo || '—' }}</td>
|
|
<td>{{ line.accountName || '—' }}</td>
|
|
<td>
|
|
<span class="dri-type-badge">{{ line.type || '—' }}</span>
|
|
</td>
|
|
<td class="num dri-cr-amount">₹{{ line.amount | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
<tr class="dri-cr-total-row">
|
|
<td colspan="4" class="dri-cr-total-label">Total Credit</td>
|
|
<td class="num dri-cr-total-amount">₹{{ total(creditLines) | number: '1.2-2' }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
@if (entry.status === 'PENDING' && isMine && !done) {
|
|
<div class="dri-card dri-card--processing">
|
|
<div class="dri-section-title">
|
|
<mat-icon>info</mat-icon>
|
|
Your own entry
|
|
</div>
|
|
<p class="dri-processing-text">
|
|
You made this entry, so another user with checker rights has to approve or reject it.
|
|
</p>
|
|
</div>
|
|
}
|
|
|
|
@if (entry.status === 'REJECTED') {
|
|
<div class="dri-card dri-card--rejected">
|
|
<div class="dri-section-title">
|
|
<mat-icon>cancel</mat-icon>
|
|
Rejected
|
|
</div>
|
|
<p class="dri-rejection-text">
|
|
Nothing was done{{ voucherNo ? '. Voucher ' + voucherNo + ' is cancelled and will not be used' : '' }}.
|
|
</p>
|
|
@if (entry.checker) {
|
|
<div class="dri-meta-item" style="margin-top: 8px">
|
|
<mat-icon>manage_accounts</mat-icon>
|
|
{{ entry.checker }}
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
@if (entry.status === 'APPROVED') {
|
|
<div class="dri-card dri-card--approved">
|
|
<div class="dri-section-title">
|
|
<mat-icon>check_circle</mat-icon>
|
|
Approved and carried out
|
|
</div>
|
|
<p class="dri-txn-refs cell-mono">
|
|
{{
|
|
voucherNo
|
|
? 'Voucher ' + voucherNo
|
|
: entry.entity === 'DDSBATCH'
|
|
? 'Posting is running - refresh for its voucher'
|
|
: '—'
|
|
}}
|
|
</p>
|
|
<div class="dri-meta-item" style="margin-top: 8px">
|
|
<mat-icon>manage_accounts</mat-icon>
|
|
Approved by: {{ entry.checker || '—' }}
|
|
</div>
|
|
</div>
|
|
}
|
|
|
|
@if (error) {
|
|
<div class="dri-card dri-card--failed">
|
|
<div class="dri-section-title">
|
|
<mat-icon>error</mat-icon>
|
|
Could not complete
|
|
</div>
|
|
<p class="dri-rejection-text">{{ error }}</p>
|
|
</div>
|
|
}
|
|
|
|
@if (entry.status === 'PENDING' && !done) {
|
|
<div class="dri-actions" [class.ddr-actions]="isProductReview || isAgentReview || isPartyReview">
|
|
@if (!confirmReject) {
|
|
<button type="button" class="dri-btn dri-btn--approve" [disabled]="!canAct" (click)="act('approve')">
|
|
<mat-icon>check_circle</mat-icon>
|
|
{{ working ? 'Processing…' : 'Approve ' + entry.type }}
|
|
</button>
|
|
<button type="button" class="dri-btn dri-btn--reject" [disabled]="!canAct" (click)="confirmReject = true">
|
|
<mat-icon>cancel</mat-icon>
|
|
Reject
|
|
</button>
|
|
} @else {
|
|
<div class="dri-reject-form">
|
|
<label class="dri-reject-label">
|
|
Reject this entry? Nothing will be done{{
|
|
voucherNo ? ' and voucher ' + voucherNo + ' will be cancelled' : ''
|
|
}}.
|
|
</label>
|
|
<div class="dri-reject-actions">
|
|
<button type="button" class="dri-btn dri-btn--reject" [disabled]="!canAct" (click)="act('reject')">
|
|
<mat-icon>cancel</mat-icon>
|
|
{{ working ? 'Processing…' : 'Confirm Rejection' }}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="dri-btn dri-btn--ghost"
|
|
[disabled]="working"
|
|
(click)="confirmReject = false"
|
|
>
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|