Files
edr-platform/apps/edr-freight-web/backoffice/src/services/shippingLineCredits.service.ts
2026-08-13 18:56:52 +00:00

132 lines
4.1 KiB
TypeScript

import { api as apiClient } from "@/auth/http";
import { URL_CONSTANTS } from "@/constants/URLS";
import type {
CreditInvoicePendingAction,
GeneratedCreditInvoice,
OutstandingTotals,
PaginatedCreditInvoices,
PaginatedShippingLineCredits,
ShippingLineCreditStatus,
} from "@/types/shippingLineCredit";
export interface ShippingLineCreditListFilter {
page?: number;
pageSize?: number;
status?: ShippingLineCreditStatus;
/** Narrow to one line; omit for all lines. */
shippingLineId?: string;
}
export const shippingLineCreditsService = {
/** Outstanding totals — every line, or one line when an id is given. */
summary(shippingLineId?: string): Promise<OutstandingTotals> {
return apiClient
.get<OutstandingTotals>(URL_CONSTANTS.SHIPPING_LINE_CREDITS.SUMMARY, {
params: shippingLineId ? { shippingLineId } : {},
})
.then((r) => r.data);
},
/** The whole credit ledger, newest first, optionally filtered. */
list(
filter: ShippingLineCreditListFilter = {},
): Promise<PaginatedShippingLineCredits> {
const { page = 1, pageSize = 20, status, shippingLineId } = filter;
return apiClient
.get<PaginatedShippingLineCredits>(
URL_CONSTANTS.SHIPPING_LINE_CREDITS.BASE,
{
params: {
page,
pageSize,
...(status ? { status } : {}),
...(shippingLineId ? { shippingLineId } : {}),
},
},
)
.then((r) => r.data);
},
/**
* Bill a batch of unbilled credits as one invoice. The API enforces that all
* credits belong to one shipping line and share one currency.
*/
generateInvoice(
creditIds: string[],
dueInDays?: number,
): Promise<GeneratedCreditInvoice> {
return apiClient
.post<GeneratedCreditInvoice>(URL_CONSTANTS.SHIPPING_LINE_CREDITS.INVOICE, {
creditIds,
...(dueInDays ? { dueInDays } : {}),
})
.then((r) => r.data);
},
/** Credit invoices with any pending manual-action request attached. */
listInvoices(filter: {
page?: number;
pageSize?: number;
status?: string;
shippingLineId?: string;
} = {}): Promise<PaginatedCreditInvoices> {
const { page = 1, pageSize = 20, status, shippingLineId } = filter;
return apiClient
.get<PaginatedCreditInvoices>(URL_CONSTANTS.SHIPPING_LINE_CREDITS.INVOICES, {
params: {
page,
pageSize,
...(status ? { status } : {}),
...(shippingLineId ? { shippingLineId } : {}),
},
})
.then((r) => r.data);
},
/** Undecided manual-action requests for a batch of invoice ids. */
pendingInvoiceActions(
invoiceIds: string[],
): Promise<CreditInvoicePendingAction[]> {
if (!invoiceIds.length) return Promise.resolve([]);
return apiClient
.get<CreditInvoicePendingAction[]>(
`${URL_CONSTANTS.SHIPPING_LINE_CREDITS.BASE}/invoice-actions/pending`,
{ params: { invoiceIds: invoiceIds.join(",") } },
)
.then((r) => r.data);
},
/** Maker step: raise a mark-paid or cancel request on a credit invoice. */
requestInvoiceAction(
invoiceId: string,
action: "MARK_PAID" | "CANCEL",
reason: string,
paymentReference?: string,
): Promise<CreditInvoicePendingAction> {
const url =
action === "MARK_PAID"
? URL_CONSTANTS.SHIPPING_LINE_CREDITS.MARK_PAID_REQUEST(invoiceId)
: URL_CONSTANTS.SHIPPING_LINE_CREDITS.CANCEL_REQUEST(invoiceId);
return apiClient
.post<CreditInvoicePendingAction>(url, {
reason,
...(paymentReference ? { paymentReference } : {}),
})
.then((r) => r.data);
},
/** Decision step: approve (executes) or reject a pending request. */
decideInvoiceAction(
approvalId: string,
approve: boolean,
note?: string,
): Promise<CreditInvoicePendingAction> {
const url = approve
? URL_CONSTANTS.SHIPPING_LINE_CREDITS.APPROVE_ACTION(approvalId)
: URL_CONSTANTS.SHIPPING_LINE_CREDITS.REJECT_ACTION(approvalId);
return apiClient
.post<CreditInvoicePendingAction>(url, note ? { note } : {})
.then((r) => r.data);
},
};