@voyant-travel/finance 0.119.5

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 (294) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +192 -0
  3. package/dist/action-ledger-drift.d.ts +29 -0
  4. package/dist/action-ledger-drift.d.ts.map +1 -0
  5. package/dist/action-ledger-drift.js +166 -0
  6. package/dist/booking-tax.d.ts +124 -0
  7. package/dist/booking-tax.d.ts.map +1 -0
  8. package/dist/booking-tax.js +264 -0
  9. package/dist/checkout-routes.d.ts +1154 -0
  10. package/dist/checkout-routes.d.ts.map +1 -0
  11. package/dist/checkout-routes.js +116 -0
  12. package/dist/checkout-service-plan.d.ts +137 -0
  13. package/dist/checkout-service-plan.d.ts.map +1 -0
  14. package/dist/checkout-service-plan.js +119 -0
  15. package/dist/checkout-service.d.ts +9 -0
  16. package/dist/checkout-service.d.ts.map +1 -0
  17. package/dist/checkout-service.js +324 -0
  18. package/dist/checkout-validation.d.ts +1682 -0
  19. package/dist/checkout-validation.d.ts.map +1 -0
  20. package/dist/checkout-validation.js +228 -0
  21. package/dist/document-download.d.ts +3 -0
  22. package/dist/document-download.d.ts.map +1 -0
  23. package/dist/document-download.js +1 -0
  24. package/dist/fx-money.d.ts +17 -0
  25. package/dist/fx-money.d.ts.map +1 -0
  26. package/dist/fx-money.js +194 -0
  27. package/dist/index.d.ts +65 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +108 -0
  30. package/dist/invoice-fx.d.ts +134 -0
  31. package/dist/invoice-fx.d.ts.map +1 -0
  32. package/dist/invoice-fx.js +240 -0
  33. package/dist/invoice-number-errors.d.ts +2 -0
  34. package/dist/invoice-number-errors.d.ts.map +1 -0
  35. package/dist/invoice-number-errors.js +58 -0
  36. package/dist/markets-ref.d.ts +149 -0
  37. package/dist/markets-ref.d.ts.map +1 -0
  38. package/dist/markets-ref.js +17 -0
  39. package/dist/payment-link.d.ts +23 -0
  40. package/dist/payment-link.d.ts.map +1 -0
  41. package/dist/payment-link.js +30 -0
  42. package/dist/payment-policy.d.ts +113 -0
  43. package/dist/payment-policy.d.ts.map +1 -0
  44. package/dist/payment-policy.js +193 -0
  45. package/dist/route-runtime.d.ts +22 -0
  46. package/dist/route-runtime.d.ts.map +1 -0
  47. package/dist/route-runtime.js +18 -0
  48. package/dist/routes-action-ledger.d.ts +181 -0
  49. package/dist/routes-action-ledger.d.ts.map +1 -0
  50. package/dist/routes-action-ledger.js +142 -0
  51. package/dist/routes-booking-billing.d.ts +852 -0
  52. package/dist/routes-booking-billing.d.ts.map +1 -0
  53. package/dist/routes-booking-billing.js +223 -0
  54. package/dist/routes-booking-create.d.ts +3 -0
  55. package/dist/routes-booking-create.d.ts.map +1 -0
  56. package/dist/routes-booking-create.js +194 -0
  57. package/dist/routes-booking-reads.d.ts +46 -0
  58. package/dist/routes-booking-reads.d.ts.map +1 -0
  59. package/dist/routes-booking-reads.js +20 -0
  60. package/dist/routes-documents.d.ts +195 -0
  61. package/dist/routes-documents.d.ts.map +1 -0
  62. package/dist/routes-documents.js +93 -0
  63. package/dist/routes-invoice-core.d.ts +794 -0
  64. package/dist/routes-invoice-core.d.ts.map +1 -0
  65. package/dist/routes-invoice-core.js +238 -0
  66. package/dist/routes-invoice-documents.d.ts +401 -0
  67. package/dist/routes-invoice-documents.d.ts.map +1 -0
  68. package/dist/routes-invoice-documents.js +91 -0
  69. package/dist/routes-invoice-issue.d.ts +384 -0
  70. package/dist/routes-invoice-issue.d.ts.map +1 -0
  71. package/dist/routes-invoice-issue.js +208 -0
  72. package/dist/routes-payment-processing.d.ts +1193 -0
  73. package/dist/routes-payment-processing.d.ts.map +1 -0
  74. package/dist/routes-payment-processing.js +238 -0
  75. package/dist/routes-payments.d.ts +309 -0
  76. package/dist/routes-payments.d.ts.map +1 -0
  77. package/dist/routes-payments.js +94 -0
  78. package/dist/routes-public.d.ts +1948 -0
  79. package/dist/routes-public.d.ts.map +1 -0
  80. package/dist/routes-public.js +275 -0
  81. package/dist/routes-reference-data.d.ts +977 -0
  82. package/dist/routes-reference-data.d.ts.map +1 -0
  83. package/dist/routes-reference-data.js +191 -0
  84. package/dist/routes-reports.d.ts +344 -0
  85. package/dist/routes-reports.d.ts.map +1 -0
  86. package/dist/routes-reports.js +93 -0
  87. package/dist/routes-runtime.d.ts +71 -0
  88. package/dist/routes-runtime.d.ts.map +1 -0
  89. package/dist/routes-runtime.js +59 -0
  90. package/dist/routes-settlement.d.ts +67 -0
  91. package/dist/routes-settlement.d.ts.map +1 -0
  92. package/dist/routes-settlement.js +23 -0
  93. package/dist/routes-shared.d.ts +35 -0
  94. package/dist/routes-shared.d.ts.map +1 -0
  95. package/dist/routes-shared.js +10 -0
  96. package/dist/routes-supplier-invoices.d.ts +778 -0
  97. package/dist/routes-supplier-invoices.d.ts.map +1 -0
  98. package/dist/routes-supplier-invoices.js +159 -0
  99. package/dist/routes-vouchers.d.ts +228 -0
  100. package/dist/routes-vouchers.d.ts.map +1 -0
  101. package/dist/routes-vouchers.js +54 -0
  102. package/dist/routes.d.ts +5577 -0
  103. package/dist/routes.d.ts.map +1 -0
  104. package/dist/routes.js +44 -0
  105. package/dist/schema/booking-billing.d.ts +1006 -0
  106. package/dist/schema/booking-billing.d.ts.map +1 -0
  107. package/dist/schema/booking-billing.js +106 -0
  108. package/dist/schema/enums.d.ts +48 -0
  109. package/dist/schema/enums.d.ts.map +1 -0
  110. package/dist/schema/enums.js +237 -0
  111. package/dist/schema/invoice-documents.d.ts +1245 -0
  112. package/dist/schema/invoice-documents.d.ts.map +1 -0
  113. package/dist/schema/invoice-documents.js +140 -0
  114. package/dist/schema/payment-instruments.d.ts +418 -0
  115. package/dist/schema/payment-instruments.d.ts.map +1 -0
  116. package/dist/schema/payment-instruments.js +45 -0
  117. package/dist/schema/payment-processing.d.ts +563 -0
  118. package/dist/schema/payment-processing.d.ts.map +1 -0
  119. package/dist/schema/payment-processing.js +65 -0
  120. package/dist/schema/payment-sessions.d.ts +728 -0
  121. package/dist/schema/payment-sessions.d.ts.map +1 -0
  122. package/dist/schema/payment-sessions.js +79 -0
  123. package/dist/schema/receivables.d.ts +1474 -0
  124. package/dist/schema/receivables.d.ts.map +1 -0
  125. package/dist/schema/receivables.js +179 -0
  126. package/dist/schema/relations.d.ts +82 -0
  127. package/dist/schema/relations.d.ts.map +1 -0
  128. package/dist/schema/relations.js +144 -0
  129. package/dist/schema/supplier-invoices.d.ts +1619 -0
  130. package/dist/schema/supplier-invoices.d.ts.map +1 -0
  131. package/dist/schema/supplier-invoices.js +228 -0
  132. package/dist/schema/tax.d.ts +712 -0
  133. package/dist/schema/tax.d.ts.map +1 -0
  134. package/dist/schema/tax.js +98 -0
  135. package/dist/schema/vouchers.d.ts +444 -0
  136. package/dist/schema/vouchers.d.ts.map +1 -0
  137. package/dist/schema/vouchers.js +64 -0
  138. package/dist/schema.d.ts +12 -0
  139. package/dist/schema.d.ts.map +1 -0
  140. package/dist/schema.js +11 -0
  141. package/dist/service-accountant-shares.d.ts +106 -0
  142. package/dist/service-accountant-shares.d.ts.map +1 -0
  143. package/dist/service-accountant-shares.js +331 -0
  144. package/dist/service-action-ledger-accounting.d.ts +104 -0
  145. package/dist/service-action-ledger-accounting.d.ts.map +1 -0
  146. package/dist/service-action-ledger-accounting.js +386 -0
  147. package/dist/service-action-ledger-booking-payments.d.ts +48 -0
  148. package/dist/service-action-ledger-booking-payments.d.ts.map +1 -0
  149. package/dist/service-action-ledger-booking-payments.js +178 -0
  150. package/dist/service-action-ledger-bookings.d.ts +44 -0
  151. package/dist/service-action-ledger-bookings.d.ts.map +1 -0
  152. package/dist/service-action-ledger-bookings.js +81 -0
  153. package/dist/service-action-ledger-payment-authorizations.d.ts +48 -0
  154. package/dist/service-action-ledger-payment-authorizations.d.ts.map +1 -0
  155. package/dist/service-action-ledger-payment-authorizations.js +209 -0
  156. package/dist/service-action-ledger-payment-sessions.d.ts +83 -0
  157. package/dist/service-action-ledger-payment-sessions.d.ts.map +1 -0
  158. package/dist/service-action-ledger-payment-sessions.js +294 -0
  159. package/dist/service-action-ledger-supplier-invoices.d.ts +27 -0
  160. package/dist/service-action-ledger-supplier-invoices.d.ts.map +1 -0
  161. package/dist/service-action-ledger-supplier-invoices.js +111 -0
  162. package/dist/service-action-ledger-supplier-payments.d.ts +21 -0
  163. package/dist/service-action-ledger-supplier-payments.d.ts.map +1 -0
  164. package/dist/service-action-ledger-supplier-payments.js +97 -0
  165. package/dist/service-action-ledger.d.ts +7 -0
  166. package/dist/service-action-ledger.d.ts.map +1 -0
  167. package/dist/service-action-ledger.js +6 -0
  168. package/dist/service-aggregates.d.ts +96 -0
  169. package/dist/service-aggregates.d.ts.map +1 -0
  170. package/dist/service-aggregates.js +294 -0
  171. package/dist/service-booking-billing.d.ts +2322 -0
  172. package/dist/service-booking-billing.d.ts.map +1 -0
  173. package/dist/service-booking-billing.js +8 -0
  174. package/dist/service-booking-create.d.ts +410 -0
  175. package/dist/service-booking-create.d.ts.map +1 -0
  176. package/dist/service-booking-create.js +1256 -0
  177. package/dist/service-booking-guarantees.d.ts +725 -0
  178. package/dist/service-booking-guarantees.d.ts.map +1 -0
  179. package/dist/service-booking-guarantees.js +153 -0
  180. package/dist/service-booking-item-billing.d.ts +1062 -0
  181. package/dist/service-booking-item-billing.d.ts.map +1 -0
  182. package/dist/service-booking-item-billing.js +77 -0
  183. package/dist/service-booking-payment-schedules.d.ts +557 -0
  184. package/dist/service-booking-payment-schedules.d.ts.map +1 -0
  185. package/dist/service-booking-payment-schedules.js +372 -0
  186. package/dist/service-bookings-dual-create.d.ts +308 -0
  187. package/dist/service-bookings-dual-create.d.ts.map +1 -0
  188. package/dist/service-bookings-dual-create.js +131 -0
  189. package/dist/service-boundary-sql.d.ts +6 -0
  190. package/dist/service-boundary-sql.d.ts.map +1 -0
  191. package/dist/service-boundary-sql.js +15 -0
  192. package/dist/service-cost-categories.d.ts +26 -0
  193. package/dist/service-cost-categories.d.ts.map +1 -0
  194. package/dist/service-cost-categories.js +76 -0
  195. package/dist/service-documents.d.ts +80 -0
  196. package/dist/service-documents.d.ts.map +1 -0
  197. package/dist/service-documents.js +228 -0
  198. package/dist/service-invoice-artifacts.d.ts +246 -0
  199. package/dist/service-invoice-artifacts.d.ts.map +1 -0
  200. package/dist/service-invoice-artifacts.js +277 -0
  201. package/dist/service-invoice-core.d.ts +405 -0
  202. package/dist/service-invoice-core.d.ts.map +1 -0
  203. package/dist/service-invoice-core.js +290 -0
  204. package/dist/service-invoice-credit-notes.d.ts +973 -0
  205. package/dist/service-invoice-credit-notes.d.ts.map +1 -0
  206. package/dist/service-invoice-credit-notes.js +142 -0
  207. package/dist/service-invoice-from-booking.d.ts +41 -0
  208. package/dist/service-invoice-from-booking.d.ts.map +1 -0
  209. package/dist/service-invoice-from-booking.js +267 -0
  210. package/dist/service-invoice-line-items.d.ts +432 -0
  211. package/dist/service-invoice-line-items.d.ts.map +1 -0
  212. package/dist/service-invoice-line-items.js +102 -0
  213. package/dist/service-invoice-numbering.d.ts +227 -0
  214. package/dist/service-invoice-numbering.d.ts.map +1 -0
  215. package/dist/service-invoice-numbering.js +260 -0
  216. package/dist/service-invoice-payments.d.ts +673 -0
  217. package/dist/service-invoice-payments.d.ts.map +1 -0
  218. package/dist/service-invoice-payments.js +398 -0
  219. package/dist/service-invoices.d.ts +2501 -0
  220. package/dist/service-invoices.d.ts.map +1 -0
  221. package/dist/service-invoices.js +12 -0
  222. package/dist/service-issue.d.ts +207 -0
  223. package/dist/service-issue.d.ts.map +1 -0
  224. package/dist/service-issue.js +431 -0
  225. package/dist/service-payment-authorizations.d.ts +164 -0
  226. package/dist/service-payment-authorizations.d.ts.map +1 -0
  227. package/dist/service-payment-authorizations.js +227 -0
  228. package/dist/service-payment-instruments.d.ts +116 -0
  229. package/dist/service-payment-instruments.d.ts.map +1 -0
  230. package/dist/service-payment-instruments.js +99 -0
  231. package/dist/service-payment-processing.d.ts +676 -0
  232. package/dist/service-payment-processing.d.ts.map +1 -0
  233. package/dist/service-payment-processing.js +10 -0
  234. package/dist/service-payment-session-completion.d.ts +48 -0
  235. package/dist/service-payment-session-completion.d.ts.map +1 -0
  236. package/dist/service-payment-session-completion.js +238 -0
  237. package/dist/service-payment-sessions.d.ts +361 -0
  238. package/dist/service-payment-sessions.d.ts.map +1 -0
  239. package/dist/service-payment-sessions.js +280 -0
  240. package/dist/service-profitability.d.ts +114 -0
  241. package/dist/service-profitability.d.ts.map +1 -0
  242. package/dist/service-profitability.js +794 -0
  243. package/dist/service-public.d.ts +553 -0
  244. package/dist/service-public.d.ts.map +1 -0
  245. package/dist/service-public.js +583 -0
  246. package/dist/service-reference-data.d.ts +272 -0
  247. package/dist/service-reference-data.d.ts.map +1 -0
  248. package/dist/service-reference-data.js +280 -0
  249. package/dist/service-rendition-wait.d.ts +38 -0
  250. package/dist/service-rendition-wait.d.ts.map +1 -0
  251. package/dist/service-rendition-wait.js +67 -0
  252. package/dist/service-reports.d.ts +37 -0
  253. package/dist/service-reports.d.ts.map +1 -0
  254. package/dist/service-reports.js +62 -0
  255. package/dist/service-settlement.d.ts +46 -0
  256. package/dist/service-settlement.d.ts.map +1 -0
  257. package/dist/service-settlement.js +185 -0
  258. package/dist/service-shared.d.ts +541 -0
  259. package/dist/service-shared.d.ts.map +1 -0
  260. package/dist/service-shared.js +764 -0
  261. package/dist/service-supplier-invoices.d.ts +871 -0
  262. package/dist/service-supplier-invoices.d.ts.map +1 -0
  263. package/dist/service-supplier-invoices.js +744 -0
  264. package/dist/service-supplier-payments.d.ts +69 -0
  265. package/dist/service-supplier-payments.d.ts.map +1 -0
  266. package/dist/service-supplier-payments.js +136 -0
  267. package/dist/service-vouchers-migration.d.ts +44 -0
  268. package/dist/service-vouchers-migration.d.ts.map +1 -0
  269. package/dist/service-vouchers-migration.js +148 -0
  270. package/dist/service-vouchers.d.ts +157 -0
  271. package/dist/service-vouchers.d.ts.map +1 -0
  272. package/dist/service-vouchers.js +191 -0
  273. package/dist/service.d.ts +6490 -0
  274. package/dist/service.d.ts.map +1 -0
  275. package/dist/service.js +29 -0
  276. package/dist/validation-billing.d.ts +2 -0
  277. package/dist/validation-billing.d.ts.map +1 -0
  278. package/dist/validation-billing.js +1 -0
  279. package/dist/validation-payments.d.ts +2 -0
  280. package/dist/validation-payments.d.ts.map +1 -0
  281. package/dist/validation-payments.js +1 -0
  282. package/dist/validation-public.d.ts +2 -0
  283. package/dist/validation-public.d.ts.map +1 -0
  284. package/dist/validation-public.js +1 -0
  285. package/dist/validation-shared.d.ts +2 -0
  286. package/dist/validation-shared.d.ts.map +1 -0
  287. package/dist/validation-shared.js +1 -0
  288. package/dist/validation-vouchers.d.ts +2 -0
  289. package/dist/validation-vouchers.d.ts.map +1 -0
  290. package/dist/validation-vouchers.js +1 -0
  291. package/dist/validation.d.ts +2 -0
  292. package/dist/validation.d.ts.map +1 -0
  293. package/dist/validation.js +1 -0
  294. package/package.json +121 -0
@@ -0,0 +1,372 @@
1
+ import { financePaymentProcessingService } from "./service-payment-processing.js";
2
+ import { and, appendActionLedgerMutation, asc, assertBookingPaymentScheduleHasPaymentCoverage, bookingGuarantees, bookingPaymentSchedules, bookings, buildBookingGuaranteeCreateActionLedgerInput, buildBookingPaymentScheduleCreateActionLedgerInput, buildBookingPaymentScheduleDeleteActionLedgerInput, buildBookingPaymentScheduleUpdateActionLedgerInput, eq, invoices, or, PaymentValidationError, parseDateString, startOfUtcDay, toDateString, } from "./service-shared.js";
3
+ export const financeBookingPaymentScheduleService = {
4
+ listBookingPaymentSchedules(db, bookingId) {
5
+ return db
6
+ .select()
7
+ .from(bookingPaymentSchedules)
8
+ .where(eq(bookingPaymentSchedules.bookingId, bookingId))
9
+ .orderBy(asc(bookingPaymentSchedules.dueDate), asc(bookingPaymentSchedules.createdAt));
10
+ },
11
+ async createBookingPaymentSchedule(db, bookingId, data, runtime = {}) {
12
+ if (data.status === "paid") {
13
+ throw new PaymentValidationError("Create booking payment schedules as pending or due, then settle them through a payment session", { bookingId });
14
+ }
15
+ const createSchedule = async (writer) => {
16
+ const [booking] = await writer
17
+ .select({ id: bookings.id })
18
+ .from(bookings)
19
+ .where(eq(bookings.id, bookingId))
20
+ .limit(1);
21
+ if (!booking) {
22
+ return null;
23
+ }
24
+ const [row] = await writer
25
+ .insert(bookingPaymentSchedules)
26
+ .values({ ...data, bookingId })
27
+ .returning();
28
+ return row ?? null;
29
+ };
30
+ const actionLedgerContext = runtime.actionLedgerContext;
31
+ if (actionLedgerContext) {
32
+ return db.transaction(async (tx) => {
33
+ const row = await createSchedule(tx);
34
+ if (row) {
35
+ await appendActionLedgerMutation(tx, buildBookingPaymentScheduleCreateActionLedgerInput(actionLedgerContext, { schedule: row }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
36
+ }
37
+ return row;
38
+ });
39
+ }
40
+ return createSchedule(db);
41
+ },
42
+ /**
43
+ * Persist a payment schedule that was already computed elsewhere
44
+ * (typically by `computePaymentSchedule()` from the policy primitive).
45
+ *
46
+ * Idempotency: when `replace: true` (the default), any existing
47
+ * pending/due schedule rows on the booking are cleared first so a
48
+ * re-fire of the same hook doesn't pile up duplicate rows. Set
49
+ * `replace: false` to insert alongside existing rows (e.g. when
50
+ * inserting a manually-added one-off installment).
51
+ *
52
+ * Skips silently when the booking row doesn't exist (returns
53
+ * `null`) or when there are no entries to persist.
54
+ */
55
+ async applyComputedPaymentSchedule(db, bookingId, entries, options = {}) {
56
+ if (entries.length === 0)
57
+ return [];
58
+ const [booking] = await db
59
+ .select({ id: bookings.id })
60
+ .from(bookings)
61
+ .where(eq(bookings.id, bookingId))
62
+ .limit(1);
63
+ if (!booking)
64
+ return null;
65
+ const replace = options.replace ?? true;
66
+ if (replace) {
67
+ await db
68
+ .delete(bookingPaymentSchedules)
69
+ .where(and(eq(bookingPaymentSchedules.bookingId, bookingId), or(eq(bookingPaymentSchedules.status, "pending"), eq(bookingPaymentSchedules.status, "due"))));
70
+ }
71
+ const today = startOfUtcDay(new Date());
72
+ const rows = entries.map((entry) => {
73
+ const due = parseDateString(entry.dueDate) ?? today;
74
+ // The `full` schedule kind from the policy primitive collapses
75
+ // to a `balance` row in the DB (the table only has
76
+ // deposit/installment/balance/hold/other) — semantically the
77
+ // single full-payment row IS the balance to settle.
78
+ const persistedType = entry.scheduleType === "full" ? "balance" : entry.scheduleType;
79
+ return {
80
+ bookingId,
81
+ bookingItemId: null,
82
+ scheduleType: persistedType,
83
+ status: (due <= today ? "due" : "pending"),
84
+ dueDate: entry.dueDate,
85
+ currency: entry.currency,
86
+ amountCents: Math.max(0, Math.round(entry.amountCents)),
87
+ notes: entry.notes ?? null,
88
+ };
89
+ });
90
+ return db.insert(bookingPaymentSchedules).values(rows).returning();
91
+ },
92
+ async applyDefaultBookingPaymentPlan(db, bookingId, data, runtime = {}) {
93
+ const applyPlan = async (writer) => {
94
+ const [booking] = await writer
95
+ .select()
96
+ .from(bookings)
97
+ .where(eq(bookings.id, bookingId))
98
+ .limit(1);
99
+ if (!booking) {
100
+ return null;
101
+ }
102
+ const totalAmountCents = booking.sellAmountCents ?? 0;
103
+ if (totalAmountCents <= 0) {
104
+ return {
105
+ createdSchedules: [],
106
+ deletedSchedules: [],
107
+ createdGuarantee: null,
108
+ };
109
+ }
110
+ const today = startOfUtcDay(new Date());
111
+ const depositDueDate = data.depositDueDate ? parseDateString(data.depositDueDate) : today;
112
+ const startDate = booking.startDate ? parseDateString(booking.startDate) : null;
113
+ const rawBalanceDueDate = startDate
114
+ ? new Date(startDate.getTime() - data.balanceDueDaysBeforeStart * 24 * 60 * 60 * 1000)
115
+ : today;
116
+ const balanceDueDate = rawBalanceDueDate < today ? today : rawBalanceDueDate;
117
+ let depositAmountCents = 0;
118
+ if (data.depositMode === "fixed_amount") {
119
+ depositAmountCents = Math.min(totalAmountCents, data.depositValue);
120
+ }
121
+ else if (data.depositMode === "percentage") {
122
+ depositAmountCents = Math.min(totalAmountCents, Math.round((totalAmountCents * data.depositValue) / 100));
123
+ }
124
+ const clearableScheduleWhere = and(eq(bookingPaymentSchedules.bookingId, bookingId), or(eq(bookingPaymentSchedules.status, "pending"), eq(bookingPaymentSchedules.status, "due")));
125
+ const deletedSchedules = data.clearExistingPending
126
+ ? await writer.select().from(bookingPaymentSchedules).where(clearableScheduleWhere)
127
+ : [];
128
+ if (data.clearExistingPending) {
129
+ await writer.delete(bookingPaymentSchedules).where(clearableScheduleWhere);
130
+ }
131
+ const scheduleRows = [];
132
+ if (depositAmountCents > 0 && depositAmountCents < totalAmountCents) {
133
+ scheduleRows.push({
134
+ bookingItemId: null,
135
+ scheduleType: "deposit",
136
+ status: depositDueDate <= today ? "due" : "pending",
137
+ dueDate: toDateString(depositDueDate),
138
+ currency: booking.sellCurrency,
139
+ amountCents: depositAmountCents,
140
+ notes: data.notes ?? null,
141
+ });
142
+ scheduleRows.push({
143
+ bookingItemId: null,
144
+ scheduleType: "balance",
145
+ status: balanceDueDate <= today ? "due" : "pending",
146
+ dueDate: toDateString(balanceDueDate),
147
+ currency: booking.sellCurrency,
148
+ amountCents: Math.max(0, totalAmountCents - depositAmountCents),
149
+ notes: data.notes ?? null,
150
+ });
151
+ }
152
+ else {
153
+ const singleDueDate = balanceDueDate <= today ? today : balanceDueDate;
154
+ scheduleRows.push({
155
+ bookingItemId: null,
156
+ scheduleType: "balance",
157
+ status: singleDueDate <= today ? "due" : "pending",
158
+ dueDate: toDateString(singleDueDate),
159
+ currency: booking.sellCurrency,
160
+ amountCents: totalAmountCents,
161
+ notes: data.notes ?? null,
162
+ });
163
+ }
164
+ const createdSchedules = await writer
165
+ .insert(bookingPaymentSchedules)
166
+ .values(scheduleRows.map((row) => ({
167
+ ...row,
168
+ bookingId,
169
+ bookingItemId: row.bookingItemId ?? null,
170
+ notes: row.notes ?? null,
171
+ })))
172
+ .returning();
173
+ let createdGuarantee = null;
174
+ if (data.createGuarantee) {
175
+ const depositSchedule = createdSchedules.find((schedule) => schedule.scheduleType === "deposit");
176
+ if (depositSchedule) {
177
+ const [guarantee] = await writer
178
+ .insert(bookingGuarantees)
179
+ .values({
180
+ bookingId,
181
+ bookingPaymentScheduleId: depositSchedule.id,
182
+ bookingItemId: null,
183
+ guaranteeType: data.guaranteeType,
184
+ status: "pending",
185
+ paymentInstrumentId: null,
186
+ paymentAuthorizationId: null,
187
+ currency: depositSchedule.currency,
188
+ amountCents: depositSchedule.amountCents,
189
+ provider: null,
190
+ referenceNumber: null,
191
+ guaranteedAt: null,
192
+ expiresAt: null,
193
+ releasedAt: null,
194
+ notes: data.notes ?? null,
195
+ })
196
+ .returning();
197
+ createdGuarantee = guarantee ?? null;
198
+ }
199
+ }
200
+ return { createdSchedules, deletedSchedules, createdGuarantee };
201
+ };
202
+ const actionLedgerContext = runtime.actionLedgerContext;
203
+ if (actionLedgerContext) {
204
+ const result = await db.transaction(async (tx) => {
205
+ const applied = await applyPlan(tx);
206
+ if (!applied) {
207
+ return null;
208
+ }
209
+ for (const schedule of applied.deletedSchedules) {
210
+ await appendActionLedgerMutation(tx, buildBookingPaymentScheduleDeleteActionLedgerInput(actionLedgerContext, { schedule }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
211
+ }
212
+ for (const schedule of applied.createdSchedules) {
213
+ await appendActionLedgerMutation(tx, buildBookingPaymentScheduleCreateActionLedgerInput(actionLedgerContext, { schedule }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
214
+ }
215
+ if (applied.createdGuarantee) {
216
+ await appendActionLedgerMutation(tx, await buildBookingGuaranteeCreateActionLedgerInput(actionLedgerContext, { guarantee: applied.createdGuarantee }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
217
+ }
218
+ return applied.createdSchedules;
219
+ });
220
+ return result;
221
+ }
222
+ const result = await applyPlan(db);
223
+ return result?.createdSchedules ?? null;
224
+ },
225
+ async updateBookingPaymentSchedule(db, scheduleId, data, runtime = {}) {
226
+ const updateSchedule = async (writer) => {
227
+ const [existing] = await writer
228
+ .select()
229
+ .from(bookingPaymentSchedules)
230
+ .where(eq(bookingPaymentSchedules.id, scheduleId))
231
+ .limit(1);
232
+ if (!existing) {
233
+ return [];
234
+ }
235
+ const nextSchedule = {
236
+ id: existing.id,
237
+ bookingId: existing.bookingId,
238
+ amountCents: data.amountCents ?? existing.amountCents,
239
+ currency: data.currency ?? existing.currency,
240
+ };
241
+ const nextStatus = data.status ?? existing.status;
242
+ if (nextStatus === "paid") {
243
+ await assertBookingPaymentScheduleHasPaymentCoverage(writer, nextSchedule);
244
+ }
245
+ return writer
246
+ .update(bookingPaymentSchedules)
247
+ .set({ ...data, updatedAt: new Date() })
248
+ .where(eq(bookingPaymentSchedules.id, scheduleId))
249
+ .returning();
250
+ };
251
+ const actionLedgerContext = runtime.actionLedgerContext;
252
+ if (actionLedgerContext) {
253
+ const [row] = await db.transaction(async (tx) => {
254
+ const updated = await updateSchedule(tx);
255
+ if (updated[0]) {
256
+ await appendActionLedgerMutation(tx, buildBookingPaymentScheduleUpdateActionLedgerInput(actionLedgerContext, { schedule: updated[0], changes: data }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
257
+ }
258
+ return updated;
259
+ });
260
+ return row ?? null;
261
+ }
262
+ const [row] = await updateSchedule(db);
263
+ return row ?? null;
264
+ },
265
+ async deleteBookingPaymentSchedule(db, scheduleId, runtime = {}) {
266
+ const actionLedgerContext = runtime.actionLedgerContext;
267
+ if (actionLedgerContext) {
268
+ return db.transaction(async (tx) => {
269
+ const [existing] = await tx
270
+ .select()
271
+ .from(bookingPaymentSchedules)
272
+ .where(eq(bookingPaymentSchedules.id, scheduleId))
273
+ .limit(1);
274
+ if (!existing) {
275
+ return null;
276
+ }
277
+ await tx.delete(bookingPaymentSchedules).where(eq(bookingPaymentSchedules.id, scheduleId));
278
+ await appendActionLedgerMutation(tx, buildBookingPaymentScheduleDeleteActionLedgerInput(actionLedgerContext, { schedule: existing }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
279
+ return { id: existing.id };
280
+ });
281
+ }
282
+ const [row] = await db
283
+ .delete(bookingPaymentSchedules)
284
+ .where(eq(bookingPaymentSchedules.id, scheduleId))
285
+ .returning({ id: bookingPaymentSchedules.id });
286
+ return row ?? null;
287
+ },
288
+ async createPaymentSessionFromBookingSchedule(db, scheduleId, data, runtime = {}) {
289
+ const [schedule] = await db
290
+ .select()
291
+ .from(bookingPaymentSchedules)
292
+ .where(eq(bookingPaymentSchedules.id, scheduleId))
293
+ .limit(1);
294
+ if (!schedule) {
295
+ return null;
296
+ }
297
+ if (schedule.status === "paid" ||
298
+ schedule.status === "waived" ||
299
+ schedule.status === "cancelled") {
300
+ throw new Error(`Cannot create payment session for schedule in status "${schedule.status}"`);
301
+ }
302
+ return financePaymentProcessingService.createPaymentSession(db, {
303
+ targetType: "booking_payment_schedule",
304
+ targetId: schedule.id,
305
+ bookingId: schedule.bookingId,
306
+ bookingPaymentScheduleId: schedule.id,
307
+ status: "pending",
308
+ provider: data.provider ?? null,
309
+ externalReference: data.externalReference ?? null,
310
+ idempotencyKey: data.idempotencyKey ?? null,
311
+ clientReference: data.clientReference ?? schedule.id,
312
+ currency: schedule.currency,
313
+ amountCents: schedule.amountCents,
314
+ paymentMethod: data.paymentMethod ?? null,
315
+ payerPersonId: data.payerPersonId ?? null,
316
+ payerOrganizationId: data.payerOrganizationId ?? null,
317
+ payerEmail: data.payerEmail ?? null,
318
+ payerName: data.payerName ?? null,
319
+ returnUrl: data.returnUrl ?? null,
320
+ cancelUrl: data.cancelUrl ?? null,
321
+ callbackUrl: data.callbackUrl ?? null,
322
+ expiresAt: data.expiresAt ?? null,
323
+ notes: data.notes ?? schedule.notes ?? null,
324
+ providerPayload: data.providerPayload ?? null,
325
+ metadata: data.metadata ?? {
326
+ scheduleType: schedule.scheduleType,
327
+ dueDate: schedule.dueDate,
328
+ },
329
+ }, runtime);
330
+ },
331
+ async createPaymentSessionFromInvoice(db, invoiceId, data, runtime = {}) {
332
+ const [invoice] = await db.select().from(invoices).where(eq(invoices.id, invoiceId)).limit(1);
333
+ if (!invoice) {
334
+ return null;
335
+ }
336
+ if (invoice.status === "paid" || invoice.status === "void") {
337
+ throw new Error(`Cannot create payment session for invoice in status "${invoice.status}"`);
338
+ }
339
+ if (invoice.balanceDueCents <= 0) {
340
+ throw new Error("Invoice must have an outstanding balance before creating a payment session");
341
+ }
342
+ return financePaymentProcessingService.createPaymentSession(db, {
343
+ targetType: "invoice",
344
+ targetId: invoice.id,
345
+ bookingId: invoice.bookingId,
346
+ invoiceId: invoice.id,
347
+ status: "pending",
348
+ provider: data.provider ?? null,
349
+ externalReference: data.externalReference ?? invoice.invoiceNumber,
350
+ idempotencyKey: data.idempotencyKey ?? null,
351
+ clientReference: data.clientReference ?? invoice.id,
352
+ currency: invoice.currency,
353
+ amountCents: invoice.balanceDueCents,
354
+ paymentMethod: data.paymentMethod ?? null,
355
+ payerPersonId: data.payerPersonId ?? invoice.personId ?? null,
356
+ payerOrganizationId: data.payerOrganizationId ?? invoice.organizationId ?? null,
357
+ payerEmail: data.payerEmail ?? null,
358
+ payerName: data.payerName ?? null,
359
+ returnUrl: data.returnUrl ?? null,
360
+ cancelUrl: data.cancelUrl ?? null,
361
+ callbackUrl: data.callbackUrl ?? null,
362
+ expiresAt: data.expiresAt ?? null,
363
+ notes: data.notes ?? invoice.notes ?? null,
364
+ providerPayload: data.providerPayload ?? null,
365
+ metadata: data.metadata ?? {
366
+ invoiceNumber: invoice.invoiceNumber,
367
+ invoiceType: invoice.invoiceType,
368
+ dueDate: invoice.dueDate,
369
+ },
370
+ }, runtime);
371
+ },
372
+ };
@@ -0,0 +1,308 @@
1
+ import type { BookingGroup, BookingGroupMember } from "@voyant-travel/bookings/schema";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ import { z } from "zod";
4
+ import type { FinanceServiceRuntime } from "./service.js";
5
+ import { type BookingCreateOutcome, type BookingCreateResult } from "./service-booking-create.js";
6
+ export declare const dualCreateBookingSchema: z.ZodObject<{
7
+ primary: z.ZodObject<{
8
+ productId: z.ZodString;
9
+ personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
10
+ organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
11
+ bookingNumber: z.ZodString;
12
+ contactFirstName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
13
+ contactLastName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
14
+ contactEmail: z.ZodNullable<z.ZodOptional<z.ZodString>>;
15
+ contactPhone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
16
+ contactPreferredLanguage: z.ZodNullable<z.ZodOptional<z.ZodString>>;
17
+ contactCountry: z.ZodNullable<z.ZodOptional<z.ZodString>>;
18
+ contactRegion: z.ZodNullable<z.ZodOptional<z.ZodString>>;
19
+ contactCity: z.ZodNullable<z.ZodOptional<z.ZodString>>;
20
+ contactAddressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
21
+ contactAddressLine2: z.ZodNullable<z.ZodOptional<z.ZodString>>;
22
+ contactPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
23
+ pax: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
24
+ internalNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
25
+ optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
26
+ slotId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
27
+ sellAmountCentsOverride: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
28
+ catalogSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
29
+ confirmedSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
30
+ priceOverrideReason: z.ZodNullable<z.ZodOptional<z.ZodString>>;
31
+ initialStatus: z.ZodOptional<z.ZodEnum<{
32
+ cancelled: "cancelled";
33
+ expired: "expired";
34
+ draft: "draft";
35
+ completed: "completed";
36
+ on_hold: "on_hold";
37
+ awaiting_payment: "awaiting_payment";
38
+ confirmed: "confirmed";
39
+ in_progress: "in_progress";
40
+ }>>;
41
+ suppressNotifications: z.ZodOptional<z.ZodBoolean>;
42
+ allowDuplicate: z.ZodOptional<z.ZodBoolean>;
43
+ travelers: z.ZodOptional<z.ZodArray<z.ZodObject<{
44
+ clientTravelerKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
45
+ firstName: z.ZodString;
46
+ lastName: z.ZodString;
47
+ email: z.ZodNullable<z.ZodOptional<z.ZodString>>;
48
+ phone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
49
+ personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
50
+ participantType: z.ZodDefault<z.ZodEnum<{
51
+ other: "other";
52
+ traveler: "traveler";
53
+ occupant: "occupant";
54
+ }>>;
55
+ travelerCategory: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
56
+ other: "other";
57
+ adult: "adult";
58
+ child: "child";
59
+ infant: "infant";
60
+ senior: "senior";
61
+ }>>>;
62
+ preferredLanguage: z.ZodNullable<z.ZodOptional<z.ZodString>>;
63
+ specialRequests: z.ZodNullable<z.ZodOptional<z.ZodString>>;
64
+ roomUnitId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
65
+ isPrimary: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
66
+ notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
67
+ }, z.core.$strip>>>;
68
+ itemLines: z.ZodOptional<z.ZodArray<z.ZodObject<{
69
+ clientLineKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
70
+ optionUnitId: z.ZodString;
71
+ quantity: z.ZodNumber;
72
+ title: z.ZodNullable<z.ZodOptional<z.ZodString>>;
73
+ description: z.ZodNullable<z.ZodOptional<z.ZodString>>;
74
+ unitSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
75
+ totalSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
76
+ travelerKeys: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodString>>>;
77
+ travelerIndexes: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodNumber>>>;
78
+ }, z.core.$strip>>>;
79
+ extraLines: z.ZodOptional<z.ZodArray<z.ZodObject<{
80
+ clientLineKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
81
+ productExtraId: z.ZodString;
82
+ optionExtraConfigId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
83
+ name: z.ZodString;
84
+ description: z.ZodNullable<z.ZodOptional<z.ZodString>>;
85
+ pricingMode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
86
+ pricedPerPerson: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
87
+ quantity: z.ZodNumber;
88
+ sellCurrency: z.ZodString;
89
+ unitSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
90
+ totalSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
91
+ travelerKeys: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodString>>>;
92
+ travelerIndexes: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodNumber>>>;
93
+ }, z.core.$strip>>>;
94
+ paymentSchedules: z.ZodOptional<z.ZodArray<z.ZodObject<{
95
+ scheduleType: z.ZodDefault<z.ZodEnum<{
96
+ other: "other";
97
+ deposit: "deposit";
98
+ balance: "balance";
99
+ installment: "installment";
100
+ hold: "hold";
101
+ }>>;
102
+ status: z.ZodDefault<z.ZodEnum<{
103
+ pending: "pending";
104
+ cancelled: "cancelled";
105
+ due: "due";
106
+ paid: "paid";
107
+ waived: "waived";
108
+ expired: "expired";
109
+ }>>;
110
+ dueDate: z.ZodString;
111
+ currency: z.ZodString;
112
+ amountCents: z.ZodNumber;
113
+ notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
114
+ }, z.core.$strip>>>;
115
+ voucherRedemption: z.ZodOptional<z.ZodObject<{
116
+ voucherId: z.ZodString;
117
+ amountCents: z.ZodNumber;
118
+ }, z.core.$strip>>;
119
+ documentGeneration: z.ZodOptional<z.ZodDefault<z.ZodObject<{
120
+ contractDocument: z.ZodDefault<z.ZodBoolean>;
121
+ invoiceDocument: z.ZodDefault<z.ZodBoolean>;
122
+ invoiceType: z.ZodDefault<z.ZodEnum<{
123
+ invoice: "invoice";
124
+ proforma: "proforma";
125
+ }>>;
126
+ }, z.core.$strip>>>;
127
+ }, z.core.$strip>;
128
+ secondary: z.ZodObject<{
129
+ productId: z.ZodString;
130
+ personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
131
+ organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
132
+ bookingNumber: z.ZodString;
133
+ contactFirstName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
134
+ contactLastName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
135
+ contactEmail: z.ZodNullable<z.ZodOptional<z.ZodString>>;
136
+ contactPhone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
137
+ contactPreferredLanguage: z.ZodNullable<z.ZodOptional<z.ZodString>>;
138
+ contactCountry: z.ZodNullable<z.ZodOptional<z.ZodString>>;
139
+ contactRegion: z.ZodNullable<z.ZodOptional<z.ZodString>>;
140
+ contactCity: z.ZodNullable<z.ZodOptional<z.ZodString>>;
141
+ contactAddressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
142
+ contactAddressLine2: z.ZodNullable<z.ZodOptional<z.ZodString>>;
143
+ contactPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
144
+ pax: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
145
+ internalNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
146
+ optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
147
+ slotId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
148
+ sellAmountCentsOverride: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
149
+ catalogSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
150
+ confirmedSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
151
+ priceOverrideReason: z.ZodNullable<z.ZodOptional<z.ZodString>>;
152
+ initialStatus: z.ZodOptional<z.ZodEnum<{
153
+ cancelled: "cancelled";
154
+ expired: "expired";
155
+ draft: "draft";
156
+ completed: "completed";
157
+ on_hold: "on_hold";
158
+ awaiting_payment: "awaiting_payment";
159
+ confirmed: "confirmed";
160
+ in_progress: "in_progress";
161
+ }>>;
162
+ suppressNotifications: z.ZodOptional<z.ZodBoolean>;
163
+ allowDuplicate: z.ZodOptional<z.ZodBoolean>;
164
+ travelers: z.ZodOptional<z.ZodArray<z.ZodObject<{
165
+ clientTravelerKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
166
+ firstName: z.ZodString;
167
+ lastName: z.ZodString;
168
+ email: z.ZodNullable<z.ZodOptional<z.ZodString>>;
169
+ phone: z.ZodNullable<z.ZodOptional<z.ZodString>>;
170
+ personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
171
+ participantType: z.ZodDefault<z.ZodEnum<{
172
+ other: "other";
173
+ traveler: "traveler";
174
+ occupant: "occupant";
175
+ }>>;
176
+ travelerCategory: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
177
+ other: "other";
178
+ adult: "adult";
179
+ child: "child";
180
+ infant: "infant";
181
+ senior: "senior";
182
+ }>>>;
183
+ preferredLanguage: z.ZodNullable<z.ZodOptional<z.ZodString>>;
184
+ specialRequests: z.ZodNullable<z.ZodOptional<z.ZodString>>;
185
+ roomUnitId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
186
+ isPrimary: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
187
+ notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
188
+ }, z.core.$strip>>>;
189
+ itemLines: z.ZodOptional<z.ZodArray<z.ZodObject<{
190
+ clientLineKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
191
+ optionUnitId: z.ZodString;
192
+ quantity: z.ZodNumber;
193
+ title: z.ZodNullable<z.ZodOptional<z.ZodString>>;
194
+ description: z.ZodNullable<z.ZodOptional<z.ZodString>>;
195
+ unitSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
196
+ totalSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
197
+ travelerKeys: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodString>>>;
198
+ travelerIndexes: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodNumber>>>;
199
+ }, z.core.$strip>>>;
200
+ extraLines: z.ZodOptional<z.ZodArray<z.ZodObject<{
201
+ clientLineKey: z.ZodNullable<z.ZodOptional<z.ZodString>>;
202
+ productExtraId: z.ZodString;
203
+ optionExtraConfigId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
204
+ name: z.ZodString;
205
+ description: z.ZodNullable<z.ZodOptional<z.ZodString>>;
206
+ pricingMode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
207
+ pricedPerPerson: z.ZodNullable<z.ZodOptional<z.ZodBoolean>>;
208
+ quantity: z.ZodNumber;
209
+ sellCurrency: z.ZodString;
210
+ unitSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
211
+ totalSellAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
212
+ travelerKeys: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodString>>>;
213
+ travelerIndexes: z.ZodNullable<z.ZodOptional<z.ZodArray<z.ZodNumber>>>;
214
+ }, z.core.$strip>>>;
215
+ paymentSchedules: z.ZodOptional<z.ZodArray<z.ZodObject<{
216
+ scheduleType: z.ZodDefault<z.ZodEnum<{
217
+ other: "other";
218
+ deposit: "deposit";
219
+ balance: "balance";
220
+ installment: "installment";
221
+ hold: "hold";
222
+ }>>;
223
+ status: z.ZodDefault<z.ZodEnum<{
224
+ pending: "pending";
225
+ cancelled: "cancelled";
226
+ due: "due";
227
+ paid: "paid";
228
+ waived: "waived";
229
+ expired: "expired";
230
+ }>>;
231
+ dueDate: z.ZodString;
232
+ currency: z.ZodString;
233
+ amountCents: z.ZodNumber;
234
+ notes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
235
+ }, z.core.$strip>>>;
236
+ voucherRedemption: z.ZodOptional<z.ZodObject<{
237
+ voucherId: z.ZodString;
238
+ amountCents: z.ZodNumber;
239
+ }, z.core.$strip>>;
240
+ documentGeneration: z.ZodOptional<z.ZodDefault<z.ZodObject<{
241
+ contractDocument: z.ZodDefault<z.ZodBoolean>;
242
+ invoiceDocument: z.ZodDefault<z.ZodBoolean>;
243
+ invoiceType: z.ZodDefault<z.ZodEnum<{
244
+ invoice: "invoice";
245
+ proforma: "proforma";
246
+ }>>;
247
+ }, z.core.$strip>>>;
248
+ }, z.core.$strip>;
249
+ group: z.ZodDefault<z.ZodObject<{
250
+ kind: z.ZodDefault<z.ZodEnum<{
251
+ other: "other";
252
+ shared_room: "shared_room";
253
+ }>>;
254
+ label: z.ZodNullable<z.ZodOptional<z.ZodString>>;
255
+ optionUnitId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
256
+ }, z.core.$strip>>;
257
+ }, z.core.$strip>;
258
+ export type DualCreateBookingInput = z.infer<typeof dualCreateBookingSchema>;
259
+ export interface DualCreateBookingRuntime extends FinanceServiceRuntime {
260
+ }
261
+ export interface BookingDualCreatedEvent {
262
+ groupId: string;
263
+ primaryBookingId: string;
264
+ secondaryBookingId: string;
265
+ productId: string;
266
+ createdByUserId: string | null;
267
+ occurredAt: Date;
268
+ }
269
+ export interface DualCreateBookingResult {
270
+ primary: BookingCreateResult;
271
+ secondary: BookingCreateResult;
272
+ group: BookingGroup;
273
+ primaryMember: BookingGroupMember;
274
+ secondaryMember: BookingGroupMember;
275
+ }
276
+ export type DualCreateBookingOutcome = {
277
+ status: "ok";
278
+ result: DualCreateBookingResult;
279
+ } | {
280
+ status: "primary_failed" | "secondary_failed";
281
+ reason: Exclude<BookingCreateOutcome, {
282
+ status: "ok";
283
+ }>;
284
+ };
285
+ /**
286
+ * Create two bookings linked via a new `booking_group`, atomically. The
287
+ * canonical operator flow: two travelers book a shared room ("partaj"), each
288
+ * gets their own booking, and both are attached to a new shared_room group
289
+ * so subsequent payment / cancellation decisions can fan out across the
290
+ * pair.
291
+ *
292
+ * Transaction shape:
293
+ * - Outer tx opens via `db.transaction`.
294
+ * - Inner: two savepoint-scoped `createBooking(tx, ...)` calls — the
295
+ * nested transactions drizzle opens use SAVEPOINTs, so partial failures
296
+ * surface up to this layer as non-ok outcomes.
297
+ * - If either fails, the outer tx throws `DualCreateAbort` so the whole
298
+ * thing rolls back (no orphan booking, no orphan group).
299
+ * - Group creation + both memberships run last, inside the same outer tx.
300
+ *
301
+ * Event emission (`booking.dual-created`) is post-commit — subscribers only
302
+ * hear about successful pairs.
303
+ */
304
+ export declare function dualCreateBooking(db: PostgresJsDatabase, rawInput: DualCreateBookingInput, options?: {
305
+ userId?: string;
306
+ runtime?: DualCreateBookingRuntime;
307
+ }): Promise<DualCreateBookingOutcome>;
308
+ //# sourceMappingURL=service-bookings-dual-create.d.ts.map