@voyant-travel/finance 0.189.0 → 0.191.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/card-payment.d.ts +13 -0
- package/dist/card-payment.js +67 -50
- package/dist/checkout-routes.d.ts +2 -0
- package/dist/checkout-routes.js +4 -1
- package/dist/checkout-service-plan.d.ts +2 -0
- package/dist/checkout-service.js +9 -2
- package/dist/checkout-validation.d.ts +3 -3
- package/dist/checkout-validation.js +6 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -2
- package/dist/runtime-contributor.js +2 -2
- package/dist/runtime.d.ts +2 -1
- package/dist/runtime.js +85 -1
- package/dist/stale-booking-holds-runtime.d.ts +2 -2
- package/dist/stale-booking-holds-runtime.js +1 -1
- package/dist/voyant.js +2 -0
- package/package.json +12 -12
package/dist/card-payment.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface CardPaymentStartArgs {
|
|
|
41
41
|
billing: CardPaymentBilling;
|
|
42
42
|
description?: string;
|
|
43
43
|
returnUrl?: string;
|
|
44
|
+
metadata?: Record<string, unknown>;
|
|
44
45
|
}
|
|
45
46
|
/** Result of a card-payment start: the hosted-payment URL to redirect to. */
|
|
46
47
|
export interface CardPaymentStartResult {
|
|
@@ -68,4 +69,16 @@ export interface PaymentAdapterCardPaymentStarterOptions {
|
|
|
68
69
|
*/
|
|
69
70
|
resolveNotifyUrl?(c: Context): string | undefined;
|
|
70
71
|
}
|
|
72
|
+
export interface PaymentAdapterCardPaymentExecution {
|
|
73
|
+
context: PaymentAdapterRuntimeContext;
|
|
74
|
+
runtime?: FinanceServiceRuntime;
|
|
75
|
+
notifyUrl?: string;
|
|
76
|
+
idempotencyKey?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Start a payment through a selected adapter without requiring an HTTP
|
|
80
|
+
* framework context. Package runtimes use this function; the Hono-oriented
|
|
81
|
+
* starter below remains the checkout-surface convenience wrapper.
|
|
82
|
+
*/
|
|
83
|
+
export declare function startPaymentAdapterCardPayment(adapter: PaymentAdapter, args: CardPaymentStartArgs, execution: PaymentAdapterCardPaymentExecution): Promise<CardPaymentStartResult | null>;
|
|
71
84
|
export declare function createPaymentAdapterCardPaymentStarter(adapter: PaymentAdapter, options?: PaymentAdapterCardPaymentStarterOptions): CardPaymentStarter;
|
package/dist/card-payment.js
CHANGED
|
@@ -2,58 +2,75 @@ import { eq } from "drizzle-orm";
|
|
|
2
2
|
import { paymentSessions } from "./schema/payment-sessions.js";
|
|
3
3
|
import { financePaymentSessionCompletionService } from "./service-payment-session-completion.js";
|
|
4
4
|
import { financePaymentSessionService } from "./service-payment-sessions.js";
|
|
5
|
+
/**
|
|
6
|
+
* Start a payment through a selected adapter without requiring an HTTP
|
|
7
|
+
* framework context. Package runtimes use this function; the Hono-oriented
|
|
8
|
+
* starter below remains the checkout-surface convenience wrapper.
|
|
9
|
+
*/
|
|
10
|
+
export async function startPaymentAdapterCardPayment(adapter, args, execution) {
|
|
11
|
+
const [session] = await args.db
|
|
12
|
+
.select()
|
|
13
|
+
.from(paymentSessions)
|
|
14
|
+
.where(eq(paymentSessions.id, args.sessionId))
|
|
15
|
+
.limit(1);
|
|
16
|
+
if (!session)
|
|
17
|
+
return null;
|
|
18
|
+
const idempotencyKey = session.idempotencyKey ?? execution.idempotencyKey ?? `payment:${session.id}`;
|
|
19
|
+
const metadata = {
|
|
20
|
+
...(args.metadata ?? {}),
|
|
21
|
+
billing: args.billing,
|
|
22
|
+
...(execution.notifyUrl ? { notifyUrl: execution.notifyUrl } : {}),
|
|
23
|
+
};
|
|
24
|
+
const result = await adapter.initiate(execution.context, {
|
|
25
|
+
paymentSessionId: session.id,
|
|
26
|
+
money: { amountMinor: session.amountCents, currency: session.currency },
|
|
27
|
+
description: args.description ?? session.notes ?? undefined,
|
|
28
|
+
returnUrl: args.returnUrl ?? session.returnUrl ?? undefined,
|
|
29
|
+
idempotencyKey,
|
|
30
|
+
customer: {
|
|
31
|
+
email: args.billing.email,
|
|
32
|
+
phone: args.billing.phone ?? null,
|
|
33
|
+
firstName: args.billing.firstName,
|
|
34
|
+
lastName: args.billing.lastName ?? null,
|
|
35
|
+
},
|
|
36
|
+
metadata,
|
|
37
|
+
});
|
|
38
|
+
const providerData = {
|
|
39
|
+
providerSessionId: result.processorSessionId ?? undefined,
|
|
40
|
+
providerPaymentId: result.processorPaymentId ?? undefined,
|
|
41
|
+
providerPayload: result.raw === undefined ? undefined : { initiation: result.raw },
|
|
42
|
+
metadata: { paymentAdapterInitiationIdempotencyKey: result.idempotencyKey },
|
|
43
|
+
};
|
|
44
|
+
if (result.nextState === "paid" || result.nextState === "authorized") {
|
|
45
|
+
await financePaymentSessionService.updatePaymentSession(args.db, session.id, {
|
|
46
|
+
provider: adapter.id,
|
|
47
|
+
redirectUrl: result.checkout?.url ?? undefined,
|
|
48
|
+
idempotencyKey,
|
|
49
|
+
});
|
|
50
|
+
await financePaymentSessionCompletionService.completePaymentSession(args.db, session.id, {
|
|
51
|
+
status: result.nextState,
|
|
52
|
+
captureMode: "automatic",
|
|
53
|
+
...providerData,
|
|
54
|
+
}, execution.runtime);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
await financePaymentSessionService.updatePaymentSession(args.db, session.id, {
|
|
58
|
+
provider: adapter.id,
|
|
59
|
+
status: result.nextState,
|
|
60
|
+
redirectUrl: result.checkout?.url ?? undefined,
|
|
61
|
+
idempotencyKey,
|
|
62
|
+
...providerData,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return { redirectUrl: result.checkout?.url ?? null };
|
|
66
|
+
}
|
|
5
67
|
export function createPaymentAdapterCardPaymentStarter(adapter, options = {}) {
|
|
6
68
|
return async (c, args) => {
|
|
7
|
-
|
|
8
|
-
.
|
|
9
|
-
.
|
|
10
|
-
.
|
|
11
|
-
.
|
|
12
|
-
if (!session)
|
|
13
|
-
return null;
|
|
14
|
-
const idempotencyKey = session.idempotencyKey ?? options.idempotencyKey?.(session.id) ?? `payment:${session.id}`;
|
|
15
|
-
const notifyUrl = options.resolveNotifyUrl?.(c);
|
|
16
|
-
const result = await adapter.initiate(options.resolveContext?.(c) ?? { env: c.env }, {
|
|
17
|
-
paymentSessionId: session.id,
|
|
18
|
-
money: { amountMinor: session.amountCents, currency: session.currency },
|
|
19
|
-
description: args.description ?? session.notes ?? undefined,
|
|
20
|
-
returnUrl: args.returnUrl ?? session.returnUrl ?? undefined,
|
|
21
|
-
idempotencyKey,
|
|
22
|
-
customer: {
|
|
23
|
-
email: args.billing.email,
|
|
24
|
-
phone: args.billing.phone ?? null,
|
|
25
|
-
firstName: args.billing.firstName,
|
|
26
|
-
lastName: args.billing.lastName ?? null,
|
|
27
|
-
},
|
|
28
|
-
...(notifyUrl ? { metadata: { notifyUrl } } : {}),
|
|
69
|
+
return startPaymentAdapterCardPayment(adapter, args, {
|
|
70
|
+
context: options.resolveContext?.(c) ?? { env: c.env },
|
|
71
|
+
runtime: options.resolveRuntime?.(c),
|
|
72
|
+
notifyUrl: options.resolveNotifyUrl?.(c),
|
|
73
|
+
idempotencyKey: options.idempotencyKey?.(args.sessionId),
|
|
29
74
|
});
|
|
30
|
-
const providerData = {
|
|
31
|
-
providerSessionId: result.processorSessionId ?? undefined,
|
|
32
|
-
providerPaymentId: result.processorPaymentId ?? undefined,
|
|
33
|
-
providerPayload: result.raw === undefined ? undefined : { initiation: result.raw },
|
|
34
|
-
metadata: { paymentAdapterInitiationIdempotencyKey: result.idempotencyKey },
|
|
35
|
-
};
|
|
36
|
-
if (result.nextState === "paid" || result.nextState === "authorized") {
|
|
37
|
-
await financePaymentSessionService.updatePaymentSession(args.db, session.id, {
|
|
38
|
-
provider: adapter.id,
|
|
39
|
-
redirectUrl: result.checkout?.url ?? undefined,
|
|
40
|
-
idempotencyKey,
|
|
41
|
-
});
|
|
42
|
-
await financePaymentSessionCompletionService.completePaymentSession(args.db, session.id, {
|
|
43
|
-
status: result.nextState,
|
|
44
|
-
captureMode: "automatic",
|
|
45
|
-
...providerData,
|
|
46
|
-
}, options.resolveRuntime?.(c));
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
await financePaymentSessionService.updatePaymentSession(args.db, session.id, {
|
|
50
|
-
provider: adapter.id,
|
|
51
|
-
status: result.nextState,
|
|
52
|
-
redirectUrl: result.checkout?.url ?? undefined,
|
|
53
|
-
idempotencyKey,
|
|
54
|
-
...providerData,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return { redirectUrl: result.checkout?.url ?? null };
|
|
58
75
|
};
|
|
59
76
|
}
|
|
@@ -15,6 +15,7 @@ export type CheckoutRoutesOptions = {
|
|
|
15
15
|
notificationDispatcher?: CheckoutNotificationDispatcher | null;
|
|
16
16
|
resolveNotificationDispatcher?: (bindings: Record<string, unknown>) => CheckoutNotificationDispatcher | null;
|
|
17
17
|
paymentStarters?: Record<string, CheckoutPaymentStarter>;
|
|
18
|
+
resolveSelectedPaymentStarter?: (bindings: Record<string, unknown>) => CheckoutPaymentStarter | null;
|
|
18
19
|
resolvePaymentStarters?: (bindings: Record<string, unknown>) => Record<string, CheckoutPaymentStarter>;
|
|
19
20
|
bankTransferDetails?: CheckoutBankTransferDetails | null;
|
|
20
21
|
resolveBankTransferDetails?: (bindings: Record<string, unknown>) => CheckoutBankTransferDetails | null;
|
|
@@ -31,6 +32,7 @@ export interface CheckoutReminderRunList {
|
|
|
31
32
|
export type CheckoutRouteRuntime = {
|
|
32
33
|
bindings: Record<string, unknown>;
|
|
33
34
|
notificationDispatcher: CheckoutNotificationDispatcher | null;
|
|
35
|
+
selectedPaymentStarter: CheckoutPaymentStarter | null;
|
|
34
36
|
paymentStarters: Record<string, CheckoutPaymentStarter>;
|
|
35
37
|
bankTransferDetails: CheckoutBankTransferDetails | null;
|
|
36
38
|
publicCheckoutBaseUrl?: string | null;
|
package/dist/checkout-routes.js
CHANGED
|
@@ -121,7 +121,9 @@ function resolveCheckoutRouteRuntime(bindings, options, container) {
|
|
|
121
121
|
return buildCheckoutRouteRuntime(bindings, options);
|
|
122
122
|
}
|
|
123
123
|
function assertCheckoutRuntimeSupportsCollection(runtime, input) {
|
|
124
|
-
if (input.method === "card" &&
|
|
124
|
+
if (input.method === "card" &&
|
|
125
|
+
!runtime.selectedPaymentStarter &&
|
|
126
|
+
Object.keys(runtime.paymentStarters).length === 0) {
|
|
125
127
|
throw new CheckoutRouteRuntimeNotConfiguredError();
|
|
126
128
|
}
|
|
127
129
|
}
|
|
@@ -129,6 +131,7 @@ export function buildCheckoutRouteRuntime(bindings, options = {}) {
|
|
|
129
131
|
return {
|
|
130
132
|
bindings,
|
|
131
133
|
notificationDispatcher: options.resolveNotificationDispatcher?.(bindings) ?? options.notificationDispatcher ?? null,
|
|
134
|
+
selectedPaymentStarter: options.resolveSelectedPaymentStarter?.(bindings) ?? null,
|
|
132
135
|
paymentStarters: options.resolvePaymentStarters?.(bindings) ?? options.paymentStarters ?? {},
|
|
133
136
|
bankTransferDetails: options.resolveBankTransferDetails?.(bindings) ?? options.bankTransferDetails ?? null,
|
|
134
137
|
publicCheckoutBaseUrl: options.resolvePublicCheckoutBaseUrl?.(bindings) ?? options.publicCheckoutBaseUrl ?? null,
|
|
@@ -105,6 +105,8 @@ export interface CheckoutRuntimeOptions {
|
|
|
105
105
|
bindings?: Record<string, unknown>;
|
|
106
106
|
bankTransferDetails?: CheckoutBankTransferDetails | null;
|
|
107
107
|
notificationDispatcher?: CheckoutNotificationDispatcher | null;
|
|
108
|
+
/** Deployment-selected PaymentAdapter bridge. Takes precedence over legacy keyed starters. */
|
|
109
|
+
selectedPaymentStarter?: CheckoutPaymentStarter | null;
|
|
108
110
|
paymentStarters?: Record<string, CheckoutPaymentStarter>;
|
|
109
111
|
publicCheckoutBaseUrl?: string | null;
|
|
110
112
|
}
|
package/dist/checkout-service.js
CHANGED
|
@@ -256,9 +256,16 @@ export async function initiateCheckoutCollection(db, bookingId, input, options =
|
|
|
256
256
|
if (!paymentSession) {
|
|
257
257
|
throw new Error("No payment session available for provider start");
|
|
258
258
|
}
|
|
259
|
-
|
|
259
|
+
// Processor selection belongs to the deployment. A selected PaymentAdapter
|
|
260
|
+
// therefore wins even when an older client still sends a provider hint.
|
|
261
|
+
// Keyed starters remain as a compatibility path for self-hosted plugins.
|
|
262
|
+
const requestedProvider = input.startProvider.provider;
|
|
263
|
+
const starter = runtime.selectedPaymentStarter ??
|
|
264
|
+
(requestedProvider ? runtime.paymentStarters?.[requestedProvider] : undefined);
|
|
260
265
|
if (!starter) {
|
|
261
|
-
throw new Error(
|
|
266
|
+
throw new Error(requestedProvider
|
|
267
|
+
? `Payment provider "${requestedProvider}" is not configured`
|
|
268
|
+
: "No payment adapter is selected for card collection");
|
|
262
269
|
}
|
|
263
270
|
providerStart = await starter({
|
|
264
271
|
db,
|
|
@@ -46,7 +46,7 @@ export declare const checkoutReminderTargetTypeSchema: z.ZodEnum<{
|
|
|
46
46
|
booking_cancelled_non_payment: "booking_cancelled_non_payment";
|
|
47
47
|
}>;
|
|
48
48
|
export declare const checkoutProviderStartInputSchema: z.ZodObject<{
|
|
49
|
-
provider: z.ZodString
|
|
49
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
50
50
|
payload: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
51
51
|
}, z.core.$strip>;
|
|
52
52
|
export declare const checkoutNotificationAttachmentSchema: z.ZodObject<{
|
|
@@ -407,7 +407,7 @@ export declare const initiateCheckoutCollectionSchema: z.ZodObject<{
|
|
|
407
407
|
paymentLinkBaseUrl: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
408
408
|
}, z.core.$strip>>;
|
|
409
409
|
startProvider: z.ZodOptional<z.ZodObject<{
|
|
410
|
-
provider: z.ZodString
|
|
410
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
411
411
|
payload: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
412
412
|
}, z.core.$strip>>;
|
|
413
413
|
notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -659,7 +659,7 @@ export declare const bootstrapCheckoutCollectionSchema: z.ZodObject<{
|
|
|
659
659
|
paymentLinkBaseUrl: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
660
660
|
}, z.core.$strip>>;
|
|
661
661
|
startProvider: z.ZodOptional<z.ZodObject<{
|
|
662
|
-
provider: z.ZodString
|
|
662
|
+
provider: z.ZodOptional<z.ZodString>;
|
|
663
663
|
payload: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
664
664
|
}, z.core.$strip>>;
|
|
665
665
|
notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -28,7 +28,12 @@ export const checkoutReminderTargetTypeSchema = z.enum([
|
|
|
28
28
|
"invoice",
|
|
29
29
|
]);
|
|
30
30
|
export const checkoutProviderStartInputSchema = z.object({
|
|
31
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Legacy provider hint. Deployments with a selected PaymentAdapter ignore
|
|
33
|
+
* this value and always use their selected adapter. New clients should omit
|
|
34
|
+
* it so processor selection remains deployment-owned.
|
|
35
|
+
*/
|
|
36
|
+
provider: z.string().min(1).max(255).optional(),
|
|
32
37
|
payload: z.record(z.string(), z.unknown()).optional().nullable(),
|
|
33
38
|
});
|
|
34
39
|
export const checkoutNotificationAttachmentSchema = z
|
package/dist/index.d.ts
CHANGED
|
@@ -28,8 +28,8 @@ export { PAYMENT_ADAPTER_CONTRACT_VERSION, PAYMENT_ADAPTER_RUNTIME_PORT_ID, paym
|
|
|
28
28
|
export { type BookingCancellationSettlementInput, buildPaidBookingCancellationSettlementNote, closeTerminalBookingPaymentSchedules, financeBookingLifecycle, recordPaidBookingCancellationSettlement, } from "./booking-lifecycle.js";
|
|
29
29
|
export { type BookingTaxRouteOptions, type BookingTaxSettings, computeBookingItemTaxLine, createBookingTaxPreviewApiExtension, createBookingTaxPreviewRoutes, createBookingTaxSettingsApiExtension, createBookingTaxSettingsRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxPreviewRoutes, mountBookingTaxSettingsRoutes, type ProductTaxFacts, type ResolveBookingSellTaxRateOptions, type ResolveBookingTaxSettings, type ResolvedBookingSellTaxRate, resolveBookingSellTaxRate, type TaxPolicyCondition, type UpdateBookingTaxSettings, } from "./booking-tax.js";
|
|
30
30
|
export { BOOKING_TAX_PREVIEW_RUNTIME_KEY, BOOKING_TAX_SETTINGS_RUNTIME_KEY, type BookingTaxRuntime, createBookingTaxPreviewVoyantRuntime, createBookingTaxSettingsVoyantRuntime, } from "./booking-tax-runtime.js";
|
|
31
|
-
export type { CardPaymentBilling, CardPaymentStartArgs, CardPaymentStarter, CardPaymentStartResult, PaymentAdapterCardPaymentStarterOptions, } from "./card-payment.js";
|
|
32
|
-
export { createPaymentAdapterCardPaymentStarter } from "./card-payment.js";
|
|
31
|
+
export type { CardPaymentBilling, CardPaymentStartArgs, CardPaymentStarter, CardPaymentStartResult, PaymentAdapterCardPaymentExecution, PaymentAdapterCardPaymentStarterOptions, } from "./card-payment.js";
|
|
32
|
+
export { createPaymentAdapterCardPaymentStarter, startPaymentAdapterCardPayment, } from "./card-payment.js";
|
|
33
33
|
export { type DocumentDownloadEnvelope, type DocumentDownloadResolution, type DocumentDownloadResolver, resolveStoredDocumentDownload, type StoredDocumentReference, } from "./document-download.js";
|
|
34
34
|
export { createInvoiceFxApiExtension, createInvoiceFxRoutes, createVoyantDataFxExchangeRateResolver, type InvoiceExchangeRateResolution, type InvoiceFxContext, type InvoiceFxOptions, type InvoiceFxRouteOptions, type InvoiceFxSettings, mountInvoiceFxRoutes, type ResolvedInvoiceFxSettings, type ResolveInvoiceExchangeRate, type ResolveInvoiceExchangeRateInput, type ResolveInvoiceFxSettings, resolveInvoiceFxContext, resolveInvoiceFxSettingsOrDefault, type UpdateInvoiceFxSettings, type VoyantDataFxResolverOptions, } from "./invoice-fx.js";
|
|
35
35
|
export { type CreateOrderPaymentSessionsOptions, createOrderPaymentSessions, type EnsureOrderSessionParams, type OrderPaymentSessionSummary, type OrderPaymentSessions, type OrderPaymentSessionTargetType, type StartOrderPaymentProvider, } from "./order-payment-sessions.js";
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { registerBookingFinancialLifecycle } from "@voyant-travel/bookings";
|
|
|
4
4
|
import { customFieldsRuntimePort } from "@voyant-travel/core/custom-fields";
|
|
5
5
|
import { defineGraphRuntimeFactory } from "@voyant-travel/core/project";
|
|
6
6
|
import { stampOpenApiRegistryApiId } from "@voyant-travel/hono";
|
|
7
|
+
import { paymentAdapterRuntimePort } from "@voyant-travel/payments";
|
|
7
8
|
import { financeBookingLifecycle } from "./booking-lifecycle.js";
|
|
8
9
|
import { createBookingTaxSettingsRoutes } from "./booking-tax.js";
|
|
9
10
|
import { buildFinanceCheckoutRouteRuntime, createFinanceCheckoutAdminRoutes, createFinanceCheckoutRoutes, FINANCE_CHECKOUT_ROUTE_RUNTIME_CONTAINER_KEY, } from "./checkout-routes.js";
|
|
@@ -68,7 +69,9 @@ export const financeApiModule = createFinanceApiModule();
|
|
|
68
69
|
export const createFinanceVoyantRuntime = defineGraphRuntimeFactory(async ({ api, getPort, getPorts, hasPort }) => {
|
|
69
70
|
const configured = createFinanceApiModule(createFinanceRuntime(await getPort(financeHostRuntimePort), await getPort(customFieldsRuntimePort), await getPort(financeNotificationsRuntimePort), hasPort(financeCheckoutPaymentStartersRuntimePort)
|
|
70
71
|
? await getPort(financeCheckoutPaymentStartersRuntimePort)
|
|
71
|
-
: undefined, await getPorts(financeInvoiceSettlementPollerRuntimePort))
|
|
72
|
+
: undefined, await getPorts(financeInvoiceSettlementPollerRuntimePort), hasPort(paymentAdapterRuntimePort)
|
|
73
|
+
? await getPort(paymentAdapterRuntimePort)
|
|
74
|
+
: undefined));
|
|
72
75
|
const bootstrap = configured.module.bootstrap;
|
|
73
76
|
const selected = {
|
|
74
77
|
module: {
|
|
@@ -91,7 +94,7 @@ export { PAYMENT_ADAPTER_CONTRACT_VERSION, PAYMENT_ADAPTER_RUNTIME_PORT_ID, paym
|
|
|
91
94
|
export { buildPaidBookingCancellationSettlementNote, closeTerminalBookingPaymentSchedules, financeBookingLifecycle, recordPaidBookingCancellationSettlement, } from "./booking-lifecycle.js";
|
|
92
95
|
export { computeBookingItemTaxLine, createBookingTaxPreviewApiExtension, createBookingTaxPreviewRoutes, createBookingTaxSettingsApiExtension, createBookingTaxSettingsRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxPreviewRoutes, mountBookingTaxSettingsRoutes, resolveBookingSellTaxRate, } from "./booking-tax.js";
|
|
93
96
|
export { BOOKING_TAX_PREVIEW_RUNTIME_KEY, BOOKING_TAX_SETTINGS_RUNTIME_KEY, createBookingTaxPreviewVoyantRuntime, createBookingTaxSettingsVoyantRuntime, } from "./booking-tax-runtime.js";
|
|
94
|
-
export { createPaymentAdapterCardPaymentStarter } from "./card-payment.js";
|
|
97
|
+
export { createPaymentAdapterCardPaymentStarter, startPaymentAdapterCardPayment, } from "./card-payment.js";
|
|
95
98
|
export { resolveStoredDocumentDownload, } from "./document-download.js";
|
|
96
99
|
export { createInvoiceFxApiExtension, createInvoiceFxRoutes, createVoyantDataFxExchangeRateResolver, mountInvoiceFxRoutes, resolveInvoiceFxContext, resolveInvoiceFxSettingsOrDefault, } from "./invoice-fx.js";
|
|
97
100
|
export { createOrderPaymentSessions, } from "./order-payment-sessions.js";
|
|
@@ -4,7 +4,7 @@ import { financeAppApiRuntimePort } from "@voyant-travel/finance-contracts/app-a
|
|
|
4
4
|
import { checkFinanceActionLedgerDrift } from "./action-ledger-drift.js";
|
|
5
5
|
import { createFinanceAppApiRuntime } from "./app-api-runtime.js";
|
|
6
6
|
import { financeHostRuntimePort } from "./runtime-port.js";
|
|
7
|
-
import {
|
|
7
|
+
import { createFinanceStaleBookingHoldsJobRuntime } from "./stale-booking-holds-runtime.js";
|
|
8
8
|
/** Provide Finance's generic host input and its narrow Bookings integration. */
|
|
9
9
|
export function createFinanceRuntimePortContribution(host) {
|
|
10
10
|
return {
|
|
@@ -14,7 +14,7 @@ export function createFinanceRuntimePortContribution(host) {
|
|
|
14
14
|
},
|
|
15
15
|
[financeHostRuntimePort.id]: { primitives: host.primitives },
|
|
16
16
|
[bookingsFinanceRuntimePort.id]: {
|
|
17
|
-
|
|
17
|
+
createStaleBookingHoldsJobRuntime: createFinanceStaleBookingHoldsJobRuntime,
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
20
|
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { CustomFieldsRuntime } from "@voyant-travel/core/custom-fields";
|
|
2
|
+
import type { PaymentAdapter } from "@voyant-travel/payments";
|
|
2
3
|
import type { FinanceApiModuleOptions } from "./index.js";
|
|
3
4
|
import type { FinanceAccommodationsPaymentPolicyRuntime, FinanceBookingScheduleRuntime, FinanceCheckoutPaymentStartersRuntime, FinanceCruisesPaymentPolicyRuntime, FinanceDistributionPaymentPolicyRuntime, FinanceHostRuntime, FinanceInventoryPaymentPolicyRuntime, FinanceInvoiceSettlementPollerProvider, FinanceNotificationsRuntime, FinanceOperatorSettingsRuntime } from "./runtime-port.js";
|
|
4
5
|
import type { InvoiceSettlementPoller } from "./service-settlement.js";
|
|
5
6
|
/** Compose Finance's main HTTP runtime from generic host and selected providers. */
|
|
6
|
-
export declare function createFinanceRuntime(host: FinanceHostRuntime, customFields: CustomFieldsRuntime, notifications: FinanceNotificationsRuntime, checkoutPaymentStarters?: FinanceCheckoutPaymentStartersRuntime, invoiceSettlementPollerProviders?: readonly FinanceInvoiceSettlementPollerProvider[]): FinanceApiModuleOptions;
|
|
7
|
+
export declare function createFinanceRuntime(host: FinanceHostRuntime, customFields: CustomFieldsRuntime, notifications: FinanceNotificationsRuntime, checkoutPaymentStarters?: FinanceCheckoutPaymentStartersRuntime, invoiceSettlementPollerProviders?: readonly FinanceInvoiceSettlementPollerProvider[], selectedPaymentAdapter?: PaymentAdapter): FinanceApiModuleOptions;
|
|
7
8
|
/** Compose Finance's payment schedule from statically selected domain providers. */
|
|
8
9
|
export declare function createFinanceBookingScheduleRuntime(host: FinanceHostRuntime, settings: FinanceOperatorSettingsRuntime, distribution: FinanceDistributionPaymentPolicyRuntime, accommodations: FinanceAccommodationsPaymentPolicyRuntime, cruises: FinanceCruisesPaymentPolicyRuntime, inventory: FinanceInventoryPaymentPolicyRuntime): FinanceBookingScheduleRuntime;
|
|
9
10
|
export declare function createFinanceBookingTaxRuntime(settings: FinanceOperatorSettingsRuntime): FinanceApiModuleOptions;
|
package/dist/runtime.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { startPaymentAdapterCardPayment } from "./card-payment.js";
|
|
1
2
|
import { createVoyantDataFxExchangeRateResolver, } from "./invoice-fx.js";
|
|
3
|
+
import { financeService } from "./service.js";
|
|
2
4
|
/** Compose Finance's main HTTP runtime from generic host and selected providers. */
|
|
3
|
-
export function createFinanceRuntime(host, customFields, notifications, checkoutPaymentStarters, invoiceSettlementPollerProviders = []) {
|
|
5
|
+
export function createFinanceRuntime(host, customFields, notifications, checkoutPaymentStarters, invoiceSettlementPollerProviders = [], selectedPaymentAdapter) {
|
|
4
6
|
const { primitives } = host;
|
|
5
7
|
return {
|
|
6
8
|
resolveDocumentDownloadUrl: primitives.storage.downloadUrl,
|
|
@@ -18,11 +20,93 @@ export function createFinanceRuntime(host, customFields, notifications, checkout
|
|
|
18
20
|
invoiceDueDateResolver: ({ issueDate, dueDate, bookingPaymentSchedule }) => bookingPaymentSchedule && dueDate < issueDate ? issueDate : dueDate,
|
|
19
21
|
resolveNotificationDispatcher: notifications.resolveNotificationDispatcher,
|
|
20
22
|
resolvePaymentStarters: (bindings) => checkoutPaymentStarters?.resolvePaymentStarters(bindings) ?? {},
|
|
23
|
+
resolveSelectedPaymentStarter: selectedPaymentAdapter
|
|
24
|
+
? (bindings) => createSelectedPaymentAdapterStarter(host, selectedPaymentAdapter, bindings)
|
|
25
|
+
: undefined,
|
|
21
26
|
resolveBankTransferDetails: (bindings) => resolveBankTransferDetails(primitives.env(bindings)),
|
|
22
27
|
resolvePublicCheckoutBaseUrl: (bindings) => resolvePublicCheckoutBaseUrl(primitives.env(bindings)),
|
|
23
28
|
listBookingReminderRuns: notifications.listBookingReminderRuns,
|
|
24
29
|
};
|
|
25
30
|
}
|
|
31
|
+
function createSelectedPaymentAdapterStarter(host, adapter, bindings) {
|
|
32
|
+
return async (checkout) => {
|
|
33
|
+
const payload = checkout.startProvider.payload ?? {};
|
|
34
|
+
const billing = readCardPaymentBilling(payload.billing);
|
|
35
|
+
const env = host.primitives.env(bindings);
|
|
36
|
+
const started = await startPaymentAdapterCardPayment(adapter, {
|
|
37
|
+
db: checkout.db,
|
|
38
|
+
sessionId: checkout.paymentSession.id,
|
|
39
|
+
billing,
|
|
40
|
+
description: stringValue(payload.description),
|
|
41
|
+
returnUrl: stringValue(payload.returnUrl) ?? checkout.paymentSession.returnUrl ?? undefined,
|
|
42
|
+
metadata: recordValue(payload.metadata),
|
|
43
|
+
}, {
|
|
44
|
+
context: { env },
|
|
45
|
+
notifyUrl: resolvePaymentCallbackUrl(env),
|
|
46
|
+
});
|
|
47
|
+
const session = (await financeService.getPaymentSessionById(checkout.db, checkout.paymentSession.id)) ??
|
|
48
|
+
checkout.paymentSession;
|
|
49
|
+
return {
|
|
50
|
+
provider: adapter.id,
|
|
51
|
+
paymentSessionId: session.id,
|
|
52
|
+
redirectUrl: started?.redirectUrl ?? null,
|
|
53
|
+
externalReference: session.externalReference,
|
|
54
|
+
providerSessionId: session.providerSessionId,
|
|
55
|
+
providerPaymentId: session.providerPaymentId,
|
|
56
|
+
response: null,
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function readCardPaymentBilling(value) {
|
|
61
|
+
const billing = recordValue(value);
|
|
62
|
+
const email = nonEmpty(billing.email);
|
|
63
|
+
const firstName = nonEmpty(billing.firstName);
|
|
64
|
+
if (!email || !firstName) {
|
|
65
|
+
throw new Error("Card payment billing requires email and firstName");
|
|
66
|
+
}
|
|
67
|
+
const phone = nonEmpty(billing.phone);
|
|
68
|
+
const lastName = nonEmpty(billing.lastName);
|
|
69
|
+
const city = nonEmpty(billing.city);
|
|
70
|
+
const country = typeof billing.country === "number" || typeof billing.country === "string"
|
|
71
|
+
? billing.country
|
|
72
|
+
: undefined;
|
|
73
|
+
const state = nonEmpty(billing.state);
|
|
74
|
+
const postalCode = nonEmpty(billing.postalCode);
|
|
75
|
+
const details = nonEmpty(billing.details);
|
|
76
|
+
return {
|
|
77
|
+
email,
|
|
78
|
+
firstName,
|
|
79
|
+
...(phone ? { phone } : {}),
|
|
80
|
+
...(lastName ? { lastName } : {}),
|
|
81
|
+
...(city ? { city } : {}),
|
|
82
|
+
...(country !== undefined ? { country } : {}),
|
|
83
|
+
...(state ? { state } : {}),
|
|
84
|
+
...(postalCode ? { postalCode } : {}),
|
|
85
|
+
...(details ? { details } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function recordValue(value) {
|
|
89
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
90
|
+
? value
|
|
91
|
+
: {};
|
|
92
|
+
}
|
|
93
|
+
function resolvePaymentCallbackUrl(env) {
|
|
94
|
+
const configured = nonEmpty(env.PAYMENT_CALLBACK_BASE_URL) ??
|
|
95
|
+
nonEmpty(env.DASH_BASE_URL) ??
|
|
96
|
+
nonEmpty(env.APP_URL)?.replace(/\/api\/?$/, "");
|
|
97
|
+
if (!configured)
|
|
98
|
+
return undefined;
|
|
99
|
+
const url = new URL(configured);
|
|
100
|
+
if ((url.protocol !== "http:" && url.protocol !== "https:") ||
|
|
101
|
+
url.username ||
|
|
102
|
+
url.password ||
|
|
103
|
+
url.pathname !== "/" ||
|
|
104
|
+
url.search ||
|
|
105
|
+
url.hash) {
|
|
106
|
+
throw new Error("Payment callback base must be an absolute HTTP(S) origin");
|
|
107
|
+
}
|
|
108
|
+
return `${url.origin}/api/v1/public/payment-link/callback`;
|
|
109
|
+
}
|
|
26
110
|
/** Compose Finance's payment schedule from statically selected domain providers. */
|
|
27
111
|
export function createFinanceBookingScheduleRuntime(host, settings, distribution, accommodations, cruises, inventory) {
|
|
28
112
|
const paymentPolicy = inventory.createPaymentPolicyRuntime({
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BookingsExpireStaleHoldsJobRuntime } from "@voyant-travel/bookings/job-runtime";
|
|
2
2
|
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
3
|
export interface FinanceStaleBookingHoldsRuntimeOptions {
|
|
4
4
|
resolveDb: () => PostgresJsDatabase | Promise<PostgresJsDatabase>;
|
|
5
5
|
userId?: string;
|
|
6
6
|
}
|
|
7
7
|
/** Finance-owned effects required when Bookings expires stale holds. */
|
|
8
|
-
export declare function
|
|
8
|
+
export declare function createFinanceStaleBookingHoldsJobRuntime(options: FinanceStaleBookingHoldsRuntimeOptions): BookingsExpireStaleHoldsJobRuntime;
|
|
@@ -3,7 +3,7 @@ import { closeTerminalBookingPaymentSchedules } from "./booking-lifecycle.js";
|
|
|
3
3
|
import { paymentSessions } from "./schema.js";
|
|
4
4
|
import { financeService } from "./service.js";
|
|
5
5
|
/** Finance-owned effects required when Bookings expires stale holds. */
|
|
6
|
-
export function
|
|
6
|
+
export function createFinanceStaleBookingHoldsJobRuntime(options) {
|
|
7
7
|
return {
|
|
8
8
|
resolveDb: options.resolveDb,
|
|
9
9
|
resolveRuntime: () => ({
|
package/dist/voyant.js
CHANGED
|
@@ -8,6 +8,7 @@ import { financeReceivablesDatasetDefinition, financeReportingTemplates, finance
|
|
|
8
8
|
import { financeAccommodationsPaymentPolicyRuntimePort, financeCheckoutPaymentStartersRuntimePort, financeCruisesPaymentPolicyRuntimePort, financeDistributionPaymentPolicyRuntimePort, financeHostRuntimePort, financeInventoryPaymentPolicyRuntimePort, financeInvoiceSettlementPollerRuntimePort, financeNotificationsRuntimePort, financeOperatorSettingsRuntimePort, } from "./runtime-port.js";
|
|
9
9
|
import { financeVoyantAdmin } from "./voyant-admin.js";
|
|
10
10
|
import { bookingContractDocumentRequestedPayloadSchema, bookingCreatedPayloadSchema, bookingCreateRejectedPayloadSchema, bookingDualCreatedPayloadSchema, bookingPaymentSchedulePaidPayloadSchema, invoiceDocumentGeneratedPayloadSchema, invoiceIssuanceExternalPayloadSchema, invoicePaymentRecordedExternalPayloadSchema, invoiceProformaConvertedExternalPayloadSchema, invoiceRenderedPayloadSchema, invoiceSettledPayloadSchema, invoiceVoidedExternalPayloadSchema, paymentCompletedPayloadSchema, } from "./voyant-event-schemas.js";
|
|
11
|
+
const paymentAdapterRuntimePortReference = { id: "payments.adapter.runtime" };
|
|
11
12
|
/** Import-cheap deployment declaration owned by the finance package. */
|
|
12
13
|
export const financeVoyantModule = defineModule({
|
|
13
14
|
id: "@voyant-travel/finance",
|
|
@@ -19,6 +20,7 @@ export const financeVoyantModule = defineModule({
|
|
|
19
20
|
requirePort(customFieldsRuntimePort),
|
|
20
21
|
requirePort(financeNotificationsRuntimePort),
|
|
21
22
|
requirePort(financeCheckoutPaymentStartersRuntimePort, { optional: true }),
|
|
23
|
+
{ ...paymentAdapterRuntimePortReference, optional: true },
|
|
22
24
|
requirePort(financeInvoiceSettlementPollerRuntimePort, {
|
|
23
25
|
optional: true,
|
|
24
26
|
cardinality: "many",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/finance",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.191.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -156,24 +156,24 @@
|
|
|
156
156
|
"fflate": "^0.8.2",
|
|
157
157
|
"hono": "^4.12.27",
|
|
158
158
|
"zod": "^4.4.3",
|
|
159
|
-
"@voyant-travel/action-ledger": "^0.111.
|
|
160
|
-
"@voyant-travel/bookings": "^0.
|
|
161
|
-
"@voyant-travel/core": "^0.
|
|
162
|
-
"@voyant-travel/db": "^0.
|
|
163
|
-
"@voyant-travel/types": "^0.109.
|
|
159
|
+
"@voyant-travel/action-ledger": "^0.111.13",
|
|
160
|
+
"@voyant-travel/bookings": "^0.191.0",
|
|
161
|
+
"@voyant-travel/core": "^0.131.0",
|
|
162
|
+
"@voyant-travel/db": "^0.118.0",
|
|
163
|
+
"@voyant-travel/types": "^0.109.9",
|
|
164
164
|
"@voyant-travel/finance-contracts": "^0.107.1",
|
|
165
|
-
"@voyant-travel/hono": "^0.
|
|
166
|
-
"@voyant-travel/payments": "^0.5.
|
|
167
|
-
"@voyant-travel/public-document-delivery": "^0.4.
|
|
168
|
-
"@voyant-travel/reporting-contracts": "^0.3.
|
|
169
|
-
"@voyant-travel/storage": "^0.113.
|
|
165
|
+
"@voyant-travel/hono": "^0.134.0",
|
|
166
|
+
"@voyant-travel/payments": "^0.5.2",
|
|
167
|
+
"@voyant-travel/public-document-delivery": "^0.4.11",
|
|
168
|
+
"@voyant-travel/reporting-contracts": "^0.3.1",
|
|
169
|
+
"@voyant-travel/storage": "^0.113.2",
|
|
170
170
|
"@voyant-travel/utils": "^0.109.0",
|
|
171
171
|
"@voyant-travel/tools": "^0.3.0"
|
|
172
172
|
},
|
|
173
173
|
"devDependencies": {
|
|
174
174
|
"drizzle-kit": "^0.31.10",
|
|
175
175
|
"typescript": "^6.0.3",
|
|
176
|
-
"@voyant-travel/webhook-delivery": "^0.4.
|
|
176
|
+
"@voyant-travel/webhook-delivery": "^0.4.8",
|
|
177
177
|
"@voyant-travel/voyant-typescript-config": "^0.1.0"
|
|
178
178
|
},
|
|
179
179
|
"files": [
|