diff --git a/src/app/investment/investment-reports/investment-reports.component.ts b/src/app/investment/investment-reports/investment-reports.component.ts
index 433b22a37..61c8ea240 100644
--- a/src/app/investment/investment-reports/investment-reports.component.ts
+++ b/src/app/investment/investment-reports/investment-reports.component.ts
@@ -8,6 +8,7 @@
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
import { RouterLink } from '@angular/router';
import { forkJoin, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
@@ -21,8 +22,11 @@ import {
todayDDMMYYYY
} from '../investment-data';
import { exportWorkbook, ExportSheetSpec } from '../investment-export';
+import { brokerNameOf, saveDealSlipPdf } from '../deal-slip-pdf';
+import { DateDdmmyyyyPickerComponent } from '../date-ddmmyyyy-picker/date-ddmmyyyy-picker.component';
import {
InvestmentDailyRateDto,
+ InvestmentDealSlipDto,
InvestmentFdDto,
InvestmentFdScheduleDto,
InvestmentInterestReportRowDto,
@@ -30,6 +34,7 @@ import {
InvestmentService,
apiErrorMessage,
bookValueSoldByPurchase,
+ confirmationModeLabel,
toFdHolding,
toFdTxns,
toHolding,
@@ -57,7 +62,9 @@ type ReportGroup = 'balance' | 'ledger' | 'maturity' | 'portfolio';
standalone: true,
imports: [
CommonModule,
- RouterLink
+ FormsModule,
+ RouterLink,
+ DateDdmmyyyyPickerComponent
]
})
export class InvestmentReportsComponent implements OnInit {
@@ -80,8 +87,17 @@ export class InvestmentReportsComponent implements OnInit {
/** Interest received in the financial year to the as-on date, per deal / FD (Interest Received & Receivable report). */
receivedRows: InvestmentInterestReportRowDto[] = [];
receivedFrom = '';
- /** Every purchase deal, pending ones included — the Deal Slip register (the ledgers hold only what reached the GL). */
- dealSlipTxns: InvestmentTxn[] = [];
+ /**
+ * Deal Slip Register: every purchase, sale, refund, redemption and switch dated in the period, cancelled ones
+ * included, in slip number order (loaded when the report is opened).
+ */
+ slips: InvestmentDealSlipDto[] = [];
+ slipFrom = '';
+ slipTo = todayDDMMYYYY();
+ slipLoading = false;
+ slipError = '';
+ /** Numbers missing between the first and last slip of each series in the period. */
+ slipGaps: string[] = [];
/** GOI category transfers (security shifted to another script / category). */
transfers: InvestmentSecurityTransferDto[] = [];
/** FD interest lines need one call per FD, so they load when a report needs them. */
@@ -128,7 +144,6 @@ export class InvestmentReportsComponent implements OnInit {
...r.transfers.map(toTransferTxn),
...r.fds.flatMap((f) => toFdTxns(f, []))
]);
- this.dealSlipTxns = this.byDateDesc(r.purchases.map(toPurchaseTxn));
// Received = coupons, FD payouts and FD interest paid at closure, as the interest report counts them.
this.receivedRows = r.interest.rows.filter((x) => x.received > 0);
this.receivedFrom = r.interest.fromDate;
@@ -211,6 +226,80 @@ export class InvestmentReportsComponent implements OnInit {
if (report === 'fdLedger') {
this.loadFdInterest();
}
+ if (report === 'dealSlip' && !this.slips.length && !this.slipLoading) {
+ this.loadDealSlips();
+ }
+ }
+
+ /** Deal Slip Register for the period (default: the financial year to date). */
+ loadDealSlips(): void {
+ if (!this.slipFrom) {
+ const d = parseDDMMYYYY(this.slipTo);
+ this.slipFrom = `01-04-${d.getMonth() >= 3 ? d.getFullYear() : d.getFullYear() - 1}`;
+ }
+ this.slipLoading = true;
+ this.slipError = '';
+ this.investmentService.getDealSlips(this.slipFrom, this.slipTo).subscribe({
+ next: (rows) => {
+ this.slips = rows;
+ this.slipGaps = this.findSlipGaps(rows);
+ this.slipLoading = false;
+ },
+ error: (err: unknown) => {
+ this.slips = [];
+ this.slipGaps = [];
+ this.slipLoading = false;
+ this.slipError = apiErrorMessage(err);
+ }
+ });
+ }
+
+ /**
+ * Missing numbers in each series (purchases 202627000001…, sales 202627S00001…) between the first and the last
+ * slip shown: every slip must be accounted for, cancelled ones included.
+ */
+ private findSlipGaps(rows: InvestmentDealSlipDto[]): string[] {
+ const series = new Map
();
+ for (const r of rows) {
+ const m = /^(\d{6}S?)(\d+)$/.exec(r.slipNo);
+ if (!m) {
+ continue;
+ }
+ const s = series.get(m[1]) ?? { width: m[2].length, nos: [] };
+ s.nos.push(Number(m[2]));
+ series.set(m[1], s);
+ }
+ const gaps: string[] = [];
+ series.forEach((s, prefix) => {
+ const nos = new Set(s.nos);
+ for (let n = Math.min(...s.nos) + 1; n < Math.max(...s.nos); n++) {
+ if (!nos.has(n)) {
+ gaps.push(prefix + String(n).padStart(s.width, '0'));
+ }
+ }
+ });
+ return gaps;
+ }
+
+ /** A deal settled without the counterparty's confirmation recorded (cancelled deals need none). */
+ confirmationAwaited(s: InvestmentDealSlipDto): boolean {
+ return s.status !== 'CANCELLED' && !s.confirmationReceivedOn && s.side !== 'REDEEM';
+ }
+
+ get slipsAwaited(): number {
+ return this.slips.filter((s) => this.confirmationAwaited(s)).length;
+ }
+
+ printSlip(s: InvestmentDealSlipDto): void {
+ saveDealSlipPdf(s);
+ }
+
+ confirmationLabel(mode?: string): string {
+ return confirmationModeLabel(mode);
+ }
+
+ brokerName(code?: string): string {
+ return brokerNameOf(code) ?? '';
}
instrumentLabel(type: InstrumentType): string {
@@ -298,9 +387,6 @@ export class InvestmentReportsComponent implements OnInit {
get amortizeTxns(): InvestmentTxn[] {
return this.txns.filter((t) => t.txnType === 'AMORTIZE');
}
- get dealSlips(): InvestmentTxn[] {
- return this.dealSlipTxns;
- }
get slrBondRegister(): InvestmentHolding[] {
return this.active('GOVT_SECURITY');
}
@@ -542,13 +628,90 @@ export class InvestmentReportsComponent implements OnInit {
this.amortizeTxns.map((t) => this.txnExportRow(t))
);
case 'dealSlip':
- return one(
- 'Deal Slip',
- 'Deal Slip Register',
- this.txnExportHeaders,
- this.txnExportWidths,
- this.dealSlips.map((t) => this.txnExportRow(t))
- );
+ return [
+ {
+ sheetName: 'Deal Slip Register',
+ title: 'Deal Slip Register',
+ subtitle:
+ `Deals dated ${this.slipFrom} to ${this.slipTo}` +
+ (this.slipGaps.length ? ` · missing numbers: ${this.slipGaps.join(', ')}` : ''),
+ headers: [
+ 'Slip No',
+ 'Type',
+ 'Status',
+ 'Deal Date',
+ 'Deal Time',
+ 'Settlement',
+ 'Counterparty',
+ 'Security',
+ 'ISIN',
+ 'Units',
+ 'Price',
+ 'Consideration',
+ 'Brokerage',
+ 'Net Amount',
+ 'Direct / Broker',
+ 'Broker',
+ 'Confirmation Sent By',
+ 'Confirmation Received',
+ 'Confirmation Ref',
+ 'Entered By',
+ 'Approved By',
+ 'Settled By',
+ 'Cancelled By'
+ ],
+ widths: [
+ 16,
+ 10,
+ 18,
+ 12,
+ 10,
+ 18,
+ 28,
+ 32,
+ 14,
+ 12,
+ 10,
+ 16,
+ 12,
+ 16,
+ 12,
+ 24,
+ 18,
+ 16,
+ 18,
+ 24,
+ 24,
+ 24,
+ 24
+ ],
+ rows: this.slips.map((s) => [
+ s.slipNo,
+ s.side,
+ s.status,
+ s.dealDate,
+ s.dealTime ?? '',
+ `${s.settlementType ?? ''} ${s.settlementDate}`.trim(),
+ s.counterparty ?? '',
+ `${s.scriptCode} ${s.scriptDesc}`,
+ s.isin ?? '',
+ s.units,
+ s.price ?? null,
+ s.consideration,
+ s.brokerage ?? 0,
+ s.netAmount,
+ s.dealMode === 'BROKER' ? 'Broker' : 'Direct',
+ s.brokerCode ? `${s.brokerCode} ${this.brokerName(s.brokerCode)}`.trim() : '',
+ this.confirmationLabel(s.confirmationMode),
+ s.confirmationReceivedOn ?? (this.confirmationAwaited(s) ? 'Awaited' : ''),
+ s.confirmationRef ?? '',
+ s.enteredBy ? `${s.enteredBy} ${s.enteredOn ?? ''}`.trim() : '',
+ s.approvedBy ? `${s.approvedBy} ${s.approvedOn ?? ''}`.trim() : '',
+ s.settledBy ? `${s.settledBy} ${s.settledOn ?? ''}`.trim() : '',
+ s.cancelledBy ? `${s.cancelledBy} ${s.cancelledOn ?? ''}`.trim() : ''
+ ])
+ }
+ ];
case 'intDueRegister':
return one(
'Interest Due Register',
diff --git a/src/app/investment/investment.service.ts b/src/app/investment/investment.service.ts
index 529bfea23..ae3c750ab 100644
--- a/src/app/investment/investment.service.ts
+++ b/src/app/investment/investment.service.ts
@@ -434,6 +434,11 @@ export interface InvestmentPurchaseDto {
crGlCode: string;
crGlName: string;
otherDetails?: string;
+ /** How the deal was confirmed to the counterparty (deal slip). */
+ confirmationMode?: ConfirmationMode;
+ /** When the counterparty's confirmation reached the back office, recorded on Settle. */
+ confirmationReceivedOn?: string;
+ confirmationRef?: string;
status: string;
glTransactionId?: string;
settledOnDate?: string;
@@ -517,9 +522,15 @@ export class InvestmentService {
return this.http.post<{ resourceId?: number; resourceIdentifier?: string }>('/investment/sales', body);
}
- /** Posts a pending sale on or after its settlement date; the voucher number comes back as resourceIdentifier. */
- settleSale(saleId: number): Observable<{ resourceIdentifier?: string }> {
- return this.http.post<{ resourceIdentifier?: string }>(`/investment/sales/${saleId}/settle`, {});
+ /**
+ * Posts a pending sale on or after its settlement date; the voucher number comes back as resourceIdentifier. The
+ * back office may record the counterparty's confirmation with it.
+ */
+ settleSale(saleId: number, confirmation: SettleConfirmation = {}): Observable<{ resourceIdentifier?: string }> {
+ return this.http.post<{ resourceIdentifier?: string }>(
+ `/investment/sales/${saleId}/settle`,
+ settleConfirmationBody(confirmation)
+ );
}
deleteSale(saleId: number): Observable {
@@ -636,14 +647,30 @@ export class InvestmentService {
return this.http.delete(`/investment/daily-rates/${rateId}`);
}
- /** Settles a deal: posts it to GL dated its settlement date. Under maker-checker the response only says it awaits approval. */
- settlePurchase(purchaseId: number): Observable<{ transactionId?: string; rollbackTransaction?: boolean }> {
+ /**
+ * Settles a deal: posts it to GL dated its settlement date. Under maker-checker the response only says it awaits
+ * approval. The back office may record the counterparty's confirmation with it.
+ */
+ settlePurchase(
+ purchaseId: number,
+ confirmation: SettleConfirmation = {}
+ ): Observable<{ transactionId?: string; rollbackTransaction?: boolean }> {
return this.http.post<{ transactionId?: string; rollbackTransaction?: boolean }>(
`/investment/purchases/${purchaseId}/settle`,
- {}
+ settleConfirmationBody(confirmation)
);
}
+ /** Deal slip register: deals dated fromDate to toDate (DD-MM-YYYY), cancelled ones included, in slip number order. */
+ getDealSlips(fromDate: string, toDate: string): Observable {
+ return this.http.get('/investment/deal-slips', { params: { fromDate, toDate } });
+ }
+
+ /** One deal slip by its number: a purchase deal number or a sale number. */
+ getDealSlip(slipNo: string): Observable {
+ return this.http.get('/investment/deal-slips', { params: { slipNo } });
+ }
+
/** RBI non-SLR limits for a purchase of `amount` (book value) in a script on a deal date (DD-MM-YYYY). */
getNonSlrLimit(scriptId: number | null, dealDate: string, amount: number): Observable {
const params: Record = { dealDate, amount: String(amount || 0) };
@@ -1182,6 +1209,8 @@ export interface InvestmentSaleDto {
id?: number;
purchaseId: number;
dealNo: string;
+ /** Deal slip number of the sale itself, e.g. 202627S00001 (none for a write-off or amortisation). */
+ saleNo?: string;
certNo: string;
bondType: string;
scriptCode: string;
@@ -1215,12 +1244,104 @@ export interface InvestmentSaleDto {
investmentGlCode: string;
sanctionAuthority?: string;
remarks?: string;
+ brokerCode?: string;
+ confirmationMode?: ConfirmationMode;
+ confirmationReceivedOn?: string;
+ confirmationRef?: string;
status: 'PENDING_SETTLEMENT' | 'SETTLED';
glTransactionId?: string;
voucherNo?: string;
settledOnDate?: string;
}
+/** How a deal was confirmed to the counterparty. */
+export type ConfirmationMode = 'EMAIL' | 'NDS_OM' | 'FAX' | 'LETTER' | 'PHONE';
+
+export const CONFIRMATION_MODES: Array<{ value: ConfirmationMode; label: string }> = [
+ { value: 'NDS_OM', label: 'NDS-OM / CCIL' },
+ { value: 'EMAIL', label: 'Email' },
+ { value: 'FAX', label: 'Fax' },
+ { value: 'LETTER', label: 'Letter' },
+ { value: 'PHONE', label: 'Phone (recorded line)' }
+];
+
+export function confirmationModeLabel(mode?: string | null): string {
+ return CONFIRMATION_MODES.find((m) => m.value === mode)?.label ?? mode ?? '';
+}
+
+/** The counterparty's confirmation the back office records when it settles a deal (both optional). */
+export interface SettleConfirmation {
+ /** DD-MM-YYYY. */
+ receivedOn?: string;
+ ref?: string;
+}
+
+function settleConfirmationBody(c: SettleConfirmation): Record {
+ const body: Record = {};
+ if (c.receivedOn) {
+ body['confirmationReceivedOn'] = c.receivedOn;
+ body['dateFormat'] = 'dd-MM-yyyy';
+ body['locale'] = 'en';
+ }
+ if (c.ref?.trim()) {
+ body['confirmationRef'] = c.ref.trim();
+ }
+ return body;
+}
+
+/** One deal slip: a purchase (BUY) or a sale / refund / redemption / switch, with who handled it. */
+export interface InvestmentDealSlipDto {
+ slipNo: string;
+ side: 'BUY' | 'SELL' | 'REFUND' | 'REDEEM' | 'SWITCH';
+ status: 'PENDING_SETTLEMENT' | 'SETTLED' | 'CANCELLED';
+ recordStatus: string;
+ purchaseId: number;
+ saleId?: number;
+ dealNo: string;
+ certNo?: string;
+ dealDate: string;
+ dealTime?: string;
+ settlementType?: string;
+ settlementDate: string;
+ partyCode?: string;
+ counterparty?: string;
+ bondType: string;
+ scriptCode: string;
+ scriptDesc: string;
+ isin?: string;
+ category?: string;
+ units: number;
+ faceValue: number;
+ price?: number;
+ consideration: number;
+ accruedInterest?: number;
+ brokerage?: number;
+ otherCharges?: number;
+ netAmount: number;
+ bankGlCode?: string;
+ bankGlName?: string;
+ dealMode: 'DIRECT' | 'BROKER';
+ brokerCode?: string;
+ tradeNo?: string;
+ orderNo?: string;
+ confirmationMode?: ConfirmationMode;
+ confirmationReceivedOn?: string;
+ confirmationRef?: string;
+ enteredBy?: string;
+ enteredOn?: string;
+ approvedBy?: string;
+ approvedOn?: string;
+ settledBy?: string;
+ settledOn?: string;
+ settleApprovedBy?: string;
+ settleApprovedOn?: string;
+ cancelledBy?: string;
+ cancelledOn?: string;
+ voucherNo?: string;
+ glTransactionId?: string;
+ remarks?: string;
+}
+
/** A market valuation (MTM) of AFS or HFT holdings: a preview (no id) or a posted run. */
export interface InvestmentValuationDto {
id?: number;
diff --git a/src/app/investment/share-investment/share-investment.component.html b/src/app/investment/share-investment/share-investment.component.html
index f2936fde7..16e5c8627 100644
--- a/src/app/investment/share-investment/share-investment.component.html
+++ b/src/app/investment/share-investment/share-investment.component.html
@@ -72,6 +72,36 @@
@if (activeTab === 'holdings') {
Share Holdings Register
+ @if (settleTarget?.kind === 'purchase') {
+
+ Settle {{ settleTarget?.label }} — confirmation from the institution (back office)
+
+
+
+
+
+
+ Record the institution's confirmation (share certificate / letter) if it has come; leave it blank otherwise
+ and the Deal Slip Register shows it as awaited.
+
+
+
+
+
+ }
@@ -113,8 +143,8 @@
@@ -127,6 +157,7 @@
Drop
}
+
} @empty {
@@ -219,6 +250,15 @@
+
@if (shareLimit; as l) {
@@ -415,6 +455,15 @@
+
@if (refundQuote; as q) {
@@ -448,10 +497,40 @@
Pending Refunds (posted on Settle)
+ @if (settleTarget?.kind === 'sale') {
+
+ Settle {{ settleTarget?.label }} — confirmation from the institution (back office)
+
+
+
+
+
+
+ Record the institution's confirmation (share certificate / letter) if it has come; leave it blank otherwise
+ and the Deal Slip Register shows it as awaited.
+
+
+
+
+
+ }
- | Deal No |
+ Sale No / Deal No |
Institution |
Shares |
Amount |
@@ -464,7 +543,10 @@
@for (s of pendingRefunds; track s.id) {
- {{ s.dealNo }}
+ {{ s.saleNo || s.dealNo }}
+ @if (s.saleNo) {
+ Deal {{ s.dealNo }}
+ }
|
{{ s.partyName }} |
{{ s.units | number: '1.0-0' }} |
@@ -479,8 +561,8 @@
@@ -492,6 +574,7 @@
>
Drop
+
} @empty {
diff --git a/src/app/investment/share-investment/share-investment.component.ts b/src/app/investment/share-investment/share-investment.component.ts
index 7e9404b31..5de6cd708 100644
--- a/src/app/investment/share-investment/share-investment.component.ts
+++ b/src/app/investment/share-investment/share-investment.component.ts
@@ -13,6 +13,7 @@ import { forkJoin } from 'rxjs';
import { DateDdmmyyyyPickerComponent } from '../date-ddmmyyyy-picker/date-ddmmyyyy-picker.component';
import { InvestmentTxn, SETTLEMENT_BANK_GL_OPTIONS, todayDDMMYYYY } from '../investment-data';
import { exportWorkbook } from '../investment-export';
+import { saveDealSlipPdf } from '../deal-slip-pdf';
import {
InvestmentDividendDto,
InvestmentPartyDto,
@@ -22,6 +23,8 @@ import {
InvestmentService,
InvestmentShareLimitDto,
SHARE_INSTITUTION_TYPES,
+ CONFIRMATION_MODES,
+ SettleConfirmation,
apiErrorMessage,
awaitingApproval,
sentForApproval,
@@ -42,6 +45,8 @@ interface SharePurchaseForm {
shares: number | null;
pricePerShare: number | null;
bankGlCode: string;
+ /** How the deal was confirmed to the institution (deal slip). */
+ confirmationMode: string;
}
interface ShareRefundForm {
@@ -51,6 +56,7 @@ interface ShareRefundForm {
pricePerShare: number | null;
bankGlCode: string;
remarks: string;
+ confirmationMode: string;
}
interface ShareDividendForm {
@@ -218,18 +224,68 @@ export class ShareInvestmentComponent implements OnInit {
return `inv-badge inv-badge--${status.toLowerCase()}`;
}
+ // -------------------- Settle with the institution's confirmation (back office) --------------------
+ /** The deal or refund the back office is settling, with the confirmation it records (both optional). */
+ settleTarget: { kind: 'purchase' | 'sale'; id: number; label: string } | null = null;
+ settleConfirmation: SettleConfirmation = {};
+ readonly confirmationModes = CONFIRMATION_MODES;
+
+ openPurchaseSettle(d: InvestmentPurchaseDto): void {
+ this.settleTarget = { kind: 'purchase', id: d.id, label: `deal ${d.dealNo}` };
+ this.settleConfirmation = {};
+ }
+
+ openRefundSettle(s: InvestmentSaleDto): void {
+ if (!s.id) {
+ return;
+ }
+ this.settleTarget = { kind: 'sale', id: s.id, label: `refund ${s.saleNo ?? ''} on deal ${s.dealNo}` };
+ this.settleConfirmation = {};
+ }
+
+ confirmSettle(): void {
+ const t = this.settleTarget;
+ if (!t) {
+ return;
+ }
+ if (t.kind === 'purchase') {
+ const d = this.deals.find((x) => x.id === t.id);
+ if (d) {
+ this.settleDeal(d, this.settleConfirmation);
+ }
+ } else {
+ const s = this.sales.find((x) => x.id === t.id);
+ if (s) {
+ this.settleRefund(s, this.settleConfirmation);
+ }
+ }
+ }
+
+ /** Downloads the deal slip (PDF) of a purchase deal number or a refund's sale number. */
+ printDealSlip(slipNo?: string): void {
+ if (!slipNo) {
+ this.toast('This deal has no deal slip number.');
+ return;
+ }
+ this.investmentService.getDealSlip(slipNo).subscribe({
+ next: (rows) => (rows.length ? saveDealSlipPdf(rows[0]) : this.toast(`Deal slip ${slipNo} not found.`)),
+ error: (err) => this.toast(apiErrorMessage(err))
+ });
+ }
+
/** The purchase being settled; its button stays disabled so it cannot be sent twice. */
settlingDealId: number | null = null;
/** Posts a pending deal to GL dated its settlement date: Dr 100706 Investment in Shares / Cr bank. */
- settleDeal(d: InvestmentPurchaseDto): void {
+ settleDeal(d: InvestmentPurchaseDto, confirmation: SettleConfirmation = {}): void {
if (this.settlingDealId !== null) {
return;
}
this.settlingDealId = d.id;
- this.investmentService.settlePurchase(d.id).subscribe({
+ this.investmentService.settlePurchase(d.id, confirmation).subscribe({
next: (res) => {
this.settlingDealId = null;
+ this.settleTarget = null;
this.toast(
awaitingApproval(res)
? sentForApproval(`Settlement of deal ${d.dealNo}`)
@@ -271,7 +327,8 @@ export class ShareInvestmentComponent implements OnInit {
settlementType: 'T+0',
shares: null,
pricePerShare: null,
- bankGlCode: SETTLEMENT_BANK_GL_OPTIONS[0].glCode
+ bankGlCode: SETTLEMENT_BANK_GL_OPTIONS[0].glCode,
+ confirmationMode: ''
};
}
@@ -386,6 +443,7 @@ export class ShareInvestmentComponent implements OnInit {
category: SHARE_CATEGORY,
crGlAccountId,
subType: '',
+ ...(f.confirmationMode ? { confirmationMode: f.confirmationMode } : {}),
dateFormat: 'dd-MM-yyyy',
locale: 'en'
};
@@ -474,7 +532,8 @@ export class ShareInvestmentComponent implements OnInit {
units: null,
pricePerShare: null,
bankGlCode: '',
- remarks: ''
+ remarks: '',
+ confirmationMode: ''
};
}
@@ -546,6 +605,7 @@ export class ShareInvestmentComponent implements OnInit {
saleRate: f.pricePerShare,
bankGlAccountId,
...(f.remarks.trim() ? { remarks: f.remarks.trim() } : {}),
+ ...(f.confirmationMode ? { confirmationMode: f.confirmationMode } : {}),
dateFormat: 'dd-MM-yyyy',
locale: 'en'
};
@@ -570,14 +630,15 @@ export class ShareInvestmentComponent implements OnInit {
/** The pending refund being settled or dropped; its buttons stay disabled so it cannot be sent twice. */
busySaleId: number | null = null;
- settleRefund(s: InvestmentSaleDto): void {
+ settleRefund(s: InvestmentSaleDto, confirmation: SettleConfirmation = {}): void {
if (!s.id || this.busySaleId !== null) {
return;
}
this.busySaleId = s.id;
- this.investmentService.settleSale(s.id).subscribe({
+ this.investmentService.settleSale(s.id, confirmation).subscribe({
next: (res) => {
this.busySaleId = null;
+ this.settleTarget = null;
this.toast(
awaitingApproval(res)
? sentForApproval(`Settlement of the refund on deal ${s.dealNo}`)