@voyant-travel/finance 0.120.2 → 0.122.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.
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Provider-agnostic card-payment seam.
3
+ *
4
+ * Finance defines the neutral contract a deployment's chosen card processor
5
+ * implements; checkout surfaces (flights, trips checkout, payment links,
6
+ * catalog) route card payments through a single `CardPaymentStarter` rather
7
+ * than importing any specific provider. The Netopia (or Stripe/Adyen/…)
8
+ * implementation lives in the provider's own package — finance never names a
9
+ * processor.
10
+ *
11
+ * Returning `null` from a starter means "this processor isn't configured" so
12
+ * callers fall back gracefully (bank-transfer paths still work).
13
+ */
14
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
15
+ import type { Context } from "hono";
16
+ /**
17
+ * Billing details a card processor needs to start a hosted payment.
18
+ *
19
+ * Field names are kept structurally compatible with a provider's own billing
20
+ * shape (e.g. Netopia's `NetopiaBillingAddress`) so callers' existing billing
21
+ * objects satisfy this without reshaping. `country` accepts a numeric code or
22
+ * ISO string depending on the processor.
23
+ */
24
+ export interface CardPaymentBilling {
25
+ email: string;
26
+ phone?: string;
27
+ firstName: string;
28
+ lastName?: string;
29
+ city?: string;
30
+ country?: number | string;
31
+ state?: string;
32
+ postalCode?: string;
33
+ details?: string;
34
+ }
35
+ /** Arguments a caller maps from its checkout surface to start a card payment. */
36
+ export interface CardPaymentStartArgs {
37
+ db: PostgresJsDatabase;
38
+ sessionId: string;
39
+ billing: CardPaymentBilling;
40
+ description?: string;
41
+ returnUrl?: string;
42
+ }
43
+ /** Result of a card-payment start: the hosted-payment URL to redirect to. */
44
+ export interface CardPaymentStartResult {
45
+ redirectUrl: string | null;
46
+ }
47
+ /**
48
+ * The neutral card-payment starter contract. A deployment selects exactly one
49
+ * implementation (its chosen processor) and every checkout surface routes
50
+ * through it.
51
+ *
52
+ * `c` carries the request env + container so a processor can resolve its own
53
+ * request-scoped runtime. Returning `null` means "this processor isn't
54
+ * configured" — callers fall back (bank transfer still works).
55
+ */
56
+ export type CardPaymentStarter = (c: Context, args: CardPaymentStartArgs) => Promise<CardPaymentStartResult | null>;
57
+ //# sourceMappingURL=card-payment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card-payment.d.ts","sourceRoot":"","sources":["../src/card-payment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,iFAAiF;AACjF,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,kBAAkB,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,kBAAkB,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;CAC3B;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAC/B,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,oBAAoB,KACvB,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -31,10 +31,14 @@ export interface FinanceHonoModuleOptions extends FinanceRuntimeOptions, PublicF
31
31
  export declare function createFinanceHonoModule(options?: FinanceHonoModuleOptions): HonoModule;
32
32
  export declare const financeHonoModule: HonoModule;
33
33
  export { type BookingTaxRouteOptions, type BookingTaxSettings, computeBookingItemTaxLine, createBookingTaxHonoExtension, createBookingTaxRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxRoutes, type ProductTaxFacts, type ResolveBookingSellTaxRateOptions, type ResolveBookingTaxSettings, type ResolvedBookingSellTaxRate, resolveBookingSellTaxRate, type TaxPolicyCondition, type UpdateBookingTaxSettings, } from "./booking-tax.js";
34
+ export type { CardPaymentBilling, CardPaymentStartArgs, CardPaymentStarter, CardPaymentStartResult, } from "./card-payment.js";
34
35
  export { type DocumentDownloadEnvelope, type DocumentDownloadResolution, type DocumentDownloadResolver, resolveStoredDocumentDownload, type StoredDocumentReference, } from "./document-download.js";
35
36
  export { createInvoiceFxHonoExtension, 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";
37
+ export { type CreateOrderPaymentSessionsOptions, createOrderPaymentSessions, type EnsureOrderSessionParams, type OrderPaymentSessionSummary, type OrderPaymentSessions, type OrderPaymentSessionTargetType, type StartOrderPaymentProvider, } from "./order-payment-sessions.js";
36
38
  export type { ComputedScheduleEntry, ComputeScheduleInput, DepositKind, DepositRule, PaymentPolicy, PaymentPolicyCascadeLayers, PaymentPolicySource, PaymentScheduleEntryType, ResolvedPaymentPolicy, } from "./payment-policy.js";
37
39
  export { computePaymentSchedule, isPaymentPolicyEmpty, noDepositPolicy, policyShouldRequireFullPayment, resolveEffectivePaymentPolicy, } from "./payment-policy.js";
40
+ export { createPaymentPolicyCascade, type PaymentPolicyCascade, type PaymentPolicyCascadeOptions, type PaymentPolicyCascadeReaders, readPolicySourceFromInternalNotes, stampPolicySourceOnBooking, } from "./payment-policy-cascade.js";
41
+ export { type BookingScheduleRoutesOptions, createBookingScheduleAdminRoutes, createPaymentPolicyPublicRoutes, generatePaymentScheduleForBooking, type PaymentPolicyEntityContext, } from "./payment-schedule/routes.js";
38
42
  export { buildFinanceRouteRuntime, FINANCE_ROUTE_RUNTIME_CONTAINER_KEY, type FinanceRouteRuntime, type FinanceRuntimeOptions, } from "./route-runtime.js";
39
43
  export { bookingsCreateExtension } from "./routes-booking-create.js";
40
44
  export { createFinanceAdminDocumentRoutes, type FinanceDocumentRouteOptions, type InvoiceDocumentGenerator, } from "./routes-documents.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -88,7 +88,10 @@ export const financeHonoModule = createFinanceHonoModule();
88
88
  export { computeBookingItemTaxLine, createBookingTaxHonoExtension, createBookingTaxRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxRoutes, resolveBookingSellTaxRate, } from "./booking-tax.js";
89
89
  export { resolveStoredDocumentDownload, } from "./document-download.js";
90
90
  export { createInvoiceFxHonoExtension, createInvoiceFxRoutes, createVoyantDataFxExchangeRateResolver, mountInvoiceFxRoutes, resolveInvoiceFxContext, resolveInvoiceFxSettingsOrDefault, } from "./invoice-fx.js";
91
+ export { createOrderPaymentSessions, } from "./order-payment-sessions.js";
91
92
  export { computePaymentSchedule, isPaymentPolicyEmpty, noDepositPolicy, policyShouldRequireFullPayment, resolveEffectivePaymentPolicy, } from "./payment-policy.js";
93
+ export { createPaymentPolicyCascade, readPolicySourceFromInternalNotes, stampPolicySourceOnBooking, } from "./payment-policy-cascade.js";
94
+ export { createBookingScheduleAdminRoutes, createPaymentPolicyPublicRoutes, generatePaymentScheduleForBooking, } from "./payment-schedule/routes.js";
92
95
  export { buildFinanceRouteRuntime, FINANCE_ROUTE_RUNTIME_CONTAINER_KEY, } from "./route-runtime.js";
93
96
  export { bookingsCreateExtension } from "./routes-booking-create.js";
94
97
  export { createFinanceAdminDocumentRoutes, } from "./routes-documents.js";
@@ -0,0 +1,69 @@
1
+ import type { CreatePaymentSessionInput, PostgresJsDatabase } from "./service-shared.js";
2
+ /** Target types finance recognises for external order payment sessions. */
3
+ export type OrderPaymentSessionTargetType = CreatePaymentSessionInput["targetType"];
4
+ /** A resolved payment session for an external order. */
5
+ export interface OrderPaymentSessionSummary {
6
+ sessionId: string;
7
+ status: string;
8
+ }
9
+ /** Parameters the caller maps from its domain object to create/find a session. */
10
+ export interface EnsureOrderSessionParams {
11
+ /** The external order id (becomes `payment_sessions.target_id`). */
12
+ targetId: string;
13
+ /** ISO 4217 currency code. */
14
+ currency: string;
15
+ /** Amount in minor units (cents). A non-positive amount short-circuits. */
16
+ amountCents: number;
17
+ /** Payer email for the session, when known. */
18
+ payerEmail?: string | null;
19
+ /** Payer display name for the session, when known. */
20
+ payerName?: string | null;
21
+ /** Human summary surfaced as `payment_sessions.notes`. */
22
+ notes?: string | null;
23
+ }
24
+ /**
25
+ * Best-effort provider start hook. Called after a session is created so the
26
+ * provider can populate `redirectUrl`. Failures are swallowed (logged) — the
27
+ * session still exists for non-card payment paths.
28
+ */
29
+ export type StartOrderPaymentProvider = (db: PostgresJsDatabase, sessionId: string) => Promise<void>;
30
+ export interface OrderPaymentSessions {
31
+ /**
32
+ * Ensure (idempotently) a payment session exists for an external order.
33
+ *
34
+ * Precedence: the most recent non-terminal session (a live link) wins; else a
35
+ * paid/authorized session from history; else create a fresh `pending` session
36
+ * via `financeService.createPaymentSession` and optionally start the provider.
37
+ * Returns `null` when the amount is non-positive.
38
+ */
39
+ ensureSession(db: PostgresJsDatabase, params: EnsureOrderSessionParams, startProvider?: StartOrderPaymentProvider): Promise<OrderPaymentSessionSummary | null>;
40
+ /**
41
+ * Bulk-resolve the most relevant session per order id (no N+1). Two passes:
42
+ * first the most recent non-terminal session per order, then fall back to the
43
+ * latest (terminal) session for status.
44
+ */
45
+ fetchSessions(db: PostgresJsDatabase, targetIds: string[]): Promise<Map<string, OrderPaymentSessionSummary>>;
46
+ }
47
+ export interface CreateOrderPaymentSessionsOptions {
48
+ /** The `payment_sessions.target_type` this instance scopes all reads/writes to. */
49
+ targetType: OrderPaymentSessionTargetType;
50
+ /**
51
+ * Provider to stamp on newly-created sessions. Defaults to `null` (no provider)
52
+ * so the session stays provider-agnostic — the injected `startProvider` claims
53
+ * it when it runs (e.g. Netopia sets `provider: "netopia"` on start). Set this
54
+ * only when the deployment wants the provider recorded up front. Never hard-code
55
+ * a provider here: that would mislabel Stripe/Adyen/bank-transfer deployments.
56
+ */
57
+ provider?: string | null;
58
+ /**
59
+ * Payment method to stamp on newly-created sessions. Defaults to `null` (unset)
60
+ * until a payment path is chosen.
61
+ */
62
+ paymentMethod?: CreatePaymentSessionInput["paymentMethod"] | null;
63
+ }
64
+ /**
65
+ * Build an {@link OrderPaymentSessions} bound to a single `targetType`
66
+ * (e.g. `"flight_order"`). All queries are scoped to that target type.
67
+ */
68
+ export declare function createOrderPaymentSessions(options: CreateOrderPaymentSessionsOptions): OrderPaymentSessions;
69
+ //# sourceMappingURL=order-payment-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order-payment-sessions.d.ts","sourceRoot":"","sources":["../src/order-payment-sessions.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAExF,2EAA2E;AAC3E,MAAM,MAAM,6BAA6B,GAAG,yBAAyB,CAAC,YAAY,CAAC,CAAA;AAEnF,wDAAwD;AACxD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,kFAAkF;AAClF,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAA;IACnB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAOpG,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,aAAa,CACX,EAAE,EAAE,kBAAkB,EACtB,MAAM,EAAE,wBAAwB,EAChC,aAAa,CAAC,EAAE,yBAAyB,GACxC,OAAO,CAAC,0BAA0B,GAAG,IAAI,CAAC,CAAA;IAC7C;;;;OAIG;IACH,aAAa,CACX,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAA;CACpD;AAED,MAAM,WAAW,iCAAiC;IAChD,mFAAmF;IACnF,UAAU,EAAE,6BAA6B,CAAA;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,yBAAyB,CAAC,eAAe,CAAC,GAAG,IAAI,CAAA;CAClE;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iCAAiC,GACzC,oBAAoB,CAuFtB"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Generic order payment-session orchestration.
3
+ *
4
+ * Finance owns the `payment_sessions` table, so the "ensure a live session for
5
+ * an external order, else reuse paid history, else create one and best-effort
6
+ * start the provider" pattern lives here — generic over `targetType` rather than
7
+ * baked into any one caller (flights, etc.). The caller maps its domain object
8
+ * to the small `EnsureOrderSessionParams` shape and supplies an optional
9
+ * provider-start callback.
10
+ *
11
+ * This module imports NO upstream module (flights/bookings/etc.) — it only
12
+ * touches finance's own schema + service. Callers depend on finance; finance
13
+ * never depends on them.
14
+ */
15
+ import { and, desc, eq, inArray } from "drizzle-orm";
16
+ import { paymentSessions } from "./schema.js";
17
+ import { financeService } from "./service.js";
18
+ /** Statuses that are terminal/dead for "is there a live session?" purposes. */
19
+ const TERMINAL_STATUSES = ["failed", "expired", "cancelled"];
20
+ /** Statuses worth surfacing from history even when no live session exists. */
21
+ const SETTLED_STATUSES = ["paid", "authorized"];
22
+ /**
23
+ * Build an {@link OrderPaymentSessions} bound to a single `targetType`
24
+ * (e.g. `"flight_order"`). All queries are scoped to that target type.
25
+ */
26
+ export function createOrderPaymentSessions(options) {
27
+ const { targetType, provider = null, paymentMethod = null } = options;
28
+ return {
29
+ async ensureSession(db, params, startProvider) {
30
+ // Prefer the most recent non-terminal session for this order so the UI
31
+ // surfaces a live link; fall back to paid/authorized history.
32
+ const existing = await db
33
+ .select()
34
+ .from(paymentSessions)
35
+ .where(and(eq(paymentSessions.targetId, params.targetId), eq(paymentSessions.targetType, targetType)))
36
+ .orderBy(desc(paymentSessions.createdAt));
37
+ const live = existing.find((row) => !TERMINAL_STATUSES.includes(row.status));
38
+ if (live)
39
+ return { sessionId: live.id, status: live.status };
40
+ const latest = existing[0];
41
+ if (latest && SETTLED_STATUSES.includes(latest.status)) {
42
+ return { sessionId: latest.id, status: latest.status };
43
+ }
44
+ if (params.amountCents <= 0)
45
+ return null;
46
+ const session = await financeService.createPaymentSession(db, {
47
+ targetType,
48
+ targetId: params.targetId,
49
+ currency: params.currency,
50
+ amountCents: params.amountCents,
51
+ status: "pending",
52
+ provider,
53
+ paymentMethod,
54
+ payerEmail: params.payerEmail ?? null,
55
+ payerName: params.payerName ?? null,
56
+ notes: params.notes ?? null,
57
+ });
58
+ if (!session)
59
+ return null;
60
+ // Start the provider so `redirectUrl` is populated for the landing page's
61
+ // card tab. Best-effort — other payment paths still work if it fails.
62
+ if (startProvider) {
63
+ try {
64
+ await startProvider(db, session.id);
65
+ }
66
+ catch (err) {
67
+ console.warn("[finance] order payment provider start failed:", err);
68
+ }
69
+ }
70
+ return { sessionId: session.id, status: session.status };
71
+ },
72
+ async fetchSessions(db, targetIds) {
73
+ const result = new Map();
74
+ if (targetIds.length === 0)
75
+ return result;
76
+ const rows = await db
77
+ .select({
78
+ id: paymentSessions.id,
79
+ targetId: paymentSessions.targetId,
80
+ status: paymentSessions.status,
81
+ createdAt: paymentSessions.createdAt,
82
+ })
83
+ .from(paymentSessions)
84
+ .where(and(eq(paymentSessions.targetType, targetType), inArray(paymentSessions.targetId, targetIds)))
85
+ .orderBy(desc(paymentSessions.createdAt));
86
+ // First pass — most recent non-terminal session per order.
87
+ for (const row of rows) {
88
+ if (!row.targetId || result.has(row.targetId))
89
+ continue;
90
+ if (!TERMINAL_STATUSES.includes(row.status)) {
91
+ result.set(row.targetId, { sessionId: row.id, status: row.status });
92
+ }
93
+ }
94
+ // Second pass — fall back to the latest (terminal) session for status.
95
+ for (const row of rows) {
96
+ if (!row.targetId || result.has(row.targetId))
97
+ continue;
98
+ result.set(row.targetId, { sessionId: row.id, status: row.status });
99
+ }
100
+ return result;
101
+ },
102
+ };
103
+ }
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Multi-vertical payment-policy cascade — owned by `@voyant-travel/finance`.
3
+ *
4
+ * Finance owns the `PaymentPolicy` primitive and the most-specific-wins cascade
5
+ * (`resolveEffectivePaymentPolicy`: booking → listing → category → supplier →
6
+ * operator default). This module packages the *cascade orchestration* + the
7
+ * policy-source bookkeeping so no deployment recreates it: the supplier /
8
+ * category / listing layers, the per-entity storefront-preview variant, and the
9
+ * `__payment_policy_source__:` marker protocol stamped onto a booking's
10
+ * `internalNotes`.
11
+ *
12
+ * WHY THE VERTICAL READERS ARE INJECTED (not imported):
13
+ *
14
+ * The actual schema walks the cascade performs — supplier policy off the
15
+ * booking's supplier link, category policy off `product_categories`, and the
16
+ * per-listing policy off accommodation rate plans / cruise cabin→sailing→cruise
17
+ * layers / product rows — read tables in `@voyant-travel/inventory`,
18
+ * `@voyant-travel/accommodations`, `@voyant-travel/cruises`, and
19
+ * `@voyant-travel/distribution`. Finance is a retail-spine root and the spine
20
+ * closure gate HARD-FORBIDS finance from depending on `@voyant-travel/inventory`
21
+ * / `@voyant-travel/products` (and `@voyant-travel/accommodations` transitively
22
+ * reaches the forbidden `@voyant-travel/operations`). So those reads MUST stay
23
+ * in the deployment and are injected here as `options.readers` rather than
24
+ * imported. The cascade *order*, the per-entity fan-out, and the source-marker
25
+ * protocol are vertical-agnostic framework logic and live here.
26
+ *
27
+ * The `bookings` schema reads (stamp/read the source marker) ARE imported
28
+ * directly: finance already depends on `@voyant-travel/bookings` acyclically
29
+ * (bookings never depends back on finance).
30
+ */
31
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
32
+ import type { PaymentPolicy, PaymentPolicySource } from "./payment-policy.js";
33
+ /**
34
+ * Storefront-preview entity context passed to the per-entity cascade readers.
35
+ * Mirrors the journey-level selections a customer makes before a booking row
36
+ * exists — the readers walk these to find the listing / category / supplier
37
+ * policy.
38
+ */
39
+ export interface PaymentPolicyEntityContext {
40
+ entityModule: string;
41
+ entityId: string;
42
+ /** Cruise journey selection — resolves cabin → sailing → cruise. */
43
+ sailingId?: string;
44
+ cabinCategoryId?: string;
45
+ /** Accommodation journey selection — resolves the rate plan's policy. */
46
+ ratePlanId?: string;
47
+ }
48
+ /**
49
+ * Deployment-supplied vertical readers for the cascade. Each returns the raw
50
+ * per-layer policy override (or `null` to inherit from the next-broader layer).
51
+ *
52
+ * These are INJECTED because they read across vertical modules (inventory /
53
+ * accommodations / cruises / distribution) that finance must not statically
54
+ * import. The cascade ordering that composes them is framework logic and stays
55
+ * in finance.
56
+ */
57
+ export interface PaymentPolicyCascadeReaders {
58
+ /** Supplier-layer override keyed off the booking's supplier link. */
59
+ resolveSupplierPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
60
+ /** Product-category override (first category by sortOrder) for the booking. */
61
+ resolveCategoryPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
62
+ /** Per-listing override (cruise / accommodation / product) for the booking. */
63
+ resolveListingPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
64
+ /** Per-entity (storefront preview) supplier-layer reader. */
65
+ resolveSupplierPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
66
+ /** Per-entity (storefront preview) category-layer reader. */
67
+ resolveCategoryPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
68
+ /** Per-entity (storefront preview) listing-layer reader. */
69
+ resolveListingPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
70
+ }
71
+ /** Options for {@link createPaymentPolicyCascade}. */
72
+ export interface PaymentPolicyCascadeOptions {
73
+ /** The deployment-supplied vertical readers (see above). */
74
+ readers: PaymentPolicyCascadeReaders;
75
+ }
76
+ /**
77
+ * The resolver surface produced by {@link createPaymentPolicyCascade}. Mirrors
78
+ * the function names deployments wire into the booking-schedule route module so
79
+ * a deployment can pass `cascade` fields straight into
80
+ * `BookingScheduleRoutesOptions`.
81
+ */
82
+ export interface PaymentPolicyCascade {
83
+ resolveSupplierPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
84
+ resolveCategoryPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
85
+ resolveListingPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
86
+ resolveSupplierPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
87
+ resolveCategoryPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
88
+ resolveListingPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
89
+ stampPolicySourceOnBooking(db: PostgresJsDatabase, bookingId: string, source: PaymentPolicySource): Promise<void>;
90
+ readPolicySourceFromInternalNotes(internalNotes: string | null | undefined): PaymentPolicySource | null;
91
+ }
92
+ /**
93
+ * Build the payment-policy cascade. Composes the deployment-supplied vertical
94
+ * readers into the cascade's per-layer resolvers (booking-level + per-entity
95
+ * preview) and owns the source-marker protocol on the booking row.
96
+ *
97
+ * Behaviour is byte-for-byte equivalent to the operator's previous
98
+ * `booking-payment-policy-runtime.ts`: same cascade order, same fallbacks, same
99
+ * `PaymentPolicy` shape, same `source` values.
100
+ */
101
+ export declare function createPaymentPolicyCascade(options: PaymentPolicyCascadeOptions): PaymentPolicyCascade;
102
+ /**
103
+ * Persist the winning cascade source onto a booking's `internalNotes`.
104
+ *
105
+ * Replaces any existing `__payment_policy_source__:` marker line so the stamp
106
+ * is idempotent across re-confirmations. The source enum is small
107
+ * (booking | listing | category | supplier | operator_default) so a single
108
+ * marker line is enough.
109
+ *
110
+ * Touches only the `bookings` schema, which finance already depends on
111
+ * acyclically — no vertical import, so this lives in finance.
112
+ */
113
+ export declare function stampPolicySourceOnBooking(db: PostgresJsDatabase, bookingId: string, source: PaymentPolicySource): Promise<void>;
114
+ /**
115
+ * Read the policy-source marker stamped onto a booking by the schedule
116
+ * subscriber. Used by the contract resolver so `booking.paymentPolicy.source`
117
+ * reflects the actual cascade layer (`supplier`, `operator_default`, etc.)
118
+ * rather than always echoing `"operator_default"`.
119
+ *
120
+ * Returns `null` when no marker is present or the stamped value isn't a known
121
+ * `PaymentPolicySource`.
122
+ */
123
+ export declare function readPolicySourceFromInternalNotes(internalNotes: string | null | undefined): PaymentPolicySource | null;
124
+ //# sourceMappingURL=payment-policy-cascade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-policy-cascade.d.ts","sourceRoot":"","sources":["../src/payment-policy-cascade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Multi-vertical payment-policy cascade — owned by `@voyant-travel/finance`.
3
+ *
4
+ * Finance owns the `PaymentPolicy` primitive and the most-specific-wins cascade
5
+ * (`resolveEffectivePaymentPolicy`: booking → listing → category → supplier →
6
+ * operator default). This module packages the *cascade orchestration* + the
7
+ * policy-source bookkeeping so no deployment recreates it: the supplier /
8
+ * category / listing layers, the per-entity storefront-preview variant, and the
9
+ * `__payment_policy_source__:` marker protocol stamped onto a booking's
10
+ * `internalNotes`.
11
+ *
12
+ * WHY THE VERTICAL READERS ARE INJECTED (not imported):
13
+ *
14
+ * The actual schema walks the cascade performs — supplier policy off the
15
+ * booking's supplier link, category policy off `product_categories`, and the
16
+ * per-listing policy off accommodation rate plans / cruise cabin→sailing→cruise
17
+ * layers / product rows — read tables in `@voyant-travel/inventory`,
18
+ * `@voyant-travel/accommodations`, `@voyant-travel/cruises`, and
19
+ * `@voyant-travel/distribution`. Finance is a retail-spine root and the spine
20
+ * closure gate HARD-FORBIDS finance from depending on `@voyant-travel/inventory`
21
+ * / `@voyant-travel/products` (and `@voyant-travel/accommodations` transitively
22
+ * reaches the forbidden `@voyant-travel/operations`). So those reads MUST stay
23
+ * in the deployment and are injected here as `options.readers` rather than
24
+ * imported. The cascade *order*, the per-entity fan-out, and the source-marker
25
+ * protocol are vertical-agnostic framework logic and live here.
26
+ *
27
+ * The `bookings` schema reads (stamp/read the source marker) ARE imported
28
+ * directly: finance already depends on `@voyant-travel/bookings` acyclically
29
+ * (bookings never depends back on finance).
30
+ */
31
+ import { bookings } from "@voyant-travel/bookings/schema";
32
+ import { eq } from "drizzle-orm";
33
+ /**
34
+ * The marker line stamped onto a booking's `internalNotes` recording which
35
+ * cascade layer produced the effective policy. Framework-owned protocol so the
36
+ * contract resolver can echo the real source rather than always "operator_default".
37
+ */
38
+ const POLICY_SOURCE_MARKER_PREFIX = "__payment_policy_source__:";
39
+ /**
40
+ * Build the payment-policy cascade. Composes the deployment-supplied vertical
41
+ * readers into the cascade's per-layer resolvers (booking-level + per-entity
42
+ * preview) and owns the source-marker protocol on the booking row.
43
+ *
44
+ * Behaviour is byte-for-byte equivalent to the operator's previous
45
+ * `booking-payment-policy-runtime.ts`: same cascade order, same fallbacks, same
46
+ * `PaymentPolicy` shape, same `source` values.
47
+ */
48
+ export function createPaymentPolicyCascade(options) {
49
+ const { readers } = options;
50
+ return {
51
+ resolveSupplierPolicy: (db, bookingId) => readers.resolveSupplierPolicy(db, bookingId),
52
+ resolveCategoryPolicy: (db, bookingId) => readers.resolveCategoryPolicy(db, bookingId),
53
+ resolveListingPolicy: (db, bookingId) => readers.resolveListingPolicy(db, bookingId),
54
+ resolveSupplierPolicyForEntity: (db, ctx) => readers.resolveSupplierPolicyForEntity(db, ctx),
55
+ resolveCategoryPolicyForEntity: (db, ctx) => readers.resolveCategoryPolicyForEntity(db, ctx),
56
+ resolveListingPolicyForEntity: (db, ctx) => readers.resolveListingPolicyForEntity(db, ctx),
57
+ stampPolicySourceOnBooking: (db, bookingId, source) => stampPolicySourceOnBooking(db, bookingId, source),
58
+ readPolicySourceFromInternalNotes,
59
+ };
60
+ }
61
+ /**
62
+ * Persist the winning cascade source onto a booking's `internalNotes`.
63
+ *
64
+ * Replaces any existing `__payment_policy_source__:` marker line so the stamp
65
+ * is idempotent across re-confirmations. The source enum is small
66
+ * (booking | listing | category | supplier | operator_default) so a single
67
+ * marker line is enough.
68
+ *
69
+ * Touches only the `bookings` schema, which finance already depends on
70
+ * acyclically — no vertical import, so this lives in finance.
71
+ */
72
+ export async function stampPolicySourceOnBooking(db, bookingId, source) {
73
+ const [row] = await db
74
+ .select({ internalNotes: bookings.internalNotes })
75
+ .from(bookings)
76
+ .where(eq(bookings.id, bookingId))
77
+ .limit(1);
78
+ if (!row)
79
+ return;
80
+ const filtered = (row.internalNotes ?? "")
81
+ .split(/\r?\n/)
82
+ .filter((line) => !line.trim().startsWith(POLICY_SOURCE_MARKER_PREFIX))
83
+ .join("\n");
84
+ const marker = `${POLICY_SOURCE_MARKER_PREFIX}${source}`;
85
+ const next = filtered.length > 0 ? `${filtered}\n${marker}` : marker;
86
+ await db
87
+ .update(bookings)
88
+ .set({ internalNotes: next, updatedAt: new Date() })
89
+ .where(eq(bookings.id, bookingId));
90
+ }
91
+ /**
92
+ * Read the policy-source marker stamped onto a booking by the schedule
93
+ * subscriber. Used by the contract resolver so `booking.paymentPolicy.source`
94
+ * reflects the actual cascade layer (`supplier`, `operator_default`, etc.)
95
+ * rather than always echoing `"operator_default"`.
96
+ *
97
+ * Returns `null` when no marker is present or the stamped value isn't a known
98
+ * `PaymentPolicySource`.
99
+ */
100
+ export function readPolicySourceFromInternalNotes(internalNotes) {
101
+ if (!internalNotes)
102
+ return null;
103
+ for (const line of internalNotes.split(/\r?\n/)) {
104
+ const trimmed = line.trim();
105
+ if (trimmed.startsWith(POLICY_SOURCE_MARKER_PREFIX)) {
106
+ const value = trimmed.slice(POLICY_SOURCE_MARKER_PREFIX.length).trim();
107
+ switch (value) {
108
+ case "booking":
109
+ case "listing":
110
+ case "category":
111
+ case "supplier":
112
+ case "operator_default":
113
+ return value;
114
+ default:
115
+ return null;
116
+ }
117
+ }
118
+ }
119
+ return null;
120
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Booking payment-schedule route module — owned by `@voyant-travel/finance`.
3
+ *
4
+ * Hosts the admin + public payment-policy surface plus the schedule-generation
5
+ * orchestration that backs the `booking.confirmed` subscriber:
6
+ *
7
+ * POST /v1/admin/bookings/:bookingId/payment-schedule/regenerate
8
+ * POST /v1/public/payment-policy/resolve
9
+ *
10
+ * The policy cascade (booking → listing → category → supplier → operator
11
+ * default) is deployment-specific — the resolvers read across vertical modules
12
+ * (cruises / accommodations / products / suppliers / categories) that the
13
+ * finance package must not statically import. They are therefore INJECTED via
14
+ * {@link BookingScheduleRoutesOptions}, alongside the operator-default resolver.
15
+ *
16
+ * The bookings schema (`bookings`, `bookingActivityLog`) and the action-ledger
17
+ * appender are imported directly: `@voyant-travel/finance` already depends on
18
+ * both `@voyant-travel/bookings` and `@voyant-travel/action-ledger` acyclically
19
+ * (neither depends back on finance), so no injection is needed there.
20
+ *
21
+ * All handler behavior, cascade precedence, idempotency, and the activity-log
22
+ * entry are preserved byte-for-byte from the operator's previous
23
+ * `booking-schedule.ts`.
24
+ */
25
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
26
+ import { type Context, Hono } from "hono";
27
+ import { type PaymentPolicy, type PaymentPolicySource } from "../payment-policy.js";
28
+ import type { PaymentPolicyEntityContext } from "../payment-policy-cascade.js";
29
+ export type { PaymentPolicyEntityContext };
30
+ /**
31
+ * Deployment-supplied options for the booking payment-schedule route module.
32
+ *
33
+ * The cascade resolvers + operator default are INJECTED because they read
34
+ * across vertical modules (cruises / accommodations / products / suppliers /
35
+ * product categories) that finance must not statically import. The bookings
36
+ * schema and action-ledger appender are NOT injected — finance already depends
37
+ * on both acyclically and imports them directly.
38
+ */
39
+ export interface BookingScheduleRoutesOptions {
40
+ /** Resolve the per-request drizzle db from the Hono context (`c.get("db")`). */
41
+ resolveDb(c: Context): PostgresJsDatabase;
42
+ /** Operator-default payment policy (the cascade's last-resort layer). */
43
+ resolveOperatorDefaultPaymentPolicy(db: PostgresJsDatabase): Promise<PaymentPolicy | null>;
44
+ /** Phase 2: supplier-layer override keyed off the booking's supplier link. */
45
+ resolveSupplierPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
46
+ /** Phase 3: product-category override (first category by sortOrder). */
47
+ resolveCategoryPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
48
+ /** Phase 4: per-listing override (first booking-item product policy). */
49
+ resolveListingPolicy(db: PostgresJsDatabase, bookingId: string): Promise<PaymentPolicy | null>;
50
+ resolveListingPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
51
+ resolveCategoryPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
52
+ resolveSupplierPolicyForEntity(db: PostgresJsDatabase, ctx: PaymentPolicyEntityContext): Promise<PaymentPolicy | null>;
53
+ /** Persist the winning cascade source onto the booking's internalNotes. */
54
+ stampPolicySourceOnBooking(db: PostgresJsDatabase, bookingId: string, source: PaymentPolicySource): Promise<void>;
55
+ /** Read the stamped cascade source back off internalNotes (regenerate response). */
56
+ readPolicySourceFromInternalNotes(internalNotes: string): PaymentPolicySource | null;
57
+ }
58
+ /**
59
+ * Generate (or regenerate) the payment schedule for a booking.
60
+ *
61
+ * Resolves the effective customer payment policy (cascade: booking → listing →
62
+ * category → supplier → operator default), runs {@link computePaymentSchedule},
63
+ * persists the rows via `financeService.applyComputedPaymentSchedule`, stamps
64
+ * the cascade source on the booking, and writes a `system_action` activity-log
65
+ * entry.
66
+ *
67
+ * Idempotent: when any schedule row already exists for the booking (in any
68
+ * status) it returns early so a re-fired `booking.confirmed` event doesn't wipe
69
+ * outstanding rows and double-bill the customer on paper.
70
+ */
71
+ export declare function generatePaymentScheduleForBooking(db: PostgresJsDatabase, bookingId: string, options: BookingScheduleRoutesOptions): Promise<void>;
72
+ /**
73
+ * Admin payment-schedule routes (relative paths; mount at `/v1/admin/bookings`).
74
+ *
75
+ * POST /:bookingId/payment-schedule/regenerate
76
+ */
77
+ export declare function createBookingScheduleAdminRoutes(options: BookingScheduleRoutesOptions): Hono;
78
+ /**
79
+ * Public payment-policy routes (relative paths; mount at
80
+ * `/v1/public/payment-policy`).
81
+ *
82
+ * POST /resolve — anonymous storefront preview of the effective policy.
83
+ */
84
+ export declare function createPaymentPolicyPublicRoutes(options: BookingScheduleRoutesOptions): Hono;
85
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/payment-schedule/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAOH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,KAAK,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEzC,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAEzB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AAI9E,YAAY,EAAE,0BAA0B,EAAE,CAAA;AAE1C;;;;;;;;GAQG;AACH,MAAM,WAAW,4BAA4B;IAC3C,gFAAgF;IAChF,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAAA;IACzC,yEAAyE;IACzE,mCAAmC,CAAC,EAAE,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAG1F,8EAA8E;IAC9E,qBAAqB,CAAC,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAC/F,wEAAwE;IACxE,qBAAqB,CAAC,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAC/F,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAG9F,6BAA6B,CAC3B,EAAE,EAAE,kBAAkB,EACtB,GAAG,EAAE,0BAA0B,GAC9B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAChC,8BAA8B,CAC5B,EAAE,EAAE,kBAAkB,EACtB,GAAG,EAAE,0BAA0B,GAC9B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAChC,8BAA8B,CAC5B,EAAE,EAAE,kBAAkB,EACtB,GAAG,EAAE,0BAA0B,GAC9B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAA;IAGhC,2EAA2E;IAC3E,0BAA0B,CACxB,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAAA;IAChB,oFAAoF;IACpF,iCAAiC,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAAA;CACrF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iCAAiC,CACrD,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,IAAI,CAAC,CAuFf;AA6LD;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,4BAA4B,GAAG,IAAI,CAI5F;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,4BAA4B,GAAG,IAAI,CAI3F"}
@@ -0,0 +1,298 @@
1
+ /**
2
+ * Booking payment-schedule route module — owned by `@voyant-travel/finance`.
3
+ *
4
+ * Hosts the admin + public payment-policy surface plus the schedule-generation
5
+ * orchestration that backs the `booking.confirmed` subscriber:
6
+ *
7
+ * POST /v1/admin/bookings/:bookingId/payment-schedule/regenerate
8
+ * POST /v1/public/payment-policy/resolve
9
+ *
10
+ * The policy cascade (booking → listing → category → supplier → operator
11
+ * default) is deployment-specific — the resolvers read across vertical modules
12
+ * (cruises / accommodations / products / suppliers / categories) that the
13
+ * finance package must not statically import. They are therefore INJECTED via
14
+ * {@link BookingScheduleRoutesOptions}, alongside the operator-default resolver.
15
+ *
16
+ * The bookings schema (`bookings`, `bookingActivityLog`) and the action-ledger
17
+ * appender are imported directly: `@voyant-travel/finance` already depends on
18
+ * both `@voyant-travel/bookings` and `@voyant-travel/action-ledger` acyclically
19
+ * (neither depends back on finance), so no injection is needed there.
20
+ *
21
+ * All handler behavior, cascade precedence, idempotency, and the activity-log
22
+ * entry are preserved byte-for-byte from the operator's previous
23
+ * `booking-schedule.ts`.
24
+ */
25
+ import { appendActionLedgerMutation } from "@voyant-travel/action-ledger";
26
+ import { bookingActivityLog, bookings } from "@voyant-travel/bookings/schema";
27
+ import { parseJsonBody } from "@voyant-travel/hono";
28
+ import { asc, eq } from "drizzle-orm";
29
+ import { Hono } from "hono";
30
+ import { z } from "zod";
31
+ import { computePaymentSchedule, noDepositPolicy, resolveEffectivePaymentPolicy, } from "../payment-policy.js";
32
+ import { bookingPaymentSchedules } from "../schema/booking-billing.js";
33
+ import { financeService } from "../service.js";
34
+ /**
35
+ * Generate (or regenerate) the payment schedule for a booking.
36
+ *
37
+ * Resolves the effective customer payment policy (cascade: booking → listing →
38
+ * category → supplier → operator default), runs {@link computePaymentSchedule},
39
+ * persists the rows via `financeService.applyComputedPaymentSchedule`, stamps
40
+ * the cascade source on the booking, and writes a `system_action` activity-log
41
+ * entry.
42
+ *
43
+ * Idempotent: when any schedule row already exists for the booking (in any
44
+ * status) it returns early so a re-fired `booking.confirmed` event doesn't wipe
45
+ * outstanding rows and double-bill the customer on paper.
46
+ */
47
+ export async function generatePaymentScheduleForBooking(db, bookingId, options) {
48
+ const [booking] = await db.select().from(bookings).where(eq(bookings.id, bookingId)).limit(1);
49
+ if (!booking)
50
+ return;
51
+ if (!booking.sellAmountCents || booking.sellAmountCents <= 0)
52
+ return;
53
+ // Idempotency: this subscriber fires on every `booking.confirmed`
54
+ // emission, which includes re-confirmations during the
55
+ // checkout-finalize workflow when an existing booking transitions
56
+ // to confirmed after a late payment. If a schedule already exists
57
+ // (in any status — pending/due/paid/etc.), regenerating would wipe
58
+ // the outstanding rows and insert a fresh full-amount plan as if
59
+ // the booking had never been touched, double-billing the customer
60
+ // on paper.
61
+ const [existingSchedule] = await db
62
+ .select({ id: bookingPaymentSchedules.id })
63
+ .from(bookingPaymentSchedules)
64
+ .where(eq(bookingPaymentSchedules.bookingId, bookingId))
65
+ .limit(1);
66
+ if (existingSchedule)
67
+ return;
68
+ const operatorDefault = (await options.resolveOperatorDefaultPaymentPolicy(db)) ?? noDepositPolicy;
69
+ // Phase 2: supplier-layer override. Falls back to operator
70
+ // default when the booking has no supplier link or the supplier
71
+ // hasn't configured a custom policy.
72
+ const supplierPolicy = await options.resolveSupplierPolicy(db, bookingId);
73
+ // Phase 3: product-category override. Walks the booking's
74
+ // products → categories and picks the first category (by
75
+ // productCategoryProducts.sortOrder ascending) that defines a
76
+ // policy. Wins over supplier per the cascade order.
77
+ const categoryPolicy = await options.resolveCategoryPolicy(db, bookingId);
78
+ // Phase 4: per-listing override. The first booking-item's product
79
+ // with a non-null customerPaymentPolicy wins. Most specific catalog
80
+ // layer — beats category, supplier, and operator default.
81
+ const listingPolicy = await options.resolveListingPolicy(db, bookingId);
82
+ // Phase 5: booking-level override. The booking's own
83
+ // customerPaymentPolicy column wins over every catalog layer.
84
+ // Reserved for ops adjustments — most bookings leave this null.
85
+ const bookingPolicy = booking.customerPaymentPolicy ?? null;
86
+ const { policy, source } = resolveEffectivePaymentPolicy({
87
+ bookingPolicy,
88
+ listingPolicy,
89
+ categoryPolicy,
90
+ supplierPolicy,
91
+ operatorDefault,
92
+ });
93
+ const entries = computePaymentSchedule({
94
+ totalCents: booking.sellAmountCents,
95
+ currency: booking.sellCurrency,
96
+ departureDate: booking.startDate,
97
+ }, policy);
98
+ await financeService.applyComputedPaymentSchedule(db, bookingId, entries, { replace: true });
99
+ // Stash the source on the booking's internalNotes so the contract
100
+ // resolver can echo it via `booking.paymentPolicy.source`. The
101
+ // source enum is small (booking | listing | category | supplier |
102
+ // operator_default) so a single marker line is enough.
103
+ await options.stampPolicySourceOnBooking(db, bookingId, source);
104
+ // Audit trail — record what cascade layer applied, which policy
105
+ // was used, and the resulting schedule snapshot. Lets ops trace
106
+ // why a particular schedule was generated. The structured metadata
107
+ // (`kind: payment_schedule_regenerated`) distinguishes this row
108
+ // from other system-issued activity entries.
109
+ await db.insert(bookingActivityLog).values({
110
+ bookingId,
111
+ actorId: "system",
112
+ activityType: "system_action",
113
+ description: `Payment schedule regenerated from ${source} policy (${entries.length} row${entries.length === 1 ? "" : "s"})`,
114
+ metadata: {
115
+ kind: "payment_schedule_regenerated",
116
+ policySource: source,
117
+ policy,
118
+ entries,
119
+ },
120
+ });
121
+ }
122
+ // ─────────────────────────────────────────────────────────────────
123
+ // Admin route: update booking-level policy + regenerate schedule
124
+ // ─────────────────────────────────────────────────────────────────
125
+ const depositRuleApiSchema = z.object({
126
+ kind: z.enum(["none", "percent", "fixed_cents"]),
127
+ percent: z.number().min(0).max(100).optional(),
128
+ amountCents: z.number().int().min(0).optional(),
129
+ });
130
+ const policyApiSchema = z.object({
131
+ deposit: depositRuleApiSchema,
132
+ minDaysBeforeDepartureForDeposit: z.number().int().min(0),
133
+ balanceDueDaysBeforeDeparture: z.number().int().min(0),
134
+ balanceDueMinDaysFromNow: z.number().int().min(0),
135
+ });
136
+ const regenerateScheduleBodySchema = z.object({
137
+ /**
138
+ * Optional booking-level override. When provided, persists onto
139
+ * `bookings.customerPaymentPolicy` before running the resolver.
140
+ * Pass `null` to clear an existing override (cascade falls back
141
+ * to listing/category/supplier/operator default).
142
+ */
143
+ customerPaymentPolicy: policyApiSchema.nullable().optional(),
144
+ });
145
+ async function handleRegenerateSchedule(c, options) {
146
+ const db = options.resolveDb(c);
147
+ const bookingId = c.req.param("bookingId");
148
+ if (!bookingId) {
149
+ return c.json({ error: "missing_booking_id" }, 400);
150
+ }
151
+ let body;
152
+ try {
153
+ body = await parseJsonBody(c, regenerateScheduleBodySchema);
154
+ }
155
+ catch (err) {
156
+ return c.json({ error: err instanceof Error ? err.message : "invalid_body" }, 400);
157
+ }
158
+ // Persist the override (or clear it) before running the resolver.
159
+ if (Object.hasOwn(body, "customerPaymentPolicy")) {
160
+ const [before] = await db
161
+ .select({ customerPaymentPolicy: bookings.customerPaymentPolicy })
162
+ .from(bookings)
163
+ .where(eq(bookings.id, bookingId))
164
+ .limit(1);
165
+ await db
166
+ .update(bookings)
167
+ .set({
168
+ customerPaymentPolicy: (body.customerPaymentPolicy ?? null),
169
+ updatedAt: new Date(),
170
+ })
171
+ .where(eq(bookings.id, bookingId));
172
+ const overrideChanged = JSON.stringify(before?.customerPaymentPolicy ?? null) !==
173
+ JSON.stringify(body.customerPaymentPolicy ?? null);
174
+ if (overrideChanged) {
175
+ await appendActionLedgerMutation(db, {
176
+ context: getPaymentScheduleActionLedgerRequestContext(c),
177
+ actionName: "booking.payment_policy.override",
178
+ actionVersion: "v1",
179
+ actionKind: "update",
180
+ evaluatedRisk: "high",
181
+ targetType: "booking",
182
+ targetId: bookingId,
183
+ routeOrToolName: "bookings.payment-schedule.regenerate",
184
+ authorizationSource: "operator.booking-schedule.route",
185
+ mutationDetail: {
186
+ summary: body.customerPaymentPolicy === null
187
+ ? "Cleared booking payment policy override"
188
+ : "Updated booking payment policy override",
189
+ reversalKind: "none",
190
+ },
191
+ });
192
+ }
193
+ }
194
+ await generatePaymentScheduleForBooking(db, bookingId, options);
195
+ const rows = await db
196
+ .select()
197
+ .from(bookingPaymentSchedules)
198
+ .where(eq(bookingPaymentSchedules.bookingId, bookingId))
199
+ .orderBy(asc(bookingPaymentSchedules.dueDate), asc(bookingPaymentSchedules.createdAt));
200
+ const [updatedBooking] = await db
201
+ .select({
202
+ customerPaymentPolicy: bookings.customerPaymentPolicy,
203
+ internalNotes: bookings.internalNotes,
204
+ })
205
+ .from(bookings)
206
+ .where(eq(bookings.id, bookingId))
207
+ .limit(1);
208
+ return c.json({
209
+ data: {
210
+ schedule: rows,
211
+ bookingPolicy: updatedBooking?.customerPaymentPolicy ?? null,
212
+ cascadeSource: options.readPolicySourceFromInternalNotes(updatedBooking?.internalNotes ?? "") ??
213
+ "operator_default",
214
+ },
215
+ });
216
+ }
217
+ function getPaymentScheduleActionLedgerRequestContext(c) {
218
+ return {
219
+ userId: c.get("userId") ?? null,
220
+ agentId: c.get("agentId") ?? null,
221
+ workflowPrincipalId: c.get("workflowPrincipalId") ?? null,
222
+ principalSubtype: c.get("principalSubtype") ?? null,
223
+ sessionId: c.get("sessionId") ?? null,
224
+ apiTokenId: c.get("apiTokenId") ?? c.get("apiKeyId") ?? null,
225
+ callerType: c.get("callerType") ?? null,
226
+ actor: c.get("actor") ?? null,
227
+ isInternalRequest: c.get("isInternalRequest") ?? false,
228
+ organizationId: c.get("organizationId") ?? null,
229
+ workflowRunId: c.get("workflowRunId") ?? null,
230
+ workflowStepId: c.get("workflowStepId") ?? null,
231
+ correlationId: c.req.header("x-correlation-id") ?? c.req.header("x-request-id") ?? null,
232
+ };
233
+ }
234
+ // ─────────────────────────────────────────────────────────────────
235
+ // Public route: resolve policy for an entity (storefront preview)
236
+ // ─────────────────────────────────────────────────────────────────
237
+ const resolvePolicyBodySchema = z.object({
238
+ entityModule: z.string(),
239
+ entityId: z.string(),
240
+ /** Cruise journey selections — resolver walks cabin → sailing →
241
+ * cruise once these are picked. Optional because the customer
242
+ * may not have selected a cabin yet. */
243
+ sailingId: z.string().optional(),
244
+ cabinCategoryId: z.string().optional(),
245
+ /** Accommodation journey selection — resolver picks the rate plan's
246
+ * policy when present. */
247
+ ratePlanId: z.string().optional(),
248
+ });
249
+ async function handleResolvePolicy(c, options) {
250
+ const db = options.resolveDb(c);
251
+ let body;
252
+ try {
253
+ body = await parseJsonBody(c, resolvePolicyBodySchema);
254
+ }
255
+ catch (err) {
256
+ return c.json({ error: err instanceof Error ? err.message : "invalid_body" }, 400);
257
+ }
258
+ const operatorDefault = (await options.resolveOperatorDefaultPaymentPolicy(db)) ?? noDepositPolicy;
259
+ // Vertical-specific listing lookups — same source-of-truth queries
260
+ // as the booking-confirmed path, just keyed off the journey
261
+ // selections instead of a persisted booking_items row.
262
+ const listingPolicy = await options.resolveListingPolicyForEntity(db, body);
263
+ const categoryPolicy = await options.resolveCategoryPolicyForEntity(db, body);
264
+ const supplierPolicy = await options.resolveSupplierPolicyForEntity(db, body);
265
+ const { policy, source } = resolveEffectivePaymentPolicy({
266
+ listingPolicy,
267
+ categoryPolicy,
268
+ supplierPolicy,
269
+ operatorDefault,
270
+ });
271
+ return c.json({
272
+ data: {
273
+ policy,
274
+ source,
275
+ },
276
+ });
277
+ }
278
+ /**
279
+ * Admin payment-schedule routes (relative paths; mount at `/v1/admin/bookings`).
280
+ *
281
+ * POST /:bookingId/payment-schedule/regenerate
282
+ */
283
+ export function createBookingScheduleAdminRoutes(options) {
284
+ const hono = new Hono();
285
+ hono.post("/:bookingId/payment-schedule/regenerate", (c) => handleRegenerateSchedule(c, options));
286
+ return hono;
287
+ }
288
+ /**
289
+ * Public payment-policy routes (relative paths; mount at
290
+ * `/v1/public/payment-policy`).
291
+ *
292
+ * POST /resolve — anonymous storefront preview of the effective policy.
293
+ */
294
+ export function createPaymentPolicyPublicRoutes(options) {
295
+ const hono = new Hono();
296
+ hono.post("/resolve", (c) => handleResolvePolicy(c, options));
297
+ return hono;
298
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/finance",
3
- "version": "0.120.2",
3
+ "version": "0.122.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -14,6 +14,11 @@
14
14
  "import": "./dist/action-ledger-drift.js",
15
15
  "default": "./dist/action-ledger-drift.js"
16
16
  },
17
+ "./card-payment": {
18
+ "types": "./dist/card-payment.d.ts",
19
+ "import": "./dist/card-payment.js",
20
+ "default": "./dist/card-payment.js"
21
+ },
17
22
  "./checkout": {
18
23
  "types": "./dist/checkout-service.d.ts",
19
24
  "import": "./dist/checkout-service.js",
@@ -34,6 +39,16 @@
34
39
  "import": "./dist/invoice-fx.js",
35
40
  "default": "./dist/invoice-fx.js"
36
41
  },
42
+ "./order-payment-sessions": {
43
+ "types": "./dist/order-payment-sessions.d.ts",
44
+ "import": "./dist/order-payment-sessions.js",
45
+ "default": "./dist/order-payment-sessions.js"
46
+ },
47
+ "./payment-policy-cascade": {
48
+ "types": "./dist/payment-policy-cascade.d.ts",
49
+ "import": "./dist/payment-policy-cascade.js",
50
+ "default": "./dist/payment-policy-cascade.js"
51
+ },
37
52
  "./payment-link": {
38
53
  "types": "./dist/payment-link.d.ts",
39
54
  "import": "./dist/payment-link.js",
@@ -76,19 +91,17 @@
76
91
  "fflate": "^0.8.2",
77
92
  "hono": "^4.12.10",
78
93
  "zod": "^4.3.6",
79
- "@voyant-travel/action-ledger": "^0.104.11",
80
- "@voyant-travel/bookings": "^0.120.3",
94
+ "@voyant-travel/action-ledger": "^0.105.0",
95
+ "@voyant-travel/bookings": "^0.122.0",
81
96
  "@voyant-travel/core": "^0.109.0",
82
97
  "@voyant-travel/db": "^0.108.1",
83
98
  "@voyant-travel/finance-contracts": "^0.104.5",
84
- "@voyant-travel/hono": "^0.110.3",
85
- "@voyant-travel/storage": "^0.104.1",
99
+ "@voyant-travel/hono": "^0.111.0",
100
+ "@voyant-travel/storage": "^0.105.0",
86
101
  "@voyant-travel/utils": "^0.105.2"
87
102
  },
88
103
  "devDependencies": {
89
104
  "typescript": "^6.0.2",
90
- "@voyant-travel/operations": "^0.1.0",
91
- "@voyant-travel/inventory": "^0.2.0",
92
105
  "@voyant-travel/voyant-typescript-config": "^0.1.0"
93
106
  },
94
107
  "files": [