mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 01:48:12 +00:00
feat(billing): add PAYMENT_PROCESSING invoice status on payment success redirect (all except CBE bill)
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds PAYMENT_PROCESSING to the invoice status enum: the customer completed
|
||||||
|
* provider checkout (success redirect) and settlement is awaiting the
|
||||||
|
* provider webhook.
|
||||||
|
*/
|
||||||
|
export class InvoicePaymentProcessingStatus3260000000000
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = "InvoicePaymentProcessingStatus3260000000000";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TYPE freight.invoices_status_enum ADD VALUE IF NOT EXISTS 'PAYMENT_PROCESSING' AFTER 'PENDING'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(): Promise<void> {
|
||||||
|
// Postgres cannot drop an enum value; PAYMENT_PROCESSING stays. Harmless.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,8 @@ const DEFAULT_DUE_DAYS = 14;
|
|||||||
const OPEN_STATUSES: Freight.InvoiceStatus[] = [
|
const OPEN_STATUSES: Freight.InvoiceStatus[] = [
|
||||||
Freight.InvoiceStatus.Issued,
|
Freight.InvoiceStatus.Issued,
|
||||||
Freight.InvoiceStatus.Pending,
|
Freight.InvoiceStatus.Pending,
|
||||||
|
// Success-redirect ack; still unsettled, so it must stay payable/settleable.
|
||||||
|
Freight.InvoiceStatus.PaymentProcessing,
|
||||||
Freight.InvoiceStatus.PartiallyPaid,
|
Freight.InvoiceStatus.PartiallyPaid,
|
||||||
Freight.InvoiceStatus.Overdue,
|
Freight.InvoiceStatus.Overdue,
|
||||||
];
|
];
|
||||||
@@ -924,6 +926,26 @@ export class BillingService {
|
|||||||
});
|
});
|
||||||
if (!invoice) return null;
|
if (!invoice) return null;
|
||||||
|
|
||||||
|
// Reconcile-before-expire, caller-proof: an invoice with a payment intent may
|
||||||
|
// have settled at the gateway without the webhook landing yet. `paid` — leave
|
||||||
|
// it open, the (re-emitted) payment.succeeded settles it. `unverifiable` —
|
||||||
|
// never expire on unknown; the caller's next sweep retries. Invoices with no
|
||||||
|
// intent (`paymentId` null) were never payable at a gateway and expire directly.
|
||||||
|
if (invoice.paymentId) {
|
||||||
|
const { paid, unverifiable } = await this.reconcilePayable(
|
||||||
|
invoice.sourceId,
|
||||||
|
);
|
||||||
|
if (paid || unverifiable) {
|
||||||
|
this.logger.warn(
|
||||||
|
`expirePayable skipped for invoice ${invoice.invoiceNumber} (${invoice.id}) — ` +
|
||||||
|
(paid
|
||||||
|
? "gateway reconcile found a settled payment"
|
||||||
|
: "settlement unverifiable at the gateway"),
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.transition(
|
return this.transition(
|
||||||
invoice.id,
|
invoice.id,
|
||||||
Freight.InvoiceStatus.Expired,
|
Freight.InvoiceStatus.Expired,
|
||||||
@@ -1028,6 +1050,40 @@ export class BillingService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Success-redirect ack (see PaymentService.acknowledgeSuccessRedirect): move
|
||||||
|
* the invoice linked to a gateway intent to PAYMENT_PROCESSING. Only from
|
||||||
|
* ISSUED/PENDING — never overwrites a settlement (PAID/PARTIALLY_PAID) and
|
||||||
|
* is idempotent. Balance untouched: this is a display state, not a
|
||||||
|
* settlement; settleByPaymentId still performs the real transition.
|
||||||
|
*/
|
||||||
|
async markInvoicePaymentProcessing(paymentId: string): Promise<void> {
|
||||||
|
await this.dataSource.getRepository(Invoice).update(
|
||||||
|
{
|
||||||
|
paymentId,
|
||||||
|
status: In([
|
||||||
|
Freight.InvoiceStatus.Issued,
|
||||||
|
Freight.InvoiceStatus.Pending,
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
{ status: Freight.InvoiceStatus.PaymentProcessing },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counterpart of {@link markInvoicePaymentProcessing} for a failed intent:
|
||||||
|
* PAYMENT_PROCESSING → PENDING so the invoice reads payable again for a
|
||||||
|
* retry. No-op from any other status.
|
||||||
|
*/
|
||||||
|
async revertInvoicePaymentProcessing(paymentId: string): Promise<void> {
|
||||||
|
await this.dataSource
|
||||||
|
.getRepository(Invoice)
|
||||||
|
.update(
|
||||||
|
{ paymentId, status: Freight.InvoiceStatus.PaymentProcessing },
|
||||||
|
{ status: Freight.InvoiceStatus.Pending },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Payment initiation & settlement (the gateway boundary) ───────────────────
|
// ── Payment initiation & settlement (the gateway boundary) ───────────────────
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
HttpStatus,
|
HttpStatus,
|
||||||
Param,
|
Param,
|
||||||
ParseUUIDPipe,
|
ParseUUIDPipe,
|
||||||
|
Post,
|
||||||
Query,
|
Query,
|
||||||
Res,
|
Res,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
@@ -84,6 +85,15 @@ export class PaymentController {
|
|||||||
return this.paymentService.getIntentByBookingId(bookingId);
|
return this.paymentService.getIntentByBookingId(bookingId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post("redirect-success/:bookingId")
|
||||||
|
@ApiOperation({
|
||||||
|
summary:
|
||||||
|
"Success-redirect ack: mark payment processing + invoice PAYMENT_PROCESSING (webhook remains source of truth)",
|
||||||
|
})
|
||||||
|
acknowledgeSuccessRedirect(@Param("bookingId") bookingId: string) {
|
||||||
|
return this.paymentService.acknowledgeSuccessRedirect(bookingId);
|
||||||
|
}
|
||||||
|
|
||||||
@Get("receipt/:orderId")
|
@Get("receipt/:orderId")
|
||||||
@Public()
|
@Public()
|
||||||
@ApiOperation({ summary: "Generate a payment receipt HTML page" })
|
@ApiOperation({ summary: "Generate a payment receipt HTML page" })
|
||||||
|
|||||||
@@ -253,8 +253,10 @@ export class PaymentService {
|
|||||||
payerAccount: input.payerAccount,
|
payerAccount: input.payerAccount,
|
||||||
payerName: input.payerName,
|
payerName: input.payerName,
|
||||||
expiresAt: input.expiresAt,
|
expiresAt: input.expiresAt,
|
||||||
|
// bookingId lets the success page ack the redirect (→ PAYMENT_PROCESSING).
|
||||||
returnUrl:
|
returnUrl:
|
||||||
input.returnUrl ?? "https://edrfreight.triaplc.com/payment/success",
|
input.returnUrl ??
|
||||||
|
`https://edrfreight.triaplc.com/payment/success?bookingId=${encodeURIComponent(input.referenceId)}`,
|
||||||
failureUrl:
|
failureUrl:
|
||||||
input.failureUrl ?? "https://edrfreight.triaplc.com/payment/failure",
|
input.failureUrl ?? "https://edrfreight.triaplc.com/payment/failure",
|
||||||
});
|
});
|
||||||
@@ -492,6 +494,37 @@ export class PaymentService {
|
|||||||
return { alreadyFinalized: false };
|
return { alreadyFinalized: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Success-redirect ack from the portal: the customer finished provider
|
||||||
|
* checkout, settlement webhook not (necessarily) in yet. Optimistic
|
||||||
|
* intermediate only — the webhook stays the source of truth. Never
|
||||||
|
* downgrades: only action-required → processing, and the invoice moves to
|
||||||
|
* PAYMENT_PROCESSING only from an open unpaid status. CBE_BILL is excluded
|
||||||
|
* (bank-counter flow, it has no redirect).
|
||||||
|
*/
|
||||||
|
async acknowledgeSuccessRedirect(
|
||||||
|
referenceId: string,
|
||||||
|
): Promise<{ acknowledged: boolean }> {
|
||||||
|
const intent = await this.paymentRepo.findOneBy({ refId: referenceId });
|
||||||
|
if (!intent || intent.method === "cbe-bill") {
|
||||||
|
return { acknowledged: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intent.status === "action-required") {
|
||||||
|
await this.paymentRepo.update(
|
||||||
|
{ id: intent.id, status: "action-required" },
|
||||||
|
{ status: "processing" },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Even if the intent already advanced (e.g. webhook raced the redirect to
|
||||||
|
// "processing"), the invoice ack is idempotent and status-guarded.
|
||||||
|
if (intent.status === "action-required" || intent.status === "processing") {
|
||||||
|
await this.billing.markInvoicePaymentProcessing(intent.id);
|
||||||
|
return { acknowledged: true };
|
||||||
|
}
|
||||||
|
return { acknowledged: false };
|
||||||
|
}
|
||||||
|
|
||||||
async markPaymentFailed(input: {
|
async markPaymentFailed(input: {
|
||||||
intentId: string;
|
intentId: string;
|
||||||
failureCode?: string;
|
failureCode?: string;
|
||||||
@@ -510,7 +543,9 @@ export class PaymentService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Invoice stays open for retry — nothing to settle. Logged only.
|
// Invoice stays open for retry — nothing to settle. A redirect-acked
|
||||||
|
// PAYMENT_PROCESSING invoice is put back to PENDING so it reads payable.
|
||||||
|
await this.billing.revertInvoicePaymentProcessing(intent.id);
|
||||||
this.logger.warn(
|
this.logger.warn(
|
||||||
`Payment ${intent.id} failed for ${intent.refId}` +
|
`Payment ${intent.id} failed for ${intent.refId}` +
|
||||||
(input.failureMessage ? `: ${input.failureMessage}` : ""),
|
(input.failureMessage ? `: ${input.failureMessage}` : ""),
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ const INVOICE_STATUS_COLOR: Record<Freight.InvoiceStatus, string> = {
|
|||||||
DRAFT: "gray",
|
DRAFT: "gray",
|
||||||
ISSUED: "cyan",
|
ISSUED: "cyan",
|
||||||
PENDING: "yellow",
|
PENDING: "yellow",
|
||||||
|
PAYMENT_PROCESSING: "indigo",
|
||||||
PARTIALLY_PAID: "orange",
|
PARTIALLY_PAID: "orange",
|
||||||
PAID: "edr-green",
|
PAID: "edr-green",
|
||||||
OVERDUE: "red",
|
OVERDUE: "red",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { openPdfBlob } from './pdf';
|
|||||||
const INVOICE_STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
|
const INVOICE_STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
|
||||||
DRAFT: 'gray',
|
DRAFT: 'gray',
|
||||||
ISSUED: 'orange',
|
ISSUED: 'orange',
|
||||||
|
PAYMENT_PROCESSING: 'indigo',
|
||||||
PARTIALLY_PAID: 'yellow',
|
PARTIALLY_PAID: 'yellow',
|
||||||
PAID: 'edr-green',
|
PAID: 'edr-green',
|
||||||
CANCELLED: 'gray',
|
CANCELLED: 'gray',
|
||||||
|
|||||||
@@ -183,6 +183,7 @@ export default function InvoicesPage() {
|
|||||||
data={[
|
data={[
|
||||||
{ label: "All", value: "all" },
|
{ label: "All", value: "all" },
|
||||||
{ label: "Pending", value: "PENDING" },
|
{ label: "Pending", value: "PENDING" },
|
||||||
|
{ label: "Payment processing", value: "PAYMENT_PROCESSING" },
|
||||||
{ label: "Paid", value: "PAID" },
|
{ label: "Paid", value: "PAID" },
|
||||||
{ label: "Overdue", value: "OVERDUE" },
|
{ label: "Overdue", value: "OVERDUE" },
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ const INVOICE_STATUS_META: Record<string, { label: string; color: string }> = {
|
|||||||
PAID: { label: "Paid", color: "green" },
|
PAID: { label: "Paid", color: "green" },
|
||||||
PARTIALLY_PAID: { label: "Partially Paid", color: "teal" },
|
PARTIALLY_PAID: { label: "Partially Paid", color: "teal" },
|
||||||
PENDING: { label: "Pending", color: "yellow" },
|
PENDING: { label: "Pending", color: "yellow" },
|
||||||
|
PAYMENT_PROCESSING: { label: "Payment Processing", color: "indigo" },
|
||||||
UNPAID: { label: "Unpaid", color: "yellow" },
|
UNPAID: { label: "Unpaid", color: "yellow" },
|
||||||
OPEN: { label: "Open", color: "yellow" },
|
OPEN: { label: "Open", color: "yellow" },
|
||||||
ISSUED: { label: "Issued", color: "blue" },
|
ISSUED: { label: "Issued", color: "blue" },
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ const INVOICE_STATUS_META: Record<string, { label: string; color: string }> = {
|
|||||||
PAID: { label: "Paid", color: "green" },
|
PAID: { label: "Paid", color: "green" },
|
||||||
PARTIALLY_PAID: { label: "Partially Paid", color: "teal" },
|
PARTIALLY_PAID: { label: "Partially Paid", color: "teal" },
|
||||||
PENDING: { label: "Pending", color: "yellow" },
|
PENDING: { label: "Pending", color: "yellow" },
|
||||||
|
PAYMENT_PROCESSING: { label: "Payment Processing", color: "indigo" },
|
||||||
UNPAID: { label: "Unpaid", color: "yellow" },
|
UNPAID: { label: "Unpaid", color: "yellow" },
|
||||||
OPEN: { label: "Open", color: "yellow" },
|
OPEN: { label: "Open", color: "yellow" },
|
||||||
ISSUED: { label: "Issued", color: "blue" },
|
ISSUED: { label: "Issued", color: "blue" },
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ const CONTRACT_STATUSES = [
|
|||||||
const INVOICE_STATUSES = [
|
const INVOICE_STATUSES = [
|
||||||
"ISSUED",
|
"ISSUED",
|
||||||
"PENDING",
|
"PENDING",
|
||||||
|
"PAYMENT_PROCESSING",
|
||||||
"PARTIALLY_PAID",
|
"PARTIALLY_PAID",
|
||||||
"PAID",
|
"PAID",
|
||||||
"OVERDUE",
|
"OVERDUE",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import { extractErrorMessage } from '@/components/warehouses/options';
|
|||||||
const STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
|
const STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
|
||||||
DRAFT: 'gray',
|
DRAFT: 'gray',
|
||||||
ISSUED: 'orange',
|
ISSUED: 'orange',
|
||||||
|
PAYMENT_PROCESSING: 'indigo',
|
||||||
PARTIALLY_PAID: 'yellow',
|
PARTIALLY_PAID: 'yellow',
|
||||||
PAID: 'edr-green',
|
PAID: 'edr-green',
|
||||||
CANCELLED: 'gray',
|
CANCELLED: 'gray',
|
||||||
|
|||||||
@@ -907,6 +907,7 @@ export interface AllocationCriteria {
|
|||||||
export const WAREHOUSE_INVOICE_STATUSES = [
|
export const WAREHOUSE_INVOICE_STATUSES = [
|
||||||
'DRAFT',
|
'DRAFT',
|
||||||
'ISSUED',
|
'ISSUED',
|
||||||
|
'PAYMENT_PROCESSING',
|
||||||
'PARTIALLY_PAID',
|
'PARTIALLY_PAID',
|
||||||
'PAID',
|
'PAID',
|
||||||
'CANCELLED',
|
'CANCELLED',
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ export const URL_CONSTANTS = {
|
|||||||
PAYMENTS: {
|
PAYMENTS: {
|
||||||
INITIATE: "/api/payments/initiate",
|
INITIATE: "/api/payments/initiate",
|
||||||
INTENT: (bookingId: string) => `/api/payments/intents/${bookingId}`,
|
INTENT: (bookingId: string) => `/api/payments/intents/${bookingId}`,
|
||||||
|
REDIRECT_SUCCESS: (bookingId: string) =>
|
||||||
|
`/api/payments/redirect-success/${bookingId}`,
|
||||||
CHECKOUT: "/api/payments/checkout",
|
CHECKOUT: "/api/payments/checkout",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const STATUS_STYLE: Record<
|
|||||||
[Freight.InvoiceStatus.Draft]: { label: "Draft", bg: "#EEF2F6", fg: "#64748B" },
|
[Freight.InvoiceStatus.Draft]: { label: "Draft", bg: "#EEF2F6", fg: "#64748B" },
|
||||||
[Freight.InvoiceStatus.Issued]: { label: "Due", bg: "#FEF3E2", fg: "#B45309" },
|
[Freight.InvoiceStatus.Issued]: { label: "Due", bg: "#FEF3E2", fg: "#B45309" },
|
||||||
[Freight.InvoiceStatus.Pending]: { label: "Due", bg: "#FEF3E2", fg: "#B45309" },
|
[Freight.InvoiceStatus.Pending]: { label: "Due", bg: "#FEF3E2", fg: "#B45309" },
|
||||||
|
[Freight.InvoiceStatus.PaymentProcessing]: { label: "Payment processing", bg: "#EAF1FB", fg: "#2563EB" },
|
||||||
[Freight.InvoiceStatus.PartiallyPaid]: { label: "Partially paid", bg: "#FEF9E7", fg: "#A16207" },
|
[Freight.InvoiceStatus.PartiallyPaid]: { label: "Partially paid", bg: "#FEF9E7", fg: "#A16207" },
|
||||||
[Freight.InvoiceStatus.Paid]: { label: "Paid", bg: "#E6F7EF", fg: "#0A6F4D" },
|
[Freight.InvoiceStatus.Paid]: { label: "Paid", bg: "#E6F7EF", fg: "#0A6F4D" },
|
||||||
[Freight.InvoiceStatus.Overdue]: { label: "Overdue", bg: "#FDECEC", fg: "#C0392B" },
|
[Freight.InvoiceStatus.Overdue]: { label: "Overdue", bg: "#FDECEC", fg: "#C0392B" },
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const INVOICE_STATUS_LABELS: Record<string, string> = {
|
|||||||
DRAFT: "Draft",
|
DRAFT: "Draft",
|
||||||
ISSUED: "Issued",
|
ISSUED: "Issued",
|
||||||
PENDING: "Due",
|
PENDING: "Due",
|
||||||
|
PAYMENT_PROCESSING: "Payment processing",
|
||||||
PARTIALLY_PAID: "Partially paid",
|
PARTIALLY_PAID: "Partially paid",
|
||||||
PAID: "Paid",
|
PAID: "Paid",
|
||||||
OVERDUE: "Overdue",
|
OVERDUE: "Overdue",
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ const PAYMENT_COLORS: Record<string, string> = {
|
|||||||
// Backend emits the long form on some flows; keep the short alias too.
|
// Backend emits the long form on some flows; keep the short alias too.
|
||||||
VERIFICATION_IN_PROGRESS: "yellow",
|
VERIFICATION_IN_PROGRESS: "yellow",
|
||||||
PAYMENT_VERIFICATION_IN_PROGRESS: "yellow",
|
PAYMENT_VERIFICATION_IN_PROGRESS: "yellow",
|
||||||
|
PAYMENT_PROCESSING: "yellow",
|
||||||
OVERDUE: "red",
|
OVERDUE: "red",
|
||||||
REFUNDED: "blue",
|
REFUNDED: "blue",
|
||||||
CANCELLED: "gray",
|
CANCELLED: "gray",
|
||||||
@@ -132,6 +133,7 @@ const PAYMENT_LABELS: Record<string, string> = {
|
|||||||
PNR_GENERATED: "PNR generated",
|
PNR_GENERATED: "PNR generated",
|
||||||
VERIFICATION_IN_PROGRESS: "Verifying",
|
VERIFICATION_IN_PROGRESS: "Verifying",
|
||||||
PAYMENT_VERIFICATION_IN_PROGRESS: "Verifying",
|
PAYMENT_VERIFICATION_IN_PROGRESS: "Verifying",
|
||||||
|
PAYMENT_PROCESSING: "Payment processing",
|
||||||
OVERDUE: "Overdue",
|
OVERDUE: "Overdue",
|
||||||
REFUNDED: "Refunded",
|
REFUNDED: "Refunded",
|
||||||
CANCELLED: "Cancelled",
|
CANCELLED: "Cancelled",
|
||||||
|
|||||||
@@ -8,10 +8,22 @@ import {
|
|||||||
ThemeIcon,
|
ThemeIcon,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import { CheckCircle2, FileText, Home } from "lucide-react";
|
import { CheckCircle2, FileText, Home } from "lucide-react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useEffect } from "react";
|
||||||
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||||
|
import { paymentsService } from "@/services/payments.service";
|
||||||
|
|
||||||
export default function PaymentSuccessPage() {
|
export default function PaymentSuccessPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const bookingId = searchParams.get("bookingId");
|
||||||
|
|
||||||
|
// Fire-and-forget ack: payment → processing, invoice → PAYMENT_PROCESSING.
|
||||||
|
// The provider webhook remains the source of truth for the final PAID state.
|
||||||
|
useEffect(() => {
|
||||||
|
if (bookingId) {
|
||||||
|
paymentsService.acknowledgeSuccessRedirect(bookingId).catch(() => {});
|
||||||
|
}
|
||||||
|
}, [bookingId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
|
|||||||
@@ -107,6 +107,11 @@ export const paymentsService = {
|
|||||||
return data.data ?? data;
|
return data.data ?? data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/** Success-redirect ack: payment → processing, invoice → PAYMENT_PROCESSING. */
|
||||||
|
acknowledgeSuccessRedirect: async (bookingId: string): Promise<void> => {
|
||||||
|
await client.post(P.REDIRECT_SUCCESS(bookingId));
|
||||||
|
},
|
||||||
|
|
||||||
checkoutUrl: buildCheckoutUrl,
|
checkoutUrl: buildCheckoutUrl,
|
||||||
checkoutUrlForInvoice: buildCheckoutUrlForInvoice,
|
checkoutUrlForInvoice: buildCheckoutUrlForInvoice,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ export class CbeBillService {
|
|||||||
consented_on: Math.floor(Date.now() / 1000),
|
consented_on: Math.floor(Date.now() / 1000),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ query */
|
/* ------------------------------------------------------------------ query */
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ export enum InvoiceStatus {
|
|||||||
/** Issued and awaiting payment (alias of PENDING for fee invoices). */
|
/** Issued and awaiting payment (alias of PENDING for fee invoices). */
|
||||||
Issued = "ISSUED",
|
Issued = "ISSUED",
|
||||||
Pending = "PENDING",
|
Pending = "PENDING",
|
||||||
|
/** Customer completed provider checkout (success redirect); awaiting webhook confirmation. */
|
||||||
|
PaymentProcessing = "PAYMENT_PROCESSING",
|
||||||
/** Some, but not all, of the balance has been settled. */
|
/** Some, but not all, of the balance has been settled. */
|
||||||
PartiallyPaid = "PARTIALLY_PAID",
|
PartiallyPaid = "PARTIALLY_PAID",
|
||||||
Paid = "PAID",
|
Paid = "PAID",
|
||||||
|
|||||||
Reference in New Issue
Block a user