feat(billing): USD offline bank-transfer payments

This commit is contained in:
Marshal
2026-08-08 13:37:05 +00:00
parent 83b9e32670
commit a42d32c27c
31 changed files with 923 additions and 11 deletions

View File

@@ -41,6 +41,7 @@ import type {
Invoice,
InvoiceListFilter,
PaginatedInvoices,
PaginatedOfflineUsdInvoices,
} from "@/types/invoice";
import type { IOverviewDashboard, OverviewRange } from "@/types/overview";
import {
@@ -2914,6 +2915,29 @@ export const api = {
({ id }) => invoicesService.getById(id),
({ id }) => QUERY_KEYS.INVOICES.byId(id),
),
listOfflineUsd: endpoint<
{ filter: InvoiceListFilter },
PaginatedOfflineUsdInvoices
>(
"invoices",
"listOfflineUsd",
({ filter }) => invoicesService.listOfflineUsd(filter),
({ filter }) => QUERY_KEYS.INVOICES.offlineUsd(filter),
),
confirmOffline: endpoint<
{ id: string; file: File; reference?: string },
Invoice
>(
"invoices",
"confirmOffline",
({ id, file, reference }) =>
invoicesService.confirmOffline(id, file, reference),
undefined,
// Settling the invoice also advances the booking, so refresh both trees.
() => [QUERY_KEYS.INVOICES.ROOT, QUERY_KEYS.BOOKINGS.ROOT],
),
},
overview: {

View File

@@ -4,6 +4,7 @@ import type {
Invoice,
InvoiceListFilter,
PaginatedInvoices,
PaginatedOfflineUsdInvoices,
} from "@/types/invoice";
const cleanParams = (params: object) =>
@@ -33,4 +34,25 @@ export const invoicesService = {
responseType: "blob",
});
},
/** Finance worklist: USD invoices awaiting bank-transfer confirmation. */
listOfflineUsd(
filter: InvoiceListFilter,
): Promise<PaginatedOfflineUsdInvoices> {
return apiClient
.get<PaginatedOfflineUsdInvoices>(URL_CONSTANTS.BILLING.OFFLINE_USD, {
params: cleanParams(filter),
})
.then((r) => r.data);
},
/** Confirm a USD invoice paid by bank transfer — the slip file is required. */
confirmOffline(id: string, file: File, reference?: string): Promise<Invoice> {
const body = new FormData();
body.append("file", file);
if (reference) body.append("reference", reference);
return apiClient
.post<Invoice>(URL_CONSTANTS.BILLING.CONFIRM_OFFLINE(id), body)
.then((r) => r.data);
},
};