Files
cbsnexora/src/app/chequebook/chequebook.service.ts
T
Jaanu423andClaude Sonnet 5 0cc79ccd57 feat(clerk): add clerk-facing Cheque Book screen and shell nav wiring
Adds a customer-account-scoped Cheque Book view under Clerk > Account
Facilities (list + leaf detail, with stop-payment/report-lost/mark-used/
return actions), reachable via a new hover dropdown on the Account
Facilities nav item. Also refreshes the Account Facilities page layout,
and carries over a few chequebook service/detail-dialog fixes from the
back-office module (used-leaf display, leaf-lookup dialog polish).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-15 16:08:43 +05:30

227 lines
8.3 KiB
TypeScript

/**
* 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/.
*/
/** Angular Imports */
import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
/**
* Cheque Book Inventory — stationery master, a unified stock ledger (HO receipt / branch transfer-in share
* one drawdown-cursor concept), account issuance with per-leaf serial tracking, stop-payment and
* lost/stolen hotlisting (both issued and unissued stock).
*/
@Injectable({
providedIn: 'root'
})
export class ChequeBookService {
private http = inject(HttpClient);
// ----- Series -----
/** status: 'ACTIVE' | 'INACTIVE'. Server-side paginated — always returns { pageItems, totalFilteredRecords }. */
getSeries(status?: string, offset = 0, limit = 20): Observable<any> {
let params = new HttpParams().set('offset', offset).set('limit', limit);
if (status) params = params.set('status', status);
return this.http.get('/chequeseries', { params });
}
createSeries(payload: any): Observable<any> {
return this.http.post('/chequeseries', payload);
}
updateSeries(id: string | number, payload: any): Observable<any> {
return this.http.put(`/chequeseries/${id}`, payload);
}
deactivateSeries(id: string | number): Observable<any> {
return this.http.delete(`/chequeseries/${id}`);
}
// ----- Stock lots -----
/** Server-side paginated — always returns { pageItems, totalFilteredRecords }. */
getStockLots(
officeId?: string | number,
seriesId?: string | number,
status?: string,
offset = 0,
limit = 20
): Observable<any> {
let params = new HttpParams().set('offset', offset).set('limit', limit);
if (officeId) params = params.set('officeId', officeId);
if (seriesId) params = params.set('seriesId', seriesId);
if (status) params = params.set('status', status);
return this.http.get('/chequestocklots', { params });
}
receiveStock(payload: any): Observable<any> {
return this.http.post('/chequestocklots', payload);
}
reportStockLotLost(lotId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequestocklots/${lotId}`, payload, {
params: new HttpParams().set('command', 'reportlost')
});
}
// ----- Stock transfers -----
/** Server-side paginated — always returns { pageItems, totalFilteredRecords }. */
getStockTransfers(status?: string, offset = 0, limit = 20): Observable<any> {
let params = new HttpParams().set('offset', offset).set('limit', limit);
if (status) params = params.set('status', status);
return this.http.get('/chequestocktransfers', { params });
}
dispatchStockTransfer(payload: any): Observable<any> {
return this.http.post('/chequestocktransfers', payload);
}
receiveStockTransfer(transferId: string | number): Observable<any> {
return this.http.post(
`/chequestocktransfers/${transferId}`,
{},
{ params: new HttpParams().set('command', 'receive') }
);
}
rejectStockTransfer(transferId: string | number): Observable<any> {
return this.http.post(
`/chequestocktransfers/${transferId}`,
{},
{ params: new HttpParams().set('command', 'reject') }
);
}
// ----- Cheque books -----
getBooks(
accountType?: string,
accountId?: string | number,
officeId?: string | number,
status?: string,
offset = 0,
limit = 20
): Observable<any> {
let params = new HttpParams().set('offset', offset).set('limit', limit);
if (accountType) params = params.set('accountType', accountType);
if (accountId) params = params.set('accountId', accountId);
if (officeId) params = params.set('officeId', officeId);
if (status) params = params.set('status', status);
return this.http.get('/chequebooks', { params });
}
getBook(id: string | number): Observable<any> {
return this.http.get(`/chequebooks/${id}`);
}
getLeaves(bookId: string | number): Observable<any> {
return this.http.get(`/chequebooks/${bookId}/leaves`);
}
requestBook(payload: any): Observable<any> {
return this.http.post('/chequebooks', payload);
}
issueBook(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'issue') });
}
rejectBook(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'reject') });
}
withdrawBook(bookId: string | number): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, {}, { params: new HttpParams().set('command', 'withdraw') });
}
stopPayment(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, {
params: new HttpParams().set('command', 'stoppayment')
});
}
revokeStopPayment(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, {
params: new HttpParams().set('command', 'revokestoppayment')
});
}
reportBookLost(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'reportlost') });
}
cancelLeaf(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'cancelleaf') });
}
/** Manually record that leaves cleared, once the branch sees them on the bank/clearing statement. */
markUsed(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'markused') });
}
/** Flag leaves as returned/dishonoured (insufficient funds, signature mismatch, etc.) — terminal, like reportlost. */
returnBook(bookId: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebooks/${bookId}`, payload, { params: new HttpParams().set('command', 'return') });
}
// ----- Pending requests (bespoke maker-checker for series/stock/book creation) -----
/**
* A different user than the maker must approve/reject — enforced server-side, not just in this UI.
* Server-side paginated and date-filtered, matching the clerk disbursement/withdrawal request queues.
*/
getPendingRequests(status?: string, fromDate?: string, toDate?: string, offset = 0, limit = 20): Observable<any> {
let params = new HttpParams().set('offset', offset).set('limit', limit);
if (status) params = params.set('status', status);
if (fromDate) params = params.set('fromDate', fromDate);
if (toDate) params = params.set('toDate', toDate);
return this.http.get('/chequebook/pending-requests', { params });
}
getPendingRequest(id: string | number): Observable<any> {
return this.http.get(`/chequebook/pending-requests/${id}`);
}
approvePendingRequest(id: string | number): Observable<any> {
return this.http.post(
`/chequebook/pending-requests/${id}`,
{},
{ params: new HttpParams().set('command', 'approve') }
);
}
rejectPendingRequest(id: string | number, payload: any): Observable<any> {
return this.http.post(`/chequebook/pending-requests/${id}`, payload, {
params: new HttpParams().set('command', 'reject')
});
}
// ----- Leaf lookup -----
lookupLeaf(serialNo: string | number): Observable<any> {
return this.http.get('/chequeleaves/lookup', { params: new HttpParams().set('serialNo', serialNo) });
}
// ----- Account lookup (by account number) -----
/** Search a Savings or Current account by its account number; returns a paginated list to match against. */
searchAccountByNo(accountType: string, accountNo: string): Observable<any> {
const base = accountType === 'CURRENT' ? '/currentaccounts' : '/savingsaccounts';
const params = new HttpParams().set('accountNo', accountNo).set('offset', '0').set('limit', '20');
return this.http.get(base, { params });
}
// ----- Shared template data -----
getOffices(): Observable<any> {
return this.http.get('/offices');
}
}