Add guided Payments operator workspace
Module Package Release / publish-packages (push) Successful in 14s
Module Package Release / publish-packages (push) Successful in 14s
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
ApiError,
|
||||
apiFetch,
|
||||
apiPath,
|
||||
type ApiSettings
|
||||
} from "@govoplan/core-webui";
|
||||
|
||||
export type PaymentStatus = "requested" | "paid";
|
||||
|
||||
export type EvidenceReference = {
|
||||
kind: string;
|
||||
owner_module: string;
|
||||
evidence_id: string;
|
||||
tenant_id: string;
|
||||
version?: string | null;
|
||||
checksum?: string | null;
|
||||
};
|
||||
|
||||
export type PaymentReconciliation = {
|
||||
reconciliation_id: string;
|
||||
mode: "manual";
|
||||
amount_minor: number;
|
||||
currency: string;
|
||||
transaction_reference: string;
|
||||
evidence_ref: EvidenceReference;
|
||||
received_at: string;
|
||||
recorded_at: string;
|
||||
recorded_by_ref: string;
|
||||
};
|
||||
|
||||
export type PaymentEvent = {
|
||||
event_id: string;
|
||||
event_type: string;
|
||||
status: PaymentStatus;
|
||||
occurred_at: string;
|
||||
actor_ref: string;
|
||||
payload: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type PaymentRequest = {
|
||||
payment_id: string;
|
||||
tenant_id: string;
|
||||
payment_reference: string;
|
||||
source: {
|
||||
module: string;
|
||||
resource_type: string;
|
||||
resource_id: string;
|
||||
};
|
||||
amount_minor: number;
|
||||
currency: string;
|
||||
subject: string;
|
||||
status: PaymentStatus;
|
||||
requested_at: string;
|
||||
requested_by_ref: string;
|
||||
due_at?: string | null;
|
||||
settled_at?: string | null;
|
||||
context_refs: Record<string, string>;
|
||||
metadata: Record<string, unknown>;
|
||||
reconciliation?: PaymentReconciliation | null;
|
||||
events: PaymentEvent[];
|
||||
replayed: boolean;
|
||||
};
|
||||
|
||||
export type PaymentRequestCreate = {
|
||||
source_module: string;
|
||||
source_resource_type: string;
|
||||
source_resource_id: string;
|
||||
amount_minor: number;
|
||||
currency: string;
|
||||
subject: string;
|
||||
idempotency_key: string;
|
||||
due_at?: string | null;
|
||||
context_refs: Record<string, string>;
|
||||
metadata: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type ManualPaymentReconciliationCreate = {
|
||||
amount_minor: number;
|
||||
currency: string;
|
||||
transaction_reference: string;
|
||||
evidence_ref: EvidenceReference;
|
||||
idempotency_key: string;
|
||||
received_at: string;
|
||||
metadata: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export async function listPaymentRequests(
|
||||
settings: ApiSettings,
|
||||
filters: { status?: PaymentStatus; sourceResourceId?: string; limit?: number } = {},
|
||||
signal?: AbortSignal
|
||||
): Promise<PaymentRequest[]> {
|
||||
const response = await apiFetch<{ payments: PaymentRequest[] }>(
|
||||
settings,
|
||||
apiPath("/api/v1/payments/requests", {
|
||||
status: filters.status,
|
||||
source_resource_id: filters.sourceResourceId,
|
||||
limit: filters.limit ?? 200
|
||||
}),
|
||||
{ signal }
|
||||
);
|
||||
return response.payments;
|
||||
}
|
||||
|
||||
export function createPaymentRequest(
|
||||
settings: ApiSettings,
|
||||
payload: PaymentRequestCreate
|
||||
): Promise<PaymentRequest> {
|
||||
return apiFetch<PaymentRequest>(settings, "/api/v1/payments/requests", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
|
||||
export function reconcileManualPayment(
|
||||
settings: ApiSettings,
|
||||
paymentId: string,
|
||||
payload: ManualPaymentReconciliationCreate
|
||||
): Promise<PaymentRequest> {
|
||||
return apiFetch<PaymentRequest>(
|
||||
settings,
|
||||
`/api/v1/payments/requests/${encodeURIComponent(paymentId)}/manual-reconciliations`,
|
||||
{ method: "POST", body: JSON.stringify(payload) }
|
||||
);
|
||||
}
|
||||
|
||||
export function paymentApiErrorMessage(reason: unknown): string {
|
||||
if (reason instanceof ApiError) {
|
||||
try {
|
||||
const payload = JSON.parse(reason.body) as { detail?: unknown };
|
||||
if (typeof payload.detail === "string") return payload.detail;
|
||||
} catch {
|
||||
// The response body may be plain text.
|
||||
}
|
||||
if (reason.status === 409) return "The payment changed or this replay key is already bound to different evidence. Reload and review the current state.";
|
||||
if (reason.status === 403) return "Your current role does not permit this payment action.";
|
||||
}
|
||||
return reason instanceof Error ? reason.message : String(reason);
|
||||
}
|
||||
Reference in New Issue
Block a user