@voyant-travel/commerce 0.1.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.
Files changed (210) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +145 -0
  3. package/dist/accepted-quote-version-reservation-golden-flow.test.d.ts +2 -0
  4. package/dist/accepted-quote-version-reservation-golden-flow.test.d.ts.map +1 -0
  5. package/dist/accepted-quote-version-reservation-golden-flow.test.js +398 -0
  6. package/dist/index.d.ts +15 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +14 -0
  9. package/dist/interface.d.ts +18 -0
  10. package/dist/interface.d.ts.map +1 -0
  11. package/dist/interface.js +246 -0
  12. package/dist/interface.test.d.ts +2 -0
  13. package/dist/interface.test.d.ts.map +1 -0
  14. package/dist/interface.test.js +357 -0
  15. package/dist/markets/index.d.ts +11 -0
  16. package/dist/markets/index.d.ts.map +1 -0
  17. package/dist/markets/index.js +12 -0
  18. package/dist/markets/routes.d.ts +1182 -0
  19. package/dist/markets/routes.d.ts.map +1 -0
  20. package/dist/markets/routes.js +209 -0
  21. package/dist/markets/schema.d.ts +1527 -0
  22. package/dist/markets/schema.d.ts.map +1 -0
  23. package/dist/markets/schema.js +240 -0
  24. package/dist/markets/service-core.d.ts +253 -0
  25. package/dist/markets/service-core.d.ts.map +1 -0
  26. package/dist/markets/service-core.js +242 -0
  27. package/dist/markets/service-rules.d.ts +191 -0
  28. package/dist/markets/service-rules.d.ts.map +1 -0
  29. package/dist/markets/service-rules.js +155 -0
  30. package/dist/markets/service-shared.d.ts +36 -0
  31. package/dist/markets/service-shared.d.ts.map +1 -0
  32. package/dist/markets/service-shared.js +7 -0
  33. package/dist/markets/service.d.ts +43 -0
  34. package/dist/markets/service.d.ts.map +1 -0
  35. package/dist/markets/service.js +42 -0
  36. package/dist/markets/validation.d.ts +451 -0
  37. package/dist/markets/validation.d.ts.map +1 -0
  38. package/dist/markets/validation.js +160 -0
  39. package/dist/pricing/events.d.ts +53 -0
  40. package/dist/pricing/events.d.ts.map +1 -0
  41. package/dist/pricing/events.js +28 -0
  42. package/dist/pricing/index.d.ts +15 -0
  43. package/dist/pricing/index.d.ts.map +1 -0
  44. package/dist/pricing/index.js +18 -0
  45. package/dist/pricing/routes-core.d.ts +981 -0
  46. package/dist/pricing/routes-core.d.ts.map +1 -0
  47. package/dist/pricing/routes-core.js +102 -0
  48. package/dist/pricing/routes-public.d.ts +136 -0
  49. package/dist/pricing/routes-public.d.ts.map +1 -0
  50. package/dist/pricing/routes-public.js +14 -0
  51. package/dist/pricing/routes-rules.d.ts +1339 -0
  52. package/dist/pricing/routes-rules.d.ts.map +1 -0
  53. package/dist/pricing/routes-rules.js +138 -0
  54. package/dist/pricing/routes-shared.d.ts +14 -0
  55. package/dist/pricing/routes-shared.d.ts.map +1 -0
  56. package/dist/pricing/routes-shared.js +3 -0
  57. package/dist/pricing/routes.d.ts +7 -0
  58. package/dist/pricing/routes.d.ts.map +1 -0
  59. package/dist/pricing/routes.js +6 -0
  60. package/dist/pricing/schema-catalogs.d.ts +467 -0
  61. package/dist/pricing/schema-catalogs.d.ts.map +1 -0
  62. package/dist/pricing/schema-catalogs.js +47 -0
  63. package/dist/pricing/schema-categories.d.ts +497 -0
  64. package/dist/pricing/schema-categories.d.ts.map +1 -0
  65. package/dist/pricing/schema-categories.js +54 -0
  66. package/dist/pricing/schema-departure-overrides.d.ts +228 -0
  67. package/dist/pricing/schema-departure-overrides.d.ts.map +1 -0
  68. package/dist/pricing/schema-departure-overrides.js +36 -0
  69. package/dist/pricing/schema-option-rules.d.ts +1770 -0
  70. package/dist/pricing/schema-option-rules.d.ts.map +1 -0
  71. package/dist/pricing/schema-option-rules.js +181 -0
  72. package/dist/pricing/schema-policies.d.ts +395 -0
  73. package/dist/pricing/schema-policies.d.ts.map +1 -0
  74. package/dist/pricing/schema-policies.js +41 -0
  75. package/dist/pricing/schema-relations.d.ts +59 -0
  76. package/dist/pricing/schema-relations.d.ts.map +1 -0
  77. package/dist/pricing/schema-relations.js +111 -0
  78. package/dist/pricing/schema-shared.d.ts +11 -0
  79. package/dist/pricing/schema-shared.d.ts.map +1 -0
  80. package/dist/pricing/schema-shared.js +67 -0
  81. package/dist/pricing/schema.d.ts +8 -0
  82. package/dist/pricing/schema.d.ts.map +1 -0
  83. package/dist/pricing/schema.js +7 -0
  84. package/dist/pricing/service-catalog-plane-pricing.d.ts +95 -0
  85. package/dist/pricing/service-catalog-plane-pricing.d.ts.map +1 -0
  86. package/dist/pricing/service-catalog-plane-pricing.js +382 -0
  87. package/dist/pricing/service-catalogs.d.ts +139 -0
  88. package/dist/pricing/service-catalogs.d.ts.map +1 -0
  89. package/dist/pricing/service-catalogs.js +89 -0
  90. package/dist/pricing/service-categories.d.ts +147 -0
  91. package/dist/pricing/service-categories.d.ts.map +1 -0
  92. package/dist/pricing/service-categories.js +105 -0
  93. package/dist/pricing/service-departure-overrides.d.ts +67 -0
  94. package/dist/pricing/service-departure-overrides.d.ts.map +1 -0
  95. package/dist/pricing/service-departure-overrides.js +54 -0
  96. package/dist/pricing/service-option-rules.d.ts +321 -0
  97. package/dist/pricing/service-option-rules.d.ts.map +1 -0
  98. package/dist/pricing/service-option-rules.js +340 -0
  99. package/dist/pricing/service-policies.d.ts +123 -0
  100. package/dist/pricing/service-policies.d.ts.map +1 -0
  101. package/dist/pricing/service-policies.js +95 -0
  102. package/dist/pricing/service-public.d.ts +89 -0
  103. package/dist/pricing/service-public.d.ts.map +1 -0
  104. package/dist/pricing/service-public.js +473 -0
  105. package/dist/pricing/service-rule-resolver.d.ts +67 -0
  106. package/dist/pricing/service-rule-resolver.d.ts.map +1 -0
  107. package/dist/pricing/service-rule-resolver.js +204 -0
  108. package/dist/pricing/service-shared.d.ts +53 -0
  109. package/dist/pricing/service-shared.d.ts.map +1 -0
  110. package/dist/pricing/service-shared.js +4 -0
  111. package/dist/pricing/service-transfer-rules.d.ts +211 -0
  112. package/dist/pricing/service-transfer-rules.d.ts.map +1 -0
  113. package/dist/pricing/service-transfer-rules.js +139 -0
  114. package/dist/pricing/service.d.ts +79 -0
  115. package/dist/pricing/service.d.ts.map +1 -0
  116. package/dist/pricing/service.js +78 -0
  117. package/dist/pricing/validation-public.d.ts +412 -0
  118. package/dist/pricing/validation-public.d.ts.map +1 -0
  119. package/dist/pricing/validation-public.js +111 -0
  120. package/dist/pricing/validation-shared.d.ts +71 -0
  121. package/dist/pricing/validation-shared.d.ts.map +1 -0
  122. package/dist/pricing/validation-shared.js +63 -0
  123. package/dist/pricing/validation.d.ts +987 -0
  124. package/dist/pricing/validation.d.ts.map +1 -0
  125. package/dist/pricing/validation.js +307 -0
  126. package/dist/promotions/events.d.ts +38 -0
  127. package/dist/promotions/events.d.ts.map +1 -0
  128. package/dist/promotions/events.js +25 -0
  129. package/dist/promotions/index.d.ts +12 -0
  130. package/dist/promotions/index.d.ts.map +1 -0
  131. package/dist/promotions/index.js +17 -0
  132. package/dist/promotions/routes-shared.d.ts +14 -0
  133. package/dist/promotions/routes-shared.d.ts.map +1 -0
  134. package/dist/promotions/routes-shared.js +3 -0
  135. package/dist/promotions/routes.d.ts +395 -0
  136. package/dist/promotions/routes.d.ts.map +1 -0
  137. package/dist/promotions/routes.js +55 -0
  138. package/dist/promotions/schema.d.ts +675 -0
  139. package/dist/promotions/schema.d.ts.map +1 -0
  140. package/dist/promotions/schema.js +126 -0
  141. package/dist/promotions/service-booking-confirmed.d.ts +77 -0
  142. package/dist/promotions/service-booking-confirmed.d.ts.map +1 -0
  143. package/dist/promotions/service-booking-confirmed.js +134 -0
  144. package/dist/promotions/service-boundary-scheduler.d.ts +85 -0
  145. package/dist/promotions/service-boundary-scheduler.d.ts.map +1 -0
  146. package/dist/promotions/service-boundary-scheduler.js +141 -0
  147. package/dist/promotions/service-catalog-evaluator.d.ts +22 -0
  148. package/dist/promotions/service-catalog-evaluator.d.ts.map +1 -0
  149. package/dist/promotions/service-catalog-evaluator.js +33 -0
  150. package/dist/promotions/service-catalog-plane-promotions.d.ts +73 -0
  151. package/dist/promotions/service-catalog-plane-promotions.d.ts.map +1 -0
  152. package/dist/promotions/service-catalog-plane-promotions.js +118 -0
  153. package/dist/promotions/service-evaluator.d.ts +134 -0
  154. package/dist/promotions/service-evaluator.d.ts.map +1 -0
  155. package/dist/promotions/service-evaluator.js +302 -0
  156. package/dist/promotions/service-storefront.d.ts +147 -0
  157. package/dist/promotions/service-storefront.d.ts.map +1 -0
  158. package/dist/promotions/service-storefront.js +326 -0
  159. package/dist/promotions/service.d.ts +143 -0
  160. package/dist/promotions/service.d.ts.map +1 -0
  161. package/dist/promotions/service.js +359 -0
  162. package/dist/promotions/validation.d.ts +195 -0
  163. package/dist/promotions/validation.d.ts.map +1 -0
  164. package/dist/promotions/validation.js +167 -0
  165. package/dist/promotions/workflow-bulk-reindex.d.ts +36 -0
  166. package/dist/promotions/workflow-bulk-reindex.d.ts.map +1 -0
  167. package/dist/promotions/workflow-bulk-reindex.js +53 -0
  168. package/dist/promotions/workflow-runtime.d.ts +17 -0
  169. package/dist/promotions/workflow-runtime.d.ts.map +1 -0
  170. package/dist/promotions/workflow-runtime.js +9 -0
  171. package/dist/runtime.d.ts +18 -0
  172. package/dist/runtime.d.ts.map +1 -0
  173. package/dist/runtime.js +27 -0
  174. package/dist/runtime.test.d.ts +2 -0
  175. package/dist/runtime.test.d.ts.map +1 -0
  176. package/dist/runtime.test.js +25 -0
  177. package/dist/schema.d.ts +5 -0
  178. package/dist/schema.d.ts.map +1 -0
  179. package/dist/schema.js +4 -0
  180. package/dist/sellability/index.d.ts +13 -0
  181. package/dist/sellability/index.d.ts.map +1 -0
  182. package/dist/sellability/index.js +17 -0
  183. package/dist/sellability/routes.d.ts +2332 -0
  184. package/dist/sellability/routes.d.ts.map +1 -0
  185. package/dist/sellability/routes.js +166 -0
  186. package/dist/sellability/schema.d.ts +1716 -0
  187. package/dist/sellability/schema.d.ts.map +1 -0
  188. package/dist/sellability/schema.js +278 -0
  189. package/dist/sellability/service-records.d.ts +316 -0
  190. package/dist/sellability/service-records.d.ts.map +1 -0
  191. package/dist/sellability/service-records.js +253 -0
  192. package/dist/sellability/service-resolve.d.ts +72 -0
  193. package/dist/sellability/service-resolve.d.ts.map +1 -0
  194. package/dist/sellability/service-resolve.js +580 -0
  195. package/dist/sellability/service-shared.d.ts +124 -0
  196. package/dist/sellability/service-shared.d.ts.map +1 -0
  197. package/dist/sellability/service-shared.js +96 -0
  198. package/dist/sellability/service-snapshots.d.ts +191 -0
  199. package/dist/sellability/service-snapshots.d.ts.map +1 -0
  200. package/dist/sellability/service-snapshots.js +153 -0
  201. package/dist/sellability/service.d.ts +1038 -0
  202. package/dist/sellability/service.d.ts.map +1 -0
  203. package/dist/sellability/service.js +17 -0
  204. package/dist/sellability/validation.d.ts +477 -0
  205. package/dist/sellability/validation.d.ts.map +1 -0
  206. package/dist/sellability/validation.js +192 -0
  207. package/dist/types.d.ts +239 -0
  208. package/dist/types.d.ts.map +1 -0
  209. package/dist/types.js +1 -0
  210. package/package.json +62 -0
@@ -0,0 +1,398 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createCommercialDecisionEvaluator, recordCommercialSnapshot, } from "./index.js";
3
+ const acceptedQuoteVersionId = "qver_1793_accepted";
4
+ const quoteId = "quote_1793";
5
+ const frozenTripSnapshotId = "trsn_1793_frozen";
6
+ const reservationPlanId = "trplan_1793";
7
+ const bookingId = "book_1793";
8
+ const eur = (amountMinor) => ({ amountMinor, currency: "EUR" });
9
+ const expectedModuleInterfaces = [
10
+ "Quotes.acceptQuoteVersion",
11
+ "Trips.prepareReservationPlanForAcceptedQuoteVersion",
12
+ "Commerce.evaluateCommercialDecision",
13
+ "Commerce.recordCommercialSnapshot",
14
+ "Bookings.submitReservationPlan",
15
+ "Finance.startCollection",
16
+ "Legal.attachPolicyAndTermsTargets",
17
+ ];
18
+ const expectedDurableOwnerRecords = [
19
+ "Quotes:quote_versions.status",
20
+ "Quotes:quotes.acceptedVersionId",
21
+ "Trips:trip_reservation_plans",
22
+ "Commerce:commercial_snapshots",
23
+ "Bookings:booking_origins",
24
+ "Bookings:bookings",
25
+ "Bookings:booking_items",
26
+ "Bookings:booking_travelers",
27
+ "Bookings:booking_allocations",
28
+ "Bookings:booking_fulfillments",
29
+ "Finance:payment_sessions",
30
+ "Legal:policy_acceptances",
31
+ "Legal:contracts",
32
+ ];
33
+ const pricedLineInput = {
34
+ item: {
35
+ kind: "catalog-item",
36
+ id: "catalog_item_cruise_1793",
37
+ source: "sourced",
38
+ vertical: "cruise",
39
+ adapterHint: "golden-flow-source",
40
+ sourceRef: {
41
+ providerId: "cruise-provider",
42
+ sourceId: "source_cruise",
43
+ externalRef: "sailing_1793",
44
+ },
45
+ },
46
+ date: "2026-09-18",
47
+ party: {
48
+ pax: 2,
49
+ adults: 2,
50
+ },
51
+ currency: "EUR",
52
+ buyer: {
53
+ actorType: "customer",
54
+ relationshipId: "relationship_b2b_buyer",
55
+ },
56
+ channel: {
57
+ id: "channel_direct",
58
+ kind: "direct",
59
+ },
60
+ market: {
61
+ id: "market_eu",
62
+ code: "EU",
63
+ currency: "EUR",
64
+ },
65
+ requestedAt: "2026-06-13T09:00:00.000Z",
66
+ idempotencyKey: `${acceptedQuoteVersionId}:catalog_item_cruise_1793`,
67
+ evaluationMode: "checkout",
68
+ };
69
+ const sourceAdapter = {
70
+ id: "golden-flow-source",
71
+ kind: "source",
72
+ supports(input) {
73
+ return input.item.adapterHint === "golden-flow-source";
74
+ },
75
+ evaluate(input) {
76
+ return {
77
+ status: "available",
78
+ validUntil: "2026-06-13T09:15:00.000Z",
79
+ pricing: {
80
+ currency: input.currency,
81
+ total: eur(192000),
82
+ components: [
83
+ {
84
+ kind: "base",
85
+ label: "Cabin fare",
86
+ amount: eur(192000),
87
+ ruleId: "fare_rule_1793",
88
+ },
89
+ ],
90
+ priceRuleIds: ["fare_rule_1793"],
91
+ },
92
+ availability: {
93
+ status: "available",
94
+ capacityRemaining: 4,
95
+ },
96
+ sellability: {
97
+ status: "allowed",
98
+ policyIds: ["sellability_policy_b2b"],
99
+ },
100
+ handles: [
101
+ {
102
+ providerId: "cruise-provider",
103
+ sourceId: "source_cruise",
104
+ externalRef: "source_quote_1793",
105
+ handle: "source_quote_handle_1793",
106
+ },
107
+ ],
108
+ };
109
+ },
110
+ };
111
+ describe("accepted Quote Version reservation golden flow", () => {
112
+ it("names ownership from accepted Quote Version through reservation, collection, and legal targets", async () => {
113
+ const flow = await runAcceptedQuoteVersionReservationGoldenFlow();
114
+ expect(flow.calls.map((call) => call.interfaceName)).toEqual(expectedModuleInterfaces);
115
+ expect(flow.durableRecords.map(formatDurableRecord)).toEqual(expectedDurableOwnerRecords);
116
+ expect(flow.quote.acceptedVersionId).toBe(acceptedQuoteVersionId);
117
+ expect(flow.quote.status).toBe("won");
118
+ expect(flow.quote.versions.filter((version) => version.status === "accepted")).toHaveLength(1);
119
+ expect(flow.quote.versions.find((version) => version.id !== acceptedQuoteVersionId)?.status).toBe("declined");
120
+ expect(flow.handoff).toEqual({
121
+ kind: "accepted_quote_version",
122
+ quoteId,
123
+ quoteVersionId: acceptedQuoteVersionId,
124
+ tripSnapshotRef: {
125
+ owner: "Trips",
126
+ id: frozenTripSnapshotId,
127
+ },
128
+ });
129
+ expect(flow.tripsReservedInventoryDirectly).toBe(false);
130
+ expect(flow.reservationPlan).toMatchObject({
131
+ id: reservationPlanId,
132
+ origin: "accepted_quote_version",
133
+ quoteVersionId: acceptedQuoteVersionId,
134
+ tripSnapshotId: frozenTripSnapshotId,
135
+ });
136
+ expect(flow.reservationPlan.inputs).toEqual([
137
+ expect.objectContaining({
138
+ componentId: "trcp_priced_catalog",
139
+ commercialDecisionId: expect.stringMatching(/^commercial_decision_/),
140
+ commercialSnapshotId: "commercial_snapshot_1",
141
+ }),
142
+ expect.objectContaining({
143
+ componentId: "trcp_manual_supplier",
144
+ confirmationWorkflow: "staff_supplier_confirmation",
145
+ }),
146
+ ]);
147
+ expect(flow.bookings.supportedReservationOrigins).toEqual([
148
+ "direct_b2c",
149
+ "accepted_quote_version",
150
+ ]);
151
+ expect(flow.bookings.origin).toMatchObject({
152
+ bookingId,
153
+ source: "accepted_quote_version",
154
+ quoteVersionId: acceptedQuoteVersionId,
155
+ tripSnapshotId: frozenTripSnapshotId,
156
+ reservationPlanId,
157
+ commercialSnapshotIds: ["commercial_snapshot_1"],
158
+ });
159
+ expect(flow.financeCollectionTarget).toEqual({
160
+ targetType: "booking",
161
+ targetId: bookingId,
162
+ amountMinor: 192000,
163
+ currency: "EUR",
164
+ });
165
+ expect(flow.legalTargets).toEqual([
166
+ { targetType: "booking", targetId: bookingId, targetPurpose: "terms_acceptance" },
167
+ {
168
+ targetType: "quote_version",
169
+ targetId: acceptedQuoteVersionId,
170
+ targetPurpose: "proposal_contract",
171
+ },
172
+ ]);
173
+ assertNoLegacyTransactionLadder(flow);
174
+ });
175
+ });
176
+ async function runAcceptedQuoteVersionReservationGoldenFlow() {
177
+ const calls = [];
178
+ const durableRecords = [];
179
+ const quote = {
180
+ id: quoteId,
181
+ status: "open",
182
+ acceptedVersionId: null,
183
+ versions: [
184
+ {
185
+ id: acceptedQuoteVersionId,
186
+ status: "sent",
187
+ tripSnapshotId: frozenTripSnapshotId,
188
+ },
189
+ {
190
+ id: "qver_1793_alternative",
191
+ status: "sent",
192
+ tripSnapshotId: "trsn_1793_alternative",
193
+ },
194
+ ],
195
+ };
196
+ const quotes = {
197
+ acceptQuoteVersion(versionId) {
198
+ calls.push({ interfaceName: "Quotes.acceptQuoteVersion" });
199
+ const accepted = quote.versions.find((version) => version.id === versionId);
200
+ if (!accepted || accepted.status !== "sent") {
201
+ throw new Error("Quote Version must be sent before acceptance");
202
+ }
203
+ quote.status = "won";
204
+ quote.acceptedVersionId = accepted.id;
205
+ quote.versions = quote.versions.map((version) => ({
206
+ ...version,
207
+ status: version.id === accepted.id
208
+ ? "accepted"
209
+ : version.status === "draft"
210
+ ? "superseded"
211
+ : "declined",
212
+ }));
213
+ durableRecords.push({
214
+ owner: "Quotes",
215
+ record: "quote_versions.status",
216
+ }, {
217
+ owner: "Quotes",
218
+ record: "quotes.acceptedVersionId",
219
+ });
220
+ return {
221
+ kind: "accepted_quote_version",
222
+ quoteId: quote.id,
223
+ quoteVersionId: accepted.id,
224
+ tripSnapshotRef: {
225
+ owner: "Trips",
226
+ id: accepted.tripSnapshotId,
227
+ },
228
+ };
229
+ },
230
+ };
231
+ const evaluator = createCommercialDecisionEvaluator({ adapters: [sourceAdapter] });
232
+ const repository = createSnapshotRepository(durableRecords);
233
+ const trips = {
234
+ reservedInventoryDirectly: false,
235
+ async prepareReservationPlanForAcceptedQuoteVersion(handoff) {
236
+ calls.push({ interfaceName: "Trips.prepareReservationPlanForAcceptedQuoteVersion" });
237
+ durableRecords.push({
238
+ owner: "Trips",
239
+ record: "trip_reservation_plans",
240
+ });
241
+ calls.push({ interfaceName: "Commerce.evaluateCommercialDecision" });
242
+ const decision = await evaluator.evaluateCommercialDecision(pricedLineInput);
243
+ calls.push({ interfaceName: "Commerce.recordCommercialSnapshot" });
244
+ const snapshot = await recordCommercialSnapshot(decision, {
245
+ kind: "trip-component",
246
+ id: "trcp_priced_catalog",
247
+ facts: {
248
+ quoteVersionId: handoff.quoteVersionId,
249
+ tripSnapshotId: handoff.tripSnapshotRef.id,
250
+ reservationPlanId,
251
+ },
252
+ }, repository);
253
+ return {
254
+ id: reservationPlanId,
255
+ origin: "accepted_quote_version",
256
+ quoteId: handoff.quoteId,
257
+ quoteVersionId: handoff.quoteVersionId,
258
+ tripSnapshotId: handoff.tripSnapshotRef.id,
259
+ inputs: [
260
+ {
261
+ componentId: "trcp_priced_catalog",
262
+ kind: "catalog_backed",
263
+ commercialDecisionId: decision.decisionId,
264
+ commercialSnapshotId: snapshot.snapshotId,
265
+ providerHandles: decision.handles,
266
+ },
267
+ {
268
+ componentId: "trcp_manual_supplier",
269
+ kind: "manual_placeholder",
270
+ quotedAmountMinor: 65000,
271
+ currency: "EUR",
272
+ confirmationWorkflow: "staff_supplier_confirmation",
273
+ },
274
+ ],
275
+ };
276
+ },
277
+ };
278
+ const bookings = {
279
+ supportedReservationOrigins: ["direct_b2c", "accepted_quote_version"],
280
+ submitReservationPlan(plan) {
281
+ calls.push({ interfaceName: "Bookings.submitReservationPlan" });
282
+ const origin = {
283
+ bookingId,
284
+ source: "accepted_quote_version",
285
+ quoteId: plan.quoteId,
286
+ quoteVersionId: plan.quoteVersionId,
287
+ tripSnapshotId: plan.tripSnapshotId,
288
+ reservationPlanId: plan.id,
289
+ commercialSnapshotIds: plan.inputs.flatMap((input) => "commercialSnapshotId" in input ? [input.commercialSnapshotId] : []),
290
+ providerSourceRefs: plan.inputs.flatMap((input) => "providerHandles" in input && Array.isArray(input.providerHandles)
291
+ ? input.providerHandles.map((handle) => handle.externalRef ?? handle.handle ?? null)
292
+ : []),
293
+ legacyTransactionRef: null,
294
+ };
295
+ durableRecords.push({ owner: "Bookings", record: "booking_origins" }, { owner: "Bookings", record: "bookings" }, { owner: "Bookings", record: "booking_items" }, { owner: "Bookings", record: "booking_travelers" }, { owner: "Bookings", record: "booking_allocations" }, { owner: "Bookings", record: "booking_fulfillments" });
296
+ return {
297
+ bookingId,
298
+ status: "awaiting_payment",
299
+ origin,
300
+ };
301
+ },
302
+ };
303
+ const finance = {
304
+ startCollection(input) {
305
+ calls.push({ interfaceName: "Finance.startCollection" });
306
+ durableRecords.push({
307
+ owner: "Finance",
308
+ record: "payment_sessions",
309
+ });
310
+ return {
311
+ targetType: "booking",
312
+ targetId: input.bookingId,
313
+ amountMinor: input.amountMinor,
314
+ currency: input.currency,
315
+ };
316
+ },
317
+ };
318
+ const legal = {
319
+ attachPolicyAndTermsTargets(input) {
320
+ calls.push({ interfaceName: "Legal.attachPolicyAndTermsTargets" });
321
+ durableRecords.push({
322
+ owner: "Legal",
323
+ record: "policy_acceptances",
324
+ }, {
325
+ owner: "Legal",
326
+ record: "contracts",
327
+ });
328
+ return [
329
+ {
330
+ targetType: "booking",
331
+ targetId: input.bookingId,
332
+ targetPurpose: "terms_acceptance",
333
+ },
334
+ {
335
+ targetType: "quote_version",
336
+ targetId: input.quoteVersionId,
337
+ targetPurpose: "proposal_contract",
338
+ },
339
+ ];
340
+ },
341
+ };
342
+ const handoff = quotes.acceptQuoteVersion(acceptedQuoteVersionId);
343
+ const reservationPlan = await trips.prepareReservationPlanForAcceptedQuoteVersion(handoff);
344
+ const booking = bookings.submitReservationPlan(reservationPlan);
345
+ const financeCollectionTarget = finance.startCollection({
346
+ bookingId: booking.bookingId,
347
+ amountMinor: 192000,
348
+ currency: "EUR",
349
+ });
350
+ const legalTargets = legal.attachPolicyAndTermsTargets({
351
+ bookingId: booking.bookingId,
352
+ quoteVersionId: acceptedQuoteVersionId,
353
+ });
354
+ return {
355
+ calls,
356
+ durableRecords,
357
+ quote,
358
+ handoff,
359
+ reservationPlan,
360
+ tripsReservedInventoryDirectly: trips.reservedInventoryDirectly,
361
+ bookings: {
362
+ supportedReservationOrigins: bookings.supportedReservationOrigins,
363
+ origin: booking.origin,
364
+ },
365
+ financeCollectionTarget,
366
+ legalTargets,
367
+ };
368
+ }
369
+ function createSnapshotRepository(durableRecords) {
370
+ let writeCount = 0;
371
+ return {
372
+ async recordCommercialSnapshot(write) {
373
+ writeCount += 1;
374
+ durableRecords.push({
375
+ owner: "Commerce",
376
+ record: "commercial_snapshots",
377
+ });
378
+ return {
379
+ snapshotId: `commercial_snapshot_${writeCount}`,
380
+ decisionId: write.decision.decisionId,
381
+ target: write.target,
382
+ idempotencyKey: write.idempotencyKey,
383
+ recordedAt: "2026-06-13T09:01:00.000Z",
384
+ };
385
+ },
386
+ };
387
+ }
388
+ function formatDurableRecord(record) {
389
+ return `${record.owner}:${record.record}`;
390
+ }
391
+ function assertNoLegacyTransactionLadder(value) {
392
+ const serialized = JSON.stringify(value);
393
+ expect(serialized).not.toContain("booking_transaction_details");
394
+ expect(serialized).not.toContain("transactions.");
395
+ expect(serialized).not.toContain('"offerId"');
396
+ expect(serialized).not.toContain('"orderId"');
397
+ expect(serialized).not.toContain('"transactionOrderId"');
398
+ }
@@ -0,0 +1,15 @@
1
+ import type { Module } from "@voyant-travel/core";
2
+ export declare const commerceModule: Module;
3
+ export { CommercialDecisionError, createCommerceAdapterRegistry, createCommercialDecisionEvaluator, evaluateCommercialDecision, recordCommercialSnapshot, } from "./interface.js";
4
+ export * from "./markets/index.js";
5
+ export * from "./pricing/index.js";
6
+ export { createProductPricingProjectionExtension, loadProductPriceFrom, } from "./pricing/service-catalog-plane-pricing.js";
7
+ export * from "./promotions/index.js";
8
+ export { recordPromotionRedemptionsForBooking } from "./promotions/service-booking-confirmed.js";
9
+ export { type BoundarySchedulerResult, runPromotionBoundaryScheduler, } from "./promotions/service-boundary-scheduler.js";
10
+ export { createCatalogPromotionEvaluator } from "./promotions/service-catalog-evaluator.js";
11
+ export { createProductPromotionsProjectionExtension } from "./promotions/service-catalog-plane-promotions.js";
12
+ export { type CommerceHonoModulesOptions, type CommerceRuntimeModuleName, commerceRuntimeModuleNames, createCommerceHonoModules, createCommerceStorefrontOfferResolvers, } from "./runtime.js";
13
+ export * from "./sellability/index.js";
14
+ export type { CommercialAdapterHandle, CommercialAdapterRegistrationKind, CommercialAvailabilityFact, CommercialBuyerRef, CommercialChannelRef, CommercialCurrencyCode, CommercialDecision, CommercialDecisionErrorCode, CommercialDecisionEvaluationContext, CommercialDecisionEvaluator, CommercialDecisionInput, CommercialDecisionReason, CommercialDecisionStatus, CommercialDecisionTrace, CommercialDecisionTraceOutcome, CommercialDecisionTraceSource, CommercialFxFact, CommercialItemRef, CommercialJson, CommercialMarketRef, CommercialMoney, CommercialParty, CommercialPriceAvailabilityAdapter, CommercialPriceAvailabilityResult, CommercialPricingComponent, CommercialPricingFacts, CommercialPromotionFact, CommercialPromotionFacts, CommercialProviderHandle, CommercialSellabilityFact, CommercialSnapshotRecord, CommercialSnapshotRepository, CommercialSnapshotTarget, CommercialSnapshotWriteInput, EvaluateCommercialDecision, } from "./types.js";
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAEjD,eAAO,MAAM,cAAc,EAAE,MAE5B,CAAA;AAED,OAAO,EACL,uBAAuB,EACvB,6BAA6B,EAC7B,iCAAiC,EACjC,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,gBAAgB,CAAA;AACvB,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,OAAO,EACL,uCAAuC,EACvC,oBAAoB,GACrB,MAAM,4CAA4C,CAAA;AACnD,cAAc,uBAAuB,CAAA;AACrC,OAAO,EAAE,oCAAoC,EAAE,MAAM,2CAA2C,CAAA;AAChG,OAAO,EACL,KAAK,uBAAuB,EAC5B,6BAA6B,GAC9B,MAAM,4CAA4C,CAAA;AACnD,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAA;AAC3F,OAAO,EAAE,0CAA0C,EAAE,MAAM,kDAAkD,CAAA;AAC7G,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,yBAAyB,EAC9B,0BAA0B,EAC1B,yBAAyB,EACzB,sCAAsC,GACvC,MAAM,cAAc,CAAA;AACrB,cAAc,wBAAwB,CAAA;AACtC,YAAY,EACV,uBAAuB,EACvB,iCAAiC,EACjC,0BAA0B,EAC1B,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,mCAAmC,EACnC,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,8BAA8B,EAC9B,6BAA6B,EAC7B,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,kCAAkC,EAClC,iCAAiC,EACjC,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,yBAAyB,EACzB,wBAAwB,EACxB,4BAA4B,EAC5B,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,GAC3B,MAAM,YAAY,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ export const commerceModule = {
2
+ name: "commerce",
3
+ };
4
+ export { CommercialDecisionError, createCommerceAdapterRegistry, createCommercialDecisionEvaluator, evaluateCommercialDecision, recordCommercialSnapshot, } from "./interface.js";
5
+ export * from "./markets/index.js";
6
+ export * from "./pricing/index.js";
7
+ export { createProductPricingProjectionExtension, loadProductPriceFrom, } from "./pricing/service-catalog-plane-pricing.js";
8
+ export * from "./promotions/index.js";
9
+ export { recordPromotionRedemptionsForBooking } from "./promotions/service-booking-confirmed.js";
10
+ export { runPromotionBoundaryScheduler, } from "./promotions/service-boundary-scheduler.js";
11
+ export { createCatalogPromotionEvaluator } from "./promotions/service-catalog-evaluator.js";
12
+ export { createProductPromotionsProjectionExtension } from "./promotions/service-catalog-plane-promotions.js";
13
+ export { commerceRuntimeModuleNames, createCommerceHonoModules, createCommerceStorefrontOfferResolvers, } from "./runtime.js";
14
+ export * from "./sellability/index.js";
@@ -0,0 +1,18 @@
1
+ import type { CommercialDecision, CommercialDecisionErrorCode, CommercialDecisionEvaluationContext, CommercialDecisionEvaluator, CommercialDecisionInput, CommercialPriceAvailabilityAdapter, CommercialSnapshotRecord, CommercialSnapshotRepository, CommercialSnapshotTarget } from "./types.js";
2
+ export declare class CommercialDecisionError extends Error {
3
+ readonly code: CommercialDecisionErrorCode;
4
+ constructor(message: string, code: CommercialDecisionErrorCode);
5
+ }
6
+ export declare function createCommerceAdapterRegistry(adapters?: CommercialPriceAvailabilityAdapter[]): {
7
+ listAdapters: () => CommercialPriceAvailabilityAdapter[];
8
+ registerPriceAvailabilityAdapter: (adapter: CommercialPriceAvailabilityAdapter) => void;
9
+ resolveAdapter: (input: CommercialDecisionInput) => Promise<CommercialPriceAvailabilityAdapter | null>;
10
+ };
11
+ export declare function evaluateCommercialDecision(input: CommercialDecisionInput, context?: CommercialDecisionEvaluationContext & {
12
+ registry?: ReturnType<typeof createCommerceAdapterRegistry>;
13
+ }): Promise<CommercialDecision>;
14
+ export declare function createCommercialDecisionEvaluator(options?: {
15
+ adapters?: CommercialPriceAvailabilityAdapter[];
16
+ }): CommercialDecisionEvaluator;
17
+ export declare function recordCommercialSnapshot(decision: CommercialDecision, target: CommercialSnapshotTarget, repository: CommercialSnapshotRepository): Promise<CommercialSnapshotRecord>;
18
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../src/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAIV,kBAAkB,EAClB,2BAA2B,EAC3B,mCAAmC,EACnC,2BAA2B,EAC3B,uBAAuB,EAQvB,kCAAkC,EAMlC,wBAAwB,EACxB,4BAA4B,EAC5B,wBAAwB,EACzB,MAAM,YAAY,CAAA;AAEnB,qBAAa,uBAAwB,SAAQ,KAAK;IAG9C,QAAQ,CAAC,IAAI,EAAE,2BAA2B;gBAD1C,OAAO,EAAE,MAAM,EACN,IAAI,EAAE,2BAA2B;CAK7C;AAED,wBAAgB,6BAA6B,CAAC,QAAQ,GAAE,kCAAkC,EAAO;;gDAG5C,kCAAkC;4BAUhD,uBAAuB;EAmC7D;AAED,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,uBAAuB,EAC9B,OAAO,GAAE,mCAAmC,GAAG;IAC7C,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,6BAA6B,CAAC,CAAA;CACvD,GACL,OAAO,CAAC,kBAAkB,CAAC,CAqH7B;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,kCAAkC,EAAE,CAAA;CAAO,GAChE,2BAA2B,CAQ7B;AAED,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,kBAAkB,EAC5B,MAAM,EAAE,wBAAwB,EAChC,UAAU,EAAE,4BAA4B,GACvC,OAAO,CAAC,wBAAwB,CAAC,CAMnC"}