feat(investment): show sent-for-approval message on investment actions
This commit is contained in:
@@ -75,6 +75,8 @@ import {
|
||||
InvestmentValuationDto,
|
||||
NON_SLR_TYPES,
|
||||
apiErrorMessage,
|
||||
awaitingApproval,
|
||||
sentForApproval,
|
||||
toHolding,
|
||||
toInterestTxn,
|
||||
toPurchaseTxn,
|
||||
@@ -1003,7 +1005,9 @@ export class BondInvestmentComponent implements OnInit {
|
||||
this.investmentService.createPurchase(body).subscribe({
|
||||
next: (res) => {
|
||||
this.toast(
|
||||
`Deal ${res.resourceIdentifier} saved — pending settlement. Settle it from Holdings on or after the settlement date.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval('Purchase deal')
|
||||
: `Deal ${res.resourceIdentifier} saved — pending settlement. Settle it from Holdings on or after the settlement date.`
|
||||
);
|
||||
this.activeTab = 'holdings';
|
||||
this.loadPurchases();
|
||||
@@ -1116,8 +1120,8 @@ export class BondInvestmentComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.settlingDealId = null;
|
||||
this.toast(
|
||||
res.rollbackTransaction
|
||||
? `Settlement of deal ${h.dealNo} sent for approval (Checker Inbox).`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Settlement of deal ${h.dealNo}`)
|
||||
: `Deal ${h.dealNo} settled and posted to GL (transaction ${res.transactionId}).`
|
||||
);
|
||||
this.loadPurchases();
|
||||
@@ -1136,8 +1140,12 @@ export class BondInvestmentComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
this.investmentService.deletePurchase(h.id).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Deal ${h.dealNo} (Cert No ${h.certNo}) dropped.`);
|
||||
next: (res) => {
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Drop of deal ${h.dealNo}`)
|
||||
: `Deal ${h.dealNo} (Cert No ${h.certNo}) dropped.`
|
||||
);
|
||||
this.loadPurchases();
|
||||
},
|
||||
error: (err) => this.toast(apiErrorMessage(err))
|
||||
@@ -1211,7 +1219,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
.subscribe({
|
||||
next: (res) => {
|
||||
this.redeeming = false;
|
||||
this.toast(`Deal ${q.dealNo} redeemed — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Redemption of deal ${q.dealNo}`)
|
||||
: `Deal ${q.dealNo} redeemed — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.redeemPurchaseId = null;
|
||||
this.redeemQuote = null;
|
||||
this.redeemRemarks = '';
|
||||
@@ -1315,8 +1327,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
this.investmentService.postInterest(sc.purchaseId, body).subscribe({
|
||||
next: (res) => {
|
||||
this.intPosting = false;
|
||||
const line = `${r.type === 'COUPON' ? 'Coupon' : 'Provision'} of ${r.intDate}`;
|
||||
this.toast(
|
||||
`${r.type === 'COUPON' ? 'Coupon' : 'Provision'} of ${r.intDate} posted — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`${line} voucher`)
|
||||
: `${line} posted — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.retrieveInterestSchedule();
|
||||
this.loadDueInterest();
|
||||
@@ -1450,9 +1465,13 @@ export class BondInvestmentComponent implements OnInit {
|
||||
};
|
||||
this.savingSale = true;
|
||||
this.investmentService.createSale(body).subscribe({
|
||||
next: () => {
|
||||
next: (res) => {
|
||||
this.savingSale = false;
|
||||
this.toast(`Sale saved — settle it on ${this.saleQuote?.settlementDate ?? 'the settlement date'} to post it.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval('Sale')
|
||||
: `Sale saved — settle it on ${this.saleQuote?.settlementDate ?? 'the settlement date'} to post it.`
|
||||
);
|
||||
this.sale = this.blankSale();
|
||||
this.saleQuote = null;
|
||||
this.loadInterestLog();
|
||||
@@ -1475,6 +1494,10 @@ export class BondInvestmentComponent implements OnInit {
|
||||
this.investmentService.settleSale(s.id).subscribe({
|
||||
next: (res) => {
|
||||
this.busySaleId = null;
|
||||
if (awaitingApproval(res)) {
|
||||
this.toast(sentForApproval(`Settlement of the sale of deal ${s.dealNo}`));
|
||||
return;
|
||||
}
|
||||
this.sales = this.sales.filter((x) => x.id !== s.id);
|
||||
this.toast(`Sale of deal ${s.dealNo} settled — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.loadPurchases();
|
||||
@@ -1492,8 +1515,12 @@ export class BondInvestmentComponent implements OnInit {
|
||||
}
|
||||
this.busySaleId = s.id;
|
||||
this.investmentService.deleteSale(s.id).subscribe({
|
||||
next: () => {
|
||||
next: (res) => {
|
||||
this.busySaleId = null;
|
||||
if (awaitingApproval(res)) {
|
||||
this.toast(sentForApproval(`Drop of the pending sale of deal ${s.dealNo}`));
|
||||
return;
|
||||
}
|
||||
this.sales = this.sales.filter((x) => x.id !== s.id);
|
||||
this.toast(`Pending sale of deal ${s.dealNo} dropped.`);
|
||||
this.loadInterestLog();
|
||||
@@ -1549,7 +1576,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
this.investmentService.writeOff(h.id, { amount, remarks: this.writeoffReason.trim(), locale: 'en' }).subscribe({
|
||||
next: (res) => {
|
||||
this.writingOff = false;
|
||||
this.toast(`Deal ${h.dealNo}: ₹${amount} written off — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Write-off of ₹${amount} on deal ${h.dealNo}`)
|
||||
: `Deal ${h.dealNo}: ₹${amount} written off — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.writeoffPurchaseId = null;
|
||||
this.writeoffAmount = null;
|
||||
this.writeoffReason = '';
|
||||
@@ -1594,7 +1625,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
.subscribe({
|
||||
next: (res) => {
|
||||
this.amortizing = false;
|
||||
this.toast(`Deal ${d.dealNo}: premium amortised for ${fyEnd} — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Premium amortisation of deal ${d.dealNo} for ${fyEnd}`)
|
||||
: `Deal ${d.dealNo}: premium amortised for ${fyEnd} — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.onAmortizeDealChange();
|
||||
this.loadPurchases();
|
||||
},
|
||||
@@ -1645,7 +1680,9 @@ export class BondInvestmentComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.amortizing = false;
|
||||
this.toast(
|
||||
`Amortisation for ${this.amortizeFyEnd} posted for ${this.amortizeDue.length} holding(s) — vouchers ${res.resourceIdentifier ?? ''}.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Amortisation for ${this.amortizeFyEnd} (${this.amortizeDue.length} holding(s))`)
|
||||
: `Amortisation for ${this.amortizeFyEnd} posted for ${this.amortizeDue.length} holding(s) — vouchers ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.loadAmortizeDue();
|
||||
this.loadPurchases();
|
||||
@@ -1721,7 +1758,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
.subscribe({
|
||||
next: (res) => {
|
||||
this.goiSaving = false;
|
||||
this.toast(`Deal ${h.dealNo} transferred to ${to.scriptCode} — ${res.resourceIdentifier ?? ''}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Transfer of deal ${h.dealNo} to ${to.scriptCode}`)
|
||||
: `Deal ${h.dealNo} transferred to ${to.scriptCode} — ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.goiPurchaseId = null;
|
||||
this.goiToScriptCode = '';
|
||||
this.goiRemarks = '';
|
||||
@@ -1794,9 +1835,11 @@ export class BondInvestmentComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.valuationPosting = false;
|
||||
this.toast(
|
||||
v.delta === 0
|
||||
? `Valuation of ${v.valuationDate} recorded; the IDR needed is unchanged, so no voucher.`
|
||||
: `Valuation of ${v.valuationDate} posted — ${res.resourceIdentifier ?? ''}.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`${v.category} valuation of ${v.valuationDate}`)
|
||||
: v.delta === 0
|
||||
? `Valuation of ${v.valuationDate} recorded; the IDR needed is unchanged, so no voucher.`
|
||||
: `Valuation of ${v.valuationDate} posted — ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.valuationPreview = null;
|
||||
this.loadValuationRuns();
|
||||
@@ -1956,7 +1999,9 @@ export class BondInvestmentComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.mfSwitchSaving = false;
|
||||
this.toast(
|
||||
`Switched ${this.mfSwitchUnits} units of deal ${h.dealNo} into ${to.scriptCode} — new deal ${res.resourceIdentifier ?? ''}.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Switch of ${this.mfSwitchUnits} units of deal ${h.dealNo} into ${to.scriptCode}`)
|
||||
: `Switched ${this.mfSwitchUnits} units of deal ${h.dealNo} into ${to.scriptCode} — new deal ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.mfSwitchPurchaseId = null;
|
||||
this.mfSwitchUnits = null;
|
||||
|
||||
@@ -23,7 +23,9 @@ import {
|
||||
InvestmentGlAccount,
|
||||
InvestmentPartyDto,
|
||||
InvestmentService,
|
||||
apiErrorMessage
|
||||
apiErrorMessage,
|
||||
awaitingApproval,
|
||||
sentForApproval
|
||||
} from '../investment.service';
|
||||
|
||||
type FdTab = 'holdings' | 'purchase' | 'closure' | 'interest';
|
||||
@@ -266,9 +268,13 @@ export class FdInvestmentComponent implements OnInit {
|
||||
this.investmentService
|
||||
.setDepositBase({ asOnDate: asOn, totalDeposits: this.baseAmount, locale: 'en', dateFormat: 'dd-MM-yyyy' })
|
||||
.subscribe({
|
||||
next: () => {
|
||||
next: (res) => {
|
||||
this.savingBase = false;
|
||||
this.toast(`Total deposits as on ${asOn} saved.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`Total deposits as on ${asOn}`)
|
||||
: `Total deposits as on ${asOn} saved.`
|
||||
);
|
||||
this.refreshQuote();
|
||||
},
|
||||
error: (err) => {
|
||||
@@ -319,7 +325,9 @@ export class FdInvestmentComponent implements OnInit {
|
||||
next: (res) => {
|
||||
this.saving = false;
|
||||
this.toast(
|
||||
`FD ${res.changes?.dealNo ?? ''} placed — voucher ${res.changes?.voucherNo ?? res.resourceIdentifier ?? ''}.`
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`FD of ₹${f.amount} with certificate ${f.certNo.trim()}`)
|
||||
: `FD ${res.changes?.dealNo ?? ''} placed — voucher ${res.changes?.voucherNo ?? res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.form = this.blankForm();
|
||||
this.quote = null;
|
||||
@@ -394,7 +402,11 @@ export class FdInvestmentComponent implements OnInit {
|
||||
this.investmentService.postFdInterest(fdId, body).subscribe({
|
||||
next: (res) => {
|
||||
this.postingInterest = false;
|
||||
this.toast(`${this.lineLabel(r.lineType)} of ${r.intDate} posted — voucher ${res.resourceIdentifier ?? ''}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`${this.lineLabel(r.lineType)} of ${r.intDate} voucher`)
|
||||
: `${this.lineLabel(r.lineType)} of ${r.intDate} posted — voucher ${res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.loadSchedule();
|
||||
},
|
||||
error: (err) => {
|
||||
@@ -552,7 +564,12 @@ export class FdInvestmentComponent implements OnInit {
|
||||
: c.type === 'PREMATURE'
|
||||
? 'closed'
|
||||
: 'matured';
|
||||
this.toast(`FD ${f.dealNo} ${what} — voucher ${res.changes?.voucherNo ?? res.resourceIdentifier ?? ''}.`);
|
||||
const action = c.type === 'RENEWAL' ? 'Renewal' : c.type === 'PREMATURE' ? 'Premature closure' : 'Maturity';
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(`${action} of FD ${f.dealNo}`)
|
||||
: `FD ${f.dealNo} ${what} — voucher ${res.changes?.voucherNo ?? res.resourceIdentifier ?? ''}.`
|
||||
);
|
||||
this.closure = this.blankClosure();
|
||||
this.closureQuote = null;
|
||||
this.loadFds();
|
||||
|
||||
@@ -40,7 +40,14 @@ import {
|
||||
periodBetween
|
||||
} from '../investment-data';
|
||||
import { exportWorkbook, ExportSheetSpec } from '../investment-export';
|
||||
import { InvestmentGlAccount, InvestmentService, apiErrorMessage, toDailyScriptRate } from '../investment.service';
|
||||
import {
|
||||
InvestmentGlAccount,
|
||||
InvestmentService,
|
||||
apiErrorMessage,
|
||||
awaitingApproval,
|
||||
sentForApproval,
|
||||
toDailyScriptRate
|
||||
} from '../investment.service';
|
||||
|
||||
type MasterTab =
|
||||
| 'party'
|
||||
@@ -250,7 +257,11 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
request.subscribe({
|
||||
next: (res) => {
|
||||
this.saving = false;
|
||||
this.toast(`Party ${res.resourceIdentifier ?? f.partyCode} ${f.id ? 'updated' : 'saved'}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(f.id ? `Change to party ${f.partyCode}` : `New party ${f.partyName ?? ''}`)
|
||||
: `Party ${res.resourceIdentifier ?? f.partyCode} ${f.id ? 'updated' : 'saved'}.`
|
||||
);
|
||||
this.partyForm = {};
|
||||
this.reloadMasters();
|
||||
},
|
||||
@@ -283,8 +294,10 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
this.investmentService.deleteParty(f.id).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Party ${f.partyCode} dropped.`);
|
||||
next: (res) => {
|
||||
this.toast(
|
||||
awaitingApproval(res) ? sentForApproval(`Drop of party ${f.partyCode}`) : `Party ${f.partyCode} dropped.`
|
||||
);
|
||||
this.partyForm = {};
|
||||
this.reloadMasters();
|
||||
},
|
||||
@@ -400,7 +413,11 @@ export class InvestmentMastersComponent implements OnInit {
|
||||
request.subscribe({
|
||||
next: (res) => {
|
||||
this.saving = false;
|
||||
this.toast(`Script ${res.resourceIdentifier ?? f.scriptCode} ${f.id ? 'updated' : 'saved'}.`);
|
||||
this.toast(
|
||||
awaitingApproval(res)
|
||||
? sentForApproval(f.id ? `Change to script ${f.scriptCode}` : `New script ${f.scriptName ?? ''}`)
|
||||
: `Script ${res.resourceIdentifier ?? f.scriptCode} ${f.id ? 'updated' : 'saved'}.`
|
||||
);
|
||||
this.scriptForm = {};
|
||||
this.reloadMasters();
|
||||
},
|
||||
|
||||
@@ -31,6 +31,19 @@ export const NON_SLR_TYPES: string[] = [
|
||||
'MUTUAL_FUND'
|
||||
];
|
||||
|
||||
/**
|
||||
* Every investment entry goes through maker-checker (Jitendra Sir): the server then holds it for a checker and answers
|
||||
* with its Checker Inbox entry and `rollbackTransaction` instead of carrying it out. Daily rates are not held.
|
||||
*/
|
||||
export function awaitingApproval(res: unknown): boolean {
|
||||
return !!(res as { rollbackTransaction?: boolean } | null)?.rollbackTransaction;
|
||||
}
|
||||
|
||||
/** What to tell the user when `what` went to the Checker Inbox instead of taking effect. */
|
||||
export function sentForApproval(what: string): string {
|
||||
return `${what} sent for approval (Checker Inbox) — nothing is saved or posted until a checker approves it.`;
|
||||
}
|
||||
|
||||
/** Investment party as returned by /investment/parties. */
|
||||
export interface InvestmentPartyDto {
|
||||
id: number;
|
||||
|
||||
Reference in New Issue
Block a user