/** * 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/. */ import { Injectable, inject } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; import { Observable } from 'rxjs'; /** One row of a voucher correction, as the server keeps it (snake_case columns). */ export interface VoucherCorrection { id: number; original_voucher_no: string; original_txn_id: number; wrong_savings_account_id: number; wrong_account_no: string; wrong_client_name: string | null; amount: number; txn_date: string | null; status: 'UNPASS_PENDING' | 'UNPASSED' | 'UNPASS_REJECTED' | 'CORRECTION_PENDING' | 'COMPLETED' | 'CLOSED'; reason: string | null; rejection_reason: string | null; unpass_by_name: string | null; unpass_at: string | null; unpass_approved_by_name: string | null; correct_account_no: string | null; correct_client_name: string | null; correction_by_name: string | null; correction_at: string | null; correction_approved_by_name: string | null; new_voucher_no: string | null; } /** A cash deposit voucher of today that can still be unpassed. */ export interface EligibleVoucher { voucherNo: string; amount: number; createdAt: string; cashier: string; txnId: number; savingsAccountId: number; accountNo: string; clientName: string | null; paymentType: string; } /** What the server knows about a savings account typed in as the correct one. */ export interface AccountLookup { id: number; accountNo: string; clientId: number | null; clientName: string | null; balance: number; currencyCode: string; canReceive: boolean; } /** HTTP service for the voucher correction workflow: unpass, approve, re-enter, approve. */ @Injectable({ providedIn: 'root' }) export class VoucherCorrectionService { private http = inject(HttpClient); private readonly base = '/vouchers/corrections'; eligible(search?: string): Observable { let params = new HttpParams(); if (search) params = params.set('search', search); return this.http.get(`${this.base}/eligible`, { params }); } unpass(voucherNo: string, reason: string): Observable { return this.http.post(`${this.base}/unpass`, { voucherNo, reason }); } list(status?: string, mine = false): Observable { let params = new HttpParams().set('mine', String(mine)); if (status) params = params.set('status', status); return this.http.get(this.base, { params }); } get(id: number): Observable { return this.http.get(`${this.base}/${id}`); } accountLookup(accountNo: string): Observable { return this.http.get(`${this.base}/account-lookup`, { params: { accountNo } }); } submitCorrection(id: number, correctAccountNo: string): Observable { return this.http.post(`${this.base}/${id}/correction`, { correctAccountNo }); } /** The cashier gives up the correction, e.g. when the wrong account no longer holds the money. */ close(id: number, reason: string): Observable { return this.http.post(`${this.base}/${id}/close`, { reason }); } approveUnpass(id: number): Observable { return this.http.post(`${this.base}/${id}/unpass/approve`, {}); } rejectUnpass(id: number, reason: string): Observable { return this.http.post(`${this.base}/${id}/unpass/reject`, { reason }); } approveCorrection(id: number): Observable { return this.http.post(`${this.base}/${id}/correction/approve`, {}); } rejectCorrection(id: number, reason: string): Observable { return this.http.post(`${this.base}/${id}/correction/reject`, { reason }); } /** Ids of the transactions of this account that a completed correction removed. */ voidedTransactions(savingsAccountId: number): Observable { return this.http.get(`${this.base}/voided-transactions`, { params: { savingsAccountId } }); } }