@voyant-travel/finance 0.162.1 → 0.163.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/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // agent-quality: file-size exception -- owner: finance; existing module stays co-located until a dedicated split preserves behavior and tests.
2
2
  import { OpenAPIHono } from "@hono/zod-openapi";
3
3
  import { registerBookingFinancialLifecycle } from "@voyant-travel/bookings";
4
+ import { customFieldsRuntimePort } from "@voyant-travel/core/custom-fields";
4
5
  import { defineGraphRuntimeFactory } from "@voyant-travel/core/project";
5
6
  import { stampOpenApiRegistryApiId } from "@voyant-travel/hono";
6
7
  import { financeBookingLifecycle } from "./booking-lifecycle.js";
@@ -65,7 +66,7 @@ export function createFinanceApiModule(options = {}) {
65
66
  }
66
67
  export const financeApiModule = createFinanceApiModule();
67
68
  export const createFinanceVoyantRuntime = defineGraphRuntimeFactory(async ({ api, getPort, getPorts, hasPort }) => {
68
- const configured = createFinanceApiModule(createFinanceRuntime(await getPort(financeHostRuntimePort), await getPort(financeNotificationsRuntimePort), hasPort(financeCheckoutPaymentStartersRuntimePort)
69
+ const configured = createFinanceApiModule(createFinanceRuntime(await getPort(financeHostRuntimePort), await getPort(customFieldsRuntimePort), await getPort(financeNotificationsRuntimePort), hasPort(financeCheckoutPaymentStartersRuntimePort)
69
70
  ? await getPort(financeCheckoutPaymentStartersRuntimePort)
70
71
  : undefined, await getPorts(financeInvoiceSettlementPollerRuntimePort)));
71
72
  const bootstrap = configured.module.bootstrap;
@@ -6,6 +6,7 @@ import type { InvoiceDueDateResolver, InvoiceLineDescriptionResolver, PaymentSch
6
6
  import type { InvoiceDocumentGenerator } from "./service-documents.js";
7
7
  export type FinanceRouteRuntime = {
8
8
  invoiceDocumentGenerator?: InvoiceDocumentGenerator;
9
+ resolveCustomFields?: FinanceDocumentRouteOptions["resolveCustomFields"];
9
10
  resolveDocumentDownloadUrl?: FinanceDocumentRouteOptions["resolveDocumentDownloadUrl"];
10
11
  invoiceSettlementPollers: Record<string, InvoiceSettlementPoller>;
11
12
  eventBus?: EventBus;
@@ -2,6 +2,7 @@ export const FINANCE_ROUTE_RUNTIME_CONTAINER_KEY = "providers.finance.runtime";
2
2
  export function buildFinanceRouteRuntime(bindings, options = {}) {
3
3
  return {
4
4
  invoiceDocumentGenerator: options.resolveInvoiceDocumentGenerator?.(bindings) ?? options.invoiceDocumentGenerator,
5
+ resolveCustomFields: options.resolveCustomFields,
5
6
  resolveDocumentDownloadUrl: options.resolveDocumentDownloadUrl,
6
7
  invoiceSettlementPollers: options.resolveInvoiceSettlementPollers?.(bindings) ?? options.invoiceSettlementPollers ?? {},
7
8
  eventBus: options.resolveEventBus?.(bindings) ?? options.eventBus,
@@ -23,7 +23,7 @@
23
23
  import { OpenAPIHono } from "@hono/zod-openapi";
24
24
  import type { EventBus, ModuleContainer } from "@voyant-travel/core";
25
25
  import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
26
- import { type InvoiceDocumentGenerator } from "./service-documents.js";
26
+ import { type InvoiceDocumentGenerator, type InvoiceDocumentRuntimeOptions } from "./service-documents.js";
27
27
  type Env = {
28
28
  Bindings: Record<string, unknown>;
29
29
  Variables: {
@@ -34,6 +34,7 @@ type Env = {
34
34
  };
35
35
  export interface FinanceDocumentRouteOptions {
36
36
  invoiceDocumentGenerator?: InvoiceDocumentGenerator;
37
+ resolveCustomFields?: InvoiceDocumentRuntimeOptions["resolveCustomFields"];
37
38
  resolveInvoiceDocumentGenerator?: (bindings: Record<string, unknown>) => InvoiceDocumentGenerator | undefined;
38
39
  resolveDocumentDownloadUrl?: (bindings: unknown, storageKey: string) => Promise<string | null> | string | null;
39
40
  eventBus?: EventBus;
@@ -27,7 +27,7 @@ import { resolveStoredDocumentDownload } from "./document-download.js";
27
27
  import { buildFinanceRouteRuntime, FINANCE_ROUTE_RUNTIME_CONTAINER_KEY, } from "./route-runtime.js";
28
28
  import { invoiceRenditionSchema } from "./routes-invoice-schemas.js";
29
29
  import { financeService } from "./service.js";
30
- import { financeDocumentsService } from "./service-documents.js";
30
+ import { financeDocumentsService, } from "./service-documents.js";
31
31
  import { generateInvoiceDocumentInputSchema } from "./validation.js";
32
32
  const errorResponseSchema = z.object({ error: z.string() });
33
33
  /** The signed inline download envelope (§17: `expiresAt` is an ISO string). */
@@ -140,7 +140,12 @@ export function createFinanceAdminDocumentRoutes(options = {}) {
140
140
  return c.json({ error: "Invoice document generator is not configured" }, 501);
141
141
  }
142
142
  const input = await parseOptionalJsonBody(c, generateInvoiceDocumentInputSchema);
143
- const result = await financeDocumentsService.generateInvoiceDocument(c.get("db"), c.req.valid("param").id, input, { generator, bindings: c.env, eventBus: runtime.eventBus });
143
+ const result = await financeDocumentsService.generateInvoiceDocument(c.get("db"), c.req.valid("param").id, input, {
144
+ generator,
145
+ bindings: c.env,
146
+ eventBus: runtime.eventBus,
147
+ resolveCustomFields: runtime.resolveCustomFields,
148
+ });
144
149
  if (result.status === "not_found")
145
150
  return c.json({ error: "Invoice not found" }, 404);
146
151
  if (result.status === "generator_failed") {
@@ -158,7 +163,12 @@ export function createFinanceAdminDocumentRoutes(options = {}) {
158
163
  return c.json({ error: "Invoice document generator is not configured" }, 501);
159
164
  }
160
165
  const input = await parseOptionalJsonBody(c, generateInvoiceDocumentInputSchema);
161
- const result = await financeDocumentsService.regenerateInvoiceDocument(c.get("db"), c.req.valid("param").id, input, { generator, bindings: c.env, eventBus: runtime.eventBus });
166
+ const result = await financeDocumentsService.regenerateInvoiceDocument(c.get("db"), c.req.valid("param").id, input, {
167
+ generator,
168
+ bindings: c.env,
169
+ eventBus: runtime.eventBus,
170
+ resolveCustomFields: runtime.resolveCustomFields,
171
+ });
162
172
  if (result.status === "not_found")
163
173
  return c.json({ error: "Invoice not found" }, 404);
164
174
  if (result.status === "generator_failed") {
@@ -58,6 +58,7 @@ export declare function getFinanceRouteRuntime(c: {
58
58
  }): FinanceRouteRuntime | {
59
59
  eventBus: import("@voyant-travel/core").EventBus;
60
60
  invoiceDocumentGenerator?: import("./service-documents.js").InvoiceDocumentGenerator;
61
+ resolveCustomFields?: import("./routes-documents.js").FinanceDocumentRouteOptions["resolveCustomFields"];
61
62
  resolveDocumentDownloadUrl?: import("./routes-documents.js").FinanceDocumentRouteOptions["resolveDocumentDownloadUrl"];
62
63
  invoiceSettlementPollers?: Record<string, import("./service-settlement.js").InvoiceSettlementPoller> | undefined;
63
64
  descriptionResolver?: import("./service-shared.js").InvoiceLineDescriptionResolver;
package/dist/runtime.d.ts CHANGED
@@ -1,8 +1,9 @@
1
+ import type { CustomFieldsRuntime } from "@voyant-travel/core/custom-fields";
1
2
  import type { FinanceApiModuleOptions } from "./index.js";
2
3
  import type { FinanceAccommodationsPaymentPolicyRuntime, FinanceBookingScheduleRuntime, FinanceCheckoutPaymentStartersRuntime, FinanceCruisesPaymentPolicyRuntime, FinanceDistributionPaymentPolicyRuntime, FinanceHostRuntime, FinanceInventoryPaymentPolicyRuntime, FinanceInvoiceSettlementPollerProvider, FinanceNotificationsRuntime, FinanceOperatorSettingsRuntime } from "./runtime-port.js";
3
4
  import type { InvoiceSettlementPoller } from "./service-settlement.js";
4
5
  /** Compose Finance's main HTTP runtime from generic host and selected providers. */
5
- export declare function createFinanceRuntime(host: FinanceHostRuntime, notifications: FinanceNotificationsRuntime, checkoutPaymentStarters?: FinanceCheckoutPaymentStartersRuntime, invoiceSettlementPollerProviders?: readonly FinanceInvoiceSettlementPollerProvider[]): FinanceApiModuleOptions;
6
+ export declare function createFinanceRuntime(host: FinanceHostRuntime, customFields: CustomFieldsRuntime, notifications: FinanceNotificationsRuntime, checkoutPaymentStarters?: FinanceCheckoutPaymentStartersRuntime, invoiceSettlementPollerProviders?: readonly FinanceInvoiceSettlementPollerProvider[]): FinanceApiModuleOptions;
6
7
  /** Compose Finance's payment schedule from statically selected domain providers. */
7
8
  export declare function createFinanceBookingScheduleRuntime(host: FinanceHostRuntime, settings: FinanceOperatorSettingsRuntime, distribution: FinanceDistributionPaymentPolicyRuntime, accommodations: FinanceAccommodationsPaymentPolicyRuntime, cruises: FinanceCruisesPaymentPolicyRuntime, inventory: FinanceInventoryPaymentPolicyRuntime): FinanceBookingScheduleRuntime;
8
9
  export declare function createFinanceBookingTaxRuntime(settings: FinanceOperatorSettingsRuntime): FinanceApiModuleOptions;
package/dist/runtime.js CHANGED
@@ -1,9 +1,18 @@
1
1
  import { createVoyantDataFxExchangeRateResolver, } from "./invoice-fx.js";
2
2
  /** Compose Finance's main HTTP runtime from generic host and selected providers. */
3
- export function createFinanceRuntime(host, notifications, checkoutPaymentStarters, invoiceSettlementPollerProviders = []) {
3
+ export function createFinanceRuntime(host, customFields, notifications, checkoutPaymentStarters, invoiceSettlementPollerProviders = []) {
4
4
  const { primitives } = host;
5
5
  return {
6
6
  resolveDocumentDownloadUrl: primitives.storage.downloadUrl,
7
+ resolveCustomFields: async (db, invoice) => {
8
+ if (invoice.organizationId) {
9
+ return customFields.resolveVisibleValues(db, "organization", invoice.organizationId, "invoice");
10
+ }
11
+ if (invoice.personId) {
12
+ return customFields.resolveVisibleValues(db, "person", invoice.personId, "invoice");
13
+ }
14
+ return {};
15
+ },
7
16
  resolveInvoiceExchangeRateResolver: (bindings) => createExchangeRateResolver(primitives, bindings),
8
17
  invoiceSettlementPollers: aggregateFinanceInvoiceSettlementPollers(invoiceSettlementPollerProviders),
9
18
  invoiceDueDateResolver: ({ issueDate, dueDate, bookingPaymentSchedule }) => bookingPaymentSchedule && dueDate < issueDate ? issueDate : dueDate,
@@ -4,7 +4,7 @@ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
4
4
  import { z } from "zod";
5
5
  import type { BookingPaymentSchedule, Invoice, Payment, TravelCredit, TravelCreditRedemption } from "./schema.js";
6
6
  import { type FinanceServiceRuntime } from "./service.js";
7
- import { type InvoiceDocumentGenerator } from "./service-documents.js";
7
+ import { type InvoiceDocumentGenerator, type InvoiceDocumentRuntimeOptions } from "./service-documents.js";
8
8
  declare const travelerInputSchema: z.ZodObject<{
9
9
  clientTravelerKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
10
10
  firstName: z.ZodString;
@@ -301,6 +301,7 @@ export type BookingCreateTravelerInput = z.infer<typeof travelerInputSchema>;
301
301
  */
302
302
  export interface BookingCreateRuntime extends FinanceServiceRuntime {
303
303
  invoiceDocumentGenerator?: InvoiceDocumentGenerator;
304
+ resolveCustomFields?: InvoiceDocumentRuntimeOptions["resolveCustomFields"];
304
305
  bindings?: Record<string, unknown>;
305
306
  }
306
307
  export interface BookingCreatedEvent {
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  import { bookingPaymentSchedules, travelCredits } from "./schema.js";
10
10
  import { financeService, toRows } from "./service.js";
11
11
  import { buildBookingCreateRejectedActionLedgerInput, buildBookingCreateSucceededActionLedgerInput, } from "./service-action-ledger.js";
12
- import { financeDocumentsService } from "./service-documents.js";
12
+ import { financeDocumentsService, } from "./service-documents.js";
13
13
  import { TravelCreditServiceError, travelCreditsService } from "./service-travel-credits.js";
14
14
  import { paymentMethodSchema, paymentScheduleStatusSchema, paymentScheduleTypeSchema, } from "./validation-shared.js";
15
15
  // ---------- validation ----------
@@ -1205,6 +1205,7 @@ export async function createBooking(db, rawInput, options = {}) {
1205
1205
  generator: runtime.invoiceDocumentGenerator,
1206
1206
  eventBus: runtime.eventBus,
1207
1207
  bindings: runtime.bindings,
1208
+ resolveCustomFields: runtime.resolveCustomFields,
1208
1209
  });
1209
1210
  invoiceDocument =
1210
1211
  generated.status === "generated"
@@ -31,12 +31,10 @@ export interface InvoiceDocumentRuntimeOptions {
31
31
  generator: InvoiceDocumentGenerator;
32
32
  eventBus?: EventBus;
33
33
  /**
34
- * Optional: resolve the invoice-visible custom fields for this invoice's
35
- * customer, exposed to the template as the `customFields` variable. The
36
- * deployment wires this — it holds the custom-field registry and reads the
37
- * entity's `custom_fields` column keeping `finance` decoupled from
38
- * `relationships`. Filter with `customFieldsVisibleIn(registry, entity,
39
- * "invoice")`. See docs/architecture/custom-fields-unification-adr.md.
34
+ * Resolve invoice-visible custom fields for this invoice's customer, exposed
35
+ * to the template as `customFields`. Selected graph runtimes receive this
36
+ * from the database-backed `custom-fields.runtime` port; optionality remains
37
+ * only for direct low-level service callers.
40
38
  */
41
39
  resolveCustomFields?: (db: PostgresJsDatabase, invoice: typeof invoices.$inferSelect) => Promise<Record<string, unknown>> | Record<string, unknown>;
42
40
  }
package/dist/voyant.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { actionLedgerFinanceDriftRuntimePort } from "@voyant-travel/action-ledger/runtime-port";
2
2
  import { bookingsFinanceRuntimePort } from "@voyant-travel/bookings/runtime-port";
3
3
  import { defineExtension, defineModule, providePort, requirePort, } from "@voyant-travel/core/project";
4
+ import { customFieldsRuntimePort } from "@voyant-travel/core/runtime-port";
4
5
  import { financeAccommodationsPaymentPolicyRuntimePort, financeCheckoutPaymentStartersRuntimePort, financeCruisesPaymentPolicyRuntimePort, financeDistributionPaymentPolicyRuntimePort, financeHostRuntimePort, financeInventoryPaymentPolicyRuntimePort, financeInvoiceSettlementPollerRuntimePort, financeNotificationsRuntimePort, financeOperatorSettingsRuntimePort, } from "./runtime-port.js";
5
6
  import { financeVoyantAdmin } from "./voyant-admin.js";
6
7
  import { bookingContractDocumentRequestedPayloadSchema, bookingCreatedPayloadSchema, bookingCreateRejectedPayloadSchema, bookingDualCreatedPayloadSchema, bookingPaymentSchedulePaidPayloadSchema, invoiceDocumentGeneratedPayloadSchema, invoiceIssuedPayloadSchema, invoicePaymentRecordedPayloadSchema, invoiceProformaConvertedPayloadSchema, invoiceRenderedPayloadSchema, invoiceSettledPayloadSchema, invoiceVoidedPayloadSchema, paymentCompletedPayloadSchema, } from "./voyant-event-schemas.js";
@@ -12,6 +13,7 @@ export const financeVoyantModule = defineModule({
12
13
  runtime: { entry: "@voyant-travel/finance", export: "createFinanceVoyantRuntime" },
13
14
  runtimePorts: [
14
15
  requirePort(financeHostRuntimePort),
16
+ requirePort(customFieldsRuntimePort),
15
17
  requirePort(financeNotificationsRuntimePort),
16
18
  requirePort(financeCheckoutPaymentStartersRuntimePort, { optional: true }),
17
19
  requirePort(financeInvoiceSettlementPollerRuntimePort, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyant-travel/finance",
3
- "version": "0.162.1",
3
+ "version": "0.163.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -145,17 +145,17 @@
145
145
  "fflate": "^0.8.2",
146
146
  "hono": "^4.12.27",
147
147
  "zod": "^4.4.3",
148
- "@voyant-travel/core": "^0.124.0",
149
- "@voyant-travel/db": "^0.114.8",
150
- "@voyant-travel/action-ledger": "^0.111.0",
151
- "@voyant-travel/bookings": "^0.162.1",
148
+ "@voyant-travel/action-ledger": "^0.111.1",
149
+ "@voyant-travel/bookings": "^0.163.0",
150
+ "@voyant-travel/core": "^0.125.0",
151
+ "@voyant-travel/db": "^0.114.9",
152
152
  "@voyant-travel/types": "^0.109.2",
153
- "@voyant-travel/finance-contracts": "^0.106.1",
154
- "@voyant-travel/hono": "^0.128.0",
155
- "@voyant-travel/public-document-delivery": "^0.4.0",
156
- "@voyant-travel/storage": "^0.111.0",
157
- "@voyant-travel/tools": "^0.3.0",
158
- "@voyant-travel/utils": "^0.107.1"
153
+ "@voyant-travel/finance-contracts": "^0.106.2",
154
+ "@voyant-travel/hono": "^0.128.1",
155
+ "@voyant-travel/public-document-delivery": "^0.4.1",
156
+ "@voyant-travel/storage": "^0.111.1",
157
+ "@voyant-travel/utils": "^0.107.1",
158
+ "@voyant-travel/tools": "^0.3.0"
159
159
  },
160
160
  "devDependencies": {
161
161
  "drizzle-kit": "^0.31.10",