done
This commit is contained in:
@@ -14,6 +14,26 @@
|
||||
<button mat-flat-button color="primary" (click)="openAddInventoryDialog()">Register DD Series</button>
|
||||
</div>
|
||||
|
||||
<!-- Says why the clerk is here when they arrived from a dividend claim rather than from the menu.
|
||||
Without it, a page listing every DD series gives no clue which member is waiting at the
|
||||
counter or how much the draft has to be drawn for. -->
|
||||
@if (dividendContext) {
|
||||
<div class="dividend-banner">
|
||||
<div class="dividend-banner__text">
|
||||
<strong>Issuing a dividend Demand Draft</strong>
|
||||
<span>
|
||||
{{ dividendContext.beneficiary }} ·
|
||||
{{ dividendContext.amount | number: '1.2-2' }}
|
||||
@if (dividendContext.financialYear) {
|
||||
· FY {{ dividendContext.financialYear }}
|
||||
}
|
||||
</span>
|
||||
<span class="dividend-banner__hint">Open a series below and choose an available leaflet.</span>
|
||||
</div>
|
||||
<button mat-button class="action-btn" (click)="cancelDividendClaim()">Cancel</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
<mat-card>
|
||||
<table mat-table [dataSource]="dataSource">
|
||||
<!-- ID Column -->
|
||||
@@ -80,8 +100,15 @@
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef>Actions</th>
|
||||
<td mat-cell *matCellDef="let element">
|
||||
<button mat-button class="action-btn" [routerLink]="['/sponsor-dd/leaflets', element.id]">
|
||||
View Leaflets
|
||||
<!-- The dividend context travels on, so the leaflets page knows this is a dividend
|
||||
draft and not an ordinary counter sale. -->
|
||||
<button
|
||||
mat-button
|
||||
class="action-btn"
|
||||
[routerLink]="['/sponsor-dd/leaflets', element.id]"
|
||||
[queryParams]="dividendQueryParams"
|
||||
>
|
||||
{{ dividendContext ? 'Choose Leaflet' : 'View Leaflets' }}
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { Component, OnInit, inject } from '@angular/core';
|
||||
import { CommonModule, DatePipe } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@@ -103,6 +103,34 @@ import { SponsorDDService } from '../sponsor-dd.service';
|
||||
color: #b91c1c;
|
||||
font-weight: 600;
|
||||
}
|
||||
.dividend-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #c7d2fe;
|
||||
border-left: 4px solid #4f46e5;
|
||||
border-radius: 8px;
|
||||
background-color: #eef2ff;
|
||||
}
|
||||
.dividend-banner__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
font-size: 13px;
|
||||
color: #312e81;
|
||||
}
|
||||
.dividend-banner__text strong {
|
||||
font-size: 13.5px;
|
||||
}
|
||||
.dividend-banner__hint {
|
||||
color: #4338ca;
|
||||
font-size: 12px;
|
||||
}
|
||||
.dividend-banner button {
|
||||
margin-left: auto;
|
||||
}
|
||||
`
|
||||
]
|
||||
})
|
||||
@@ -110,6 +138,17 @@ export class DdInventoryListComponent implements OnInit {
|
||||
private sponsorDDService = inject(SponsorDDService);
|
||||
private dialog = inject(MatDialog);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
|
||||
/**
|
||||
* The dividend this visit is drawing a draft for, when the clerk arrived from a dividend claim
|
||||
* rather than from the menu.
|
||||
*
|
||||
* Null on an ordinary visit, which is what keeps this page's normal behaviour untouched — the
|
||||
* banner, the relabelled action and the forwarded query params all hang off this being set.
|
||||
*/
|
||||
dividendContext: { lockId: number; amount: number; beneficiary: string; financialYear: string } | null = null;
|
||||
|
||||
displayedColumns: string[] = [
|
||||
'id',
|
||||
@@ -126,9 +165,51 @@ export class DdInventoryListComponent implements OnInit {
|
||||
dataSource: any[] = [];
|
||||
|
||||
ngOnInit(): void {
|
||||
this.readDividendContext();
|
||||
this.loadInventories();
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks up the dividend a claim sent us here to pay out.
|
||||
*
|
||||
* Read from the URL rather than handed over in a service so a refreshed or bookmarked page still
|
||||
* knows which lock it is drawing against — losing it silently would issue an ordinary counter
|
||||
* draft against the member instead of settling their dividend.
|
||||
*/
|
||||
private readDividendContext(): void {
|
||||
const params = this.route.snapshot.queryParams;
|
||||
const lockId = Number(params['dividendLockId']);
|
||||
if (!lockId) {
|
||||
return;
|
||||
}
|
||||
this.dividendContext = {
|
||||
lockId,
|
||||
amount: Number(params['dividendAmount']) || 0,
|
||||
beneficiary: params['dividendBeneficiary'] ?? '',
|
||||
financialYear: params['dividendFinancialYear'] ?? ''
|
||||
};
|
||||
}
|
||||
|
||||
/** The dividend context to carry onto the leaflets page; empty on an ordinary visit. */
|
||||
get dividendQueryParams(): Record<string, string | number> {
|
||||
return this.dividendContext
|
||||
? {
|
||||
dividendLockId: this.dividendContext.lockId,
|
||||
dividendAmount: this.dividendContext.amount,
|
||||
dividendBeneficiary: this.dividendContext.beneficiary,
|
||||
dividendFinancialYear: this.dividendContext.financialYear
|
||||
}
|
||||
: {};
|
||||
}
|
||||
|
||||
/** Abandons the claim and returns to the dividend dashboard, leaving the lock untouched. */
|
||||
cancelDividendClaim(): void {
|
||||
this.router.navigate([
|
||||
'/clerk',
|
||||
'dividend-dashboard'
|
||||
]);
|
||||
}
|
||||
|
||||
loadInventories(): void {
|
||||
this.sponsorDDService.getInventories().subscribe({
|
||||
next: (data) => {
|
||||
|
||||
@@ -189,6 +189,12 @@ export class DdIssueApprovalsComponent implements OnInit, AfterViewInit {
|
||||
if (element.paymentMethod === 'CHEQUE') {
|
||||
return 'Cheque';
|
||||
}
|
||||
// Nothing is collected — the society already owes the member this money, so the draft is funded
|
||||
// from Dividend Payable. Named rather than left as "-" so a checker can see at a glance that no
|
||||
// purchaser will be debited when they approve it.
|
||||
if (element.paymentMethod === 'DIVIDEND') {
|
||||
return 'Dividend payout';
|
||||
}
|
||||
if (element.savingsAccountId) {
|
||||
return 'Savings';
|
||||
}
|
||||
|
||||
@@ -19,6 +19,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Says why the clerk is here when they arrived from a dividend claim, and which member is
|
||||
waiting. Without it a registry of DD numbers gives no clue what the next click commits to. -->
|
||||
<div class="dividend-banner" *ngIf="dividendContext">
|
||||
<div class="dividend-banner__text">
|
||||
<strong>Issuing a dividend Demand Draft</strong>
|
||||
<span>
|
||||
{{ dividendContext.beneficiary }} · {{ dividendContext.amount | number: '1.2-2' }}
|
||||
<ng-container *ngIf="dividendContext.financialYear"> · FY {{ dividendContext.financialYear }}</ng-container>
|
||||
</span>
|
||||
<span class="dividend-banner__hint">Pick an available leaflet below and press Issue.</span>
|
||||
</div>
|
||||
<button mat-button class="action-btn" (click)="cancelDividendClaim()">Cancel</button>
|
||||
</div>
|
||||
|
||||
<mat-form-field appearance="outline" class="search-field">
|
||||
<mat-label>Search by DD Leaflet No.</mat-label>
|
||||
<input matInput [value]="searchText" (input)="onSearchChange($event.target.value)" placeholder="e.g. 3005" />
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { Component, OnInit, AfterViewInit, ViewChild, inject } from '@angular/core';
|
||||
import { CommonModule, DatePipe } from '@angular/common';
|
||||
import { ActivatedRoute, RouterModule } from '@angular/router';
|
||||
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule, FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatTableModule, MatTableDataSource } from '@angular/material/table';
|
||||
@@ -25,6 +25,7 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { SponsorDDService } from '../sponsor-dd.service';
|
||||
import { DividendClaimRequestService } from '../../clerk/dividend-claim-request.service';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-dd-list',
|
||||
@@ -50,6 +51,31 @@ import { SponsorDDService } from '../sponsor-dd.service';
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.dividend-banner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #c7d2fe;
|
||||
border-left: 4px solid #4f46e5;
|
||||
border-radius: 8px;
|
||||
background-color: #eef2ff;
|
||||
}
|
||||
.dividend-banner__text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
font-size: 13px;
|
||||
color: #312e81;
|
||||
}
|
||||
.dividend-banner__hint {
|
||||
color: #4338ca;
|
||||
font-size: 12px;
|
||||
}
|
||||
.dividend-banner button {
|
||||
margin-left: auto;
|
||||
}
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -155,11 +181,18 @@ import { SponsorDDService } from '../sponsor-dd.service';
|
||||
export class DdListComponent implements OnInit, AfterViewInit {
|
||||
private sponsorDDService = inject(SponsorDDService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dialog = inject(MatDialog);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
|
||||
/**
|
||||
* The dividend this visit is drawing a draft for, when the clerk arrived from a dividend claim.
|
||||
* Null on an ordinary visit, which leaves every existing behaviour on this page untouched.
|
||||
*/
|
||||
dividendContext: { lockId: number; amount: number; beneficiary: string; financialYear: string } | null = null;
|
||||
|
||||
inventoryId!: number;
|
||||
inventoryDetails: any = null;
|
||||
displayedColumns: string[] = [
|
||||
@@ -194,6 +227,7 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.inventoryId = +this.route.snapshot.params['inventoryId'];
|
||||
this.readDividendContext();
|
||||
this.dataSource.filterPredicate = (data) => {
|
||||
const statusMatches = this.selectedStatus === 'ALL' || data.status === this.selectedStatus;
|
||||
const searchMatches =
|
||||
@@ -207,6 +241,38 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
this.loadLeaflets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks up the dividend a claim sent the clerk here to pay out, and shows the leaflets they can
|
||||
* actually use for it.
|
||||
*
|
||||
* The page normally opens on today's issued drafts, which is the right view for reconciling but
|
||||
* exactly the wrong one here — a clerk sent to pick a blank leaflet would land on a list with
|
||||
* none in it. Dividend mode opens on AVAILABLE instead.
|
||||
*/
|
||||
private readDividendContext(): void {
|
||||
const params = this.route.snapshot.queryParams;
|
||||
const lockId = Number(params['dividendLockId']);
|
||||
if (!lockId) {
|
||||
return;
|
||||
}
|
||||
this.dividendContext = {
|
||||
lockId,
|
||||
amount: Number(params['dividendAmount']) || 0,
|
||||
beneficiary: params['dividendBeneficiary'] ?? '',
|
||||
financialYear: params['dividendFinancialYear'] ?? ''
|
||||
};
|
||||
this.selectedStatus = 'AVAILABLE';
|
||||
this.todayOnly = false;
|
||||
}
|
||||
|
||||
/** Abandons the claim and returns to the dividend dashboard, leaving the lock untouched. */
|
||||
cancelDividendClaim(): void {
|
||||
this.router.navigate([
|
||||
'/clerk',
|
||||
'dividend-dashboard'
|
||||
]);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dataSource.paginator = this.paginator;
|
||||
}
|
||||
@@ -276,12 +342,25 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
openIssueDialog(leaflet: any): void {
|
||||
const dialogRef = this.dialog.open(IssueDraftDialogComponent, {
|
||||
width: '560px',
|
||||
data: { leaflet, inventoryId: this.inventoryId },
|
||||
// The dividend, when the clerk came here from a claim. Passing it through puts the dialog in
|
||||
// dividend mode: beneficiary and amount arrive filled in, there is no payment to collect
|
||||
// because the society already owes the money, and submitting files the claim rather than an
|
||||
// ordinary issue request.
|
||||
data: { leaflet, inventoryId: this.inventoryId, dividend: this.dividendContext },
|
||||
disableClose: true
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((result) => {
|
||||
if (result) {
|
||||
// A dividend claim is finished the moment it is filed — the draft is drawn on approval, and
|
||||
// there is nothing further for the clerk to do on this page.
|
||||
if (this.dividendContext) {
|
||||
this.router.navigate([
|
||||
'/clerk',
|
||||
'dividend-dashboard'
|
||||
]);
|
||||
return;
|
||||
}
|
||||
this.loadLeaflets();
|
||||
}
|
||||
});
|
||||
@@ -366,14 +445,35 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
],
|
||||
providers: [DatePipe],
|
||||
template: `
|
||||
<h2 mat-dialog-title>Issue Demand Draft (DD No: {{ data.leaflet.ddNumber }})</h2>
|
||||
<h2 mat-dialog-title>
|
||||
{{ dividend ? 'Pay Dividend by Demand Draft' : 'Issue Demand Draft' }} (DD No:
|
||||
{{ data.leaflet.ddNumber }})
|
||||
</h2>
|
||||
<mat-dialog-content>
|
||||
<p class="hint-text">
|
||||
This submits a request to a Bank Manager / Head Cashier for approval. Money only moves (client debited, Sponsor
|
||||
DD Payable GL credited) once the request is approved.
|
||||
</p>
|
||||
<!-- A dividend draft is not a counter sale: the society already owes the member the money, so
|
||||
there is nothing to collect and the beneficiary and amount are fixed by the entitlement.
|
||||
The clerk is left with only the branch and city to fill in. -->
|
||||
<ng-container *ngIf="dividend; else counterSaleHint">
|
||||
<div class="dividend-callout">
|
||||
<strong>Settling a dividend</strong>
|
||||
<span>
|
||||
{{ dividend.beneficiary }} · {{ dividend.amount | number: '1.2-2' }}
|
||||
<ng-container *ngIf="dividend.financialYear"> · FY {{ dividend.financialYear }}</ng-container>
|
||||
</span>
|
||||
<span class="dividend-callout__hint">
|
||||
Funded from Dividend Payable — no charge, no GST, nothing collected from the member. The draft is drawn
|
||||
once a manager approves the claim.
|
||||
</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #counterSaleHint>
|
||||
<p class="hint-text">
|
||||
This submits a request to a Bank Manager / Head Cashier for approval. Money only moves (client debited,
|
||||
Sponsor DD Payable GL credited) once the request is approved.
|
||||
</p>
|
||||
</ng-template>
|
||||
<form [formGroup]="issueForm" class="dialog-form">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-form-field appearance="outline" class="full-width" *ngIf="!dividend">
|
||||
<mat-label>How is the customer paying?</mat-label>
|
||||
<mat-select formControlName="paymentMethod">
|
||||
<mat-option value="ACCOUNT_DEBIT">Debit from their Savings/Current Account</mat-option>
|
||||
@@ -382,7 +482,7 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<ng-container *ngIf="issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT'">
|
||||
<ng-container *ngIf="!dividend && issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT'">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Account Type</mat-label>
|
||||
<mat-select formControlName="accountType">
|
||||
@@ -410,7 +510,7 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
</p>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="issueForm.get('paymentMethod')?.value === 'CHEQUE'">
|
||||
<ng-container *ngIf="!dividend && issueForm.get('paymentMethod')?.value === 'CHEQUE'">
|
||||
<div class="row">
|
||||
<mat-form-field appearance="outline" class="half-width">
|
||||
<mat-label>Cheque Number</mat-label>
|
||||
@@ -426,7 +526,7 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="issueForm.get('paymentMethod')?.value === 'CASH'">
|
||||
<ng-container *ngIf="!dividend && issueForm.get('paymentMethod')?.value === 'CASH'">
|
||||
<p class="hint-text">
|
||||
Walk-in purchaser paying cash — need not be an existing bank customer. Record their details for the DD
|
||||
record; the Aadhaar number is masked before it is stored.
|
||||
@@ -501,7 +601,7 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
<mat-form-field
|
||||
appearance="outline"
|
||||
class="full-width"
|
||||
*ngIf="issueForm.get('paymentMethod')?.value !== 'CASH'"
|
||||
*ngIf="!dividend && issueForm.get('paymentMethod')?.value !== 'CASH'"
|
||||
>
|
||||
<mat-label>Client (Customer) ID</mat-label>
|
||||
<input matInput type="number" formControlName="clientId" />
|
||||
@@ -537,13 +637,14 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>DD Face Value (₹)</mat-label>
|
||||
<input matInput type="number" formControlName="faceValue" />
|
||||
<mat-hint *ngIf="issueForm.get('faceValue')?.disabled">
|
||||
<mat-hint *ngIf="dividend">Locked — the member's unclaimed dividend for this lock.</mat-hint>
|
||||
<mat-hint *ngIf="!dividend && issueForm.get('faceValue')?.disabled">
|
||||
Locked — from the DD Charges & GST breakdown entered at Transaction Entry.
|
||||
</mat-hint>
|
||||
<mat-error *ngIf="issueForm.get('faceValue')?.hasError('required')">Face Value is required</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-form-field appearance="outline" class="full-width" *ngIf="!dividend">
|
||||
<mat-label>Charges / Commission (₹)</mat-label>
|
||||
<input matInput type="number" formControlName="chargesAmount" />
|
||||
<mat-hint *ngIf="issueForm.get('chargesAmount')?.disabled">
|
||||
@@ -560,8 +661,8 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
|
||||
<ng-container
|
||||
*ngIf="
|
||||
issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT' ||
|
||||
issueForm.get('paymentMethod')?.value === 'CHEQUE'
|
||||
!dividend && (issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT' ||
|
||||
issueForm.get('paymentMethod')?.value === 'CHEQUE')
|
||||
"
|
||||
>
|
||||
<p class="hint-text" *ngIf="additionalLinesArray.length > 0">
|
||||
@@ -638,16 +739,35 @@ export class DdListComponent implements OnInit, AfterViewInit {
|
||||
[disabled]="
|
||||
issueForm.invalid ||
|
||||
loading ||
|
||||
(issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT' && accountLookupState !== 'found')
|
||||
(!dividend && issueForm.get('paymentMethod')?.value === 'ACCOUNT_DEBIT' && accountLookupState !== 'found')
|
||||
"
|
||||
(click)="onSubmit()"
|
||||
>
|
||||
Submit for Approval
|
||||
{{ dividend ? 'Submit Claim Request' : 'Submit for Approval' }}
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
`,
|
||||
styles: [
|
||||
`
|
||||
.dividend-callout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid #c7d2fe;
|
||||
border-left: 4px solid #4f46e5;
|
||||
border-radius: 8px;
|
||||
background-color: #eef2ff;
|
||||
font-size: 13px;
|
||||
color: #312e81;
|
||||
}
|
||||
.dividend-callout__hint {
|
||||
margin-top: 4px;
|
||||
color: #4338ca;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.dialog-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -702,6 +822,7 @@ export class IssueDraftDialogComponent implements OnInit {
|
||||
private dialogRef = inject(MatDialogRef<IssueDraftDialogComponent>);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private dialog = inject(MatDialog);
|
||||
private claimRequestService = inject(DividendClaimRequestService);
|
||||
protected data = inject(MAT_DIALOG_DATA);
|
||||
|
||||
issueForm!: FormGroup;
|
||||
@@ -718,6 +839,53 @@ export class IssueDraftDialogComponent implements OnInit {
|
||||
ddLimitAmount: number | null = null;
|
||||
availableCashierDeposits: any[] = [];
|
||||
|
||||
/**
|
||||
* The dividend this draft settles, when the dialog was opened from a dividend claim.
|
||||
*
|
||||
* A dividend draft is not a counter sale: the society already owes the member the money, so
|
||||
* there is no purchaser to debit, no charge and no GST. The beneficiary and the amount are fixed
|
||||
* by the entitlement itself, which leaves the clerk only the branch and city to fill in.
|
||||
*/
|
||||
get dividend(): { lockId: number; amount: number; beneficiary: string; financialYear: string } | null {
|
||||
return this.data?.dividend ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks the form to what the dividend already decided and drops everything a counter sale needs.
|
||||
*
|
||||
* The payment-method controls are cleared of their validators rather than left required-and-empty
|
||||
* — the form would otherwise never become valid and the clerk would be staring at a dead Submit
|
||||
* button with no field to fix.
|
||||
*/
|
||||
private applyDividendMode(): void {
|
||||
const dividend = this.dividend;
|
||||
if (!dividend) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.issueForm.patchValue({
|
||||
beneficiaryName: dividend.beneficiary,
|
||||
faceValue: dividend.amount,
|
||||
chargesAmount: 0
|
||||
});
|
||||
|
||||
// Fixed by the entitlement — a clerk cannot pay a different member, or a different amount, than
|
||||
// the dividend the claim was raised against.
|
||||
this.issueForm.get('beneficiaryName')?.disable();
|
||||
this.issueForm.get('faceValue')?.disable();
|
||||
|
||||
for (const name of [
|
||||
'clientId',
|
||||
'accountNumber',
|
||||
'paymentMethod',
|
||||
'chargesAmount'
|
||||
]) {
|
||||
const control = this.issueForm.get(name);
|
||||
control?.clearValidators();
|
||||
control?.updateValueAndValidity();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.sponsorDDService.getGlMappings().subscribe({
|
||||
next: (mappings) => {
|
||||
@@ -787,6 +955,8 @@ export class IssueDraftDialogComponent implements OnInit {
|
||||
additionalLines: this.fb.array([])
|
||||
});
|
||||
|
||||
this.applyDividendMode();
|
||||
|
||||
this.forceUppercase([
|
||||
'beneficiaryName',
|
||||
'payableAtBranch',
|
||||
@@ -964,9 +1134,53 @@ export class IssueDraftDialogComponent implements OnInit {
|
||||
this.dialogRef.close(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Files the dividend claim rather than an ordinary issue request.
|
||||
*
|
||||
* The draft itself is drawn when a manager approves the claim — that approval already is the
|
||||
* check on this money, so routing it through the DD maker-checker as well would put a member's
|
||||
* own dividend behind two separate approvals for no added control.
|
||||
*/
|
||||
private submitDividendClaim(): void {
|
||||
const dividend = this.dividend!;
|
||||
const formVal = this.issueForm.getRawValue();
|
||||
|
||||
this.loading = true;
|
||||
this.claimRequestService
|
||||
.submit(dividend.lockId, {
|
||||
ddApplyAmount: Number(formVal.faceValue),
|
||||
ddBeneficiaryName: formVal.beneficiaryName,
|
||||
ddPayableAtBranch: formVal.payableAtBranch,
|
||||
ddPayableAtCity: formVal.payableAtCity,
|
||||
// The leaflet the clerk actually opened this dialog on. The draft has to be drawn on the
|
||||
// physical form in their hand, not on whichever one the server would pick next.
|
||||
leafletId: this.data?.leaflet?.id
|
||||
})
|
||||
.subscribe({
|
||||
next: (res: any) => {
|
||||
const ddNumber = res?.ddNumber ? ` DD No ${res.ddNumber}.` : '';
|
||||
this.snackBar.open(
|
||||
`Dividend draft submitted for approval.${ddNumber} It now appears under DD Issuance Approvals.`,
|
||||
'Close',
|
||||
{ duration: 6000 }
|
||||
);
|
||||
this.dialogRef.close(true);
|
||||
},
|
||||
error: (err) => {
|
||||
this.loading = false;
|
||||
this.snackBar.open('Error: ' + (err.error?.message || err.message), 'Close', { duration: 5000 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.issueForm.invalid) return;
|
||||
|
||||
if (this.dividend) {
|
||||
this.submitDividendClaim();
|
||||
return;
|
||||
}
|
||||
|
||||
const formVal = this.issueForm.getRawValue();
|
||||
if (formVal.paymentMethod === 'ACCOUNT_DEBIT' && this.accountLookupState !== 'found') {
|
||||
this.snackBar.open(
|
||||
|
||||
Reference in New Issue
Block a user