@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,69 @@
1
+ import type { CreateSupplierPaymentInput, FinanceServiceRuntime, PostgresJsDatabase, SupplierPaymentListQuery, UpdateSupplierPaymentInput } from "./service-shared.js";
2
+ export declare const financeSupplierPaymentService: {
3
+ listSupplierPayments(db: PostgresJsDatabase, query: SupplierPaymentListQuery): Promise<{
4
+ data: {
5
+ id: string;
6
+ bookingId: string | null;
7
+ supplierId: string | null;
8
+ bookingSupplierStatusId: string | null;
9
+ supplierInvoiceId: string | null;
10
+ amountCents: number;
11
+ currency: string;
12
+ baseCurrency: string | null;
13
+ baseAmountCents: number | null;
14
+ fxRateSetId: string | null;
15
+ paymentMethod: "other" | "bank_transfer" | "credit_card" | "voucher" | "debit_card" | "cash" | "cheque" | "wallet" | "direct_bill";
16
+ paymentInstrumentId: string | null;
17
+ status: "failed" | "pending" | "completed" | "refunded";
18
+ referenceNumber: string | null;
19
+ paymentDate: string;
20
+ notes: string | null;
21
+ createdAt: Date;
22
+ updatedAt: Date;
23
+ }[];
24
+ total: number;
25
+ limit: number;
26
+ offset: number;
27
+ }>;
28
+ createSupplierPayment(db: PostgresJsDatabase, data: CreateSupplierPaymentInput, runtime?: FinanceServiceRuntime): Promise<{
29
+ currency: string;
30
+ id: string;
31
+ createdAt: Date;
32
+ updatedAt: Date;
33
+ status: "failed" | "pending" | "completed" | "refunded";
34
+ bookingId: string | null;
35
+ amountCents: number;
36
+ notes: string | null;
37
+ paymentMethod: "other" | "bank_transfer" | "credit_card" | "voucher" | "debit_card" | "cash" | "cheque" | "wallet" | "direct_bill";
38
+ baseCurrency: string | null;
39
+ fxRateSetId: string | null;
40
+ supplierId: string | null;
41
+ paymentInstrumentId: string | null;
42
+ referenceNumber: string | null;
43
+ baseAmountCents: number | null;
44
+ paymentDate: string;
45
+ supplierInvoiceId: string | null;
46
+ bookingSupplierStatusId: string | null;
47
+ } | null>;
48
+ updateSupplierPayment(db: PostgresJsDatabase, id: string, data: UpdateSupplierPaymentInput, runtime?: FinanceServiceRuntime): Promise<{
49
+ id: string;
50
+ bookingId: string | null;
51
+ supplierId: string | null;
52
+ bookingSupplierStatusId: string | null;
53
+ supplierInvoiceId: string | null;
54
+ amountCents: number;
55
+ currency: string;
56
+ baseCurrency: string | null;
57
+ baseAmountCents: number | null;
58
+ fxRateSetId: string | null;
59
+ paymentMethod: "other" | "bank_transfer" | "credit_card" | "voucher" | "debit_card" | "cash" | "cheque" | "wallet" | "direct_bill";
60
+ paymentInstrumentId: string | null;
61
+ status: "failed" | "pending" | "completed" | "refunded";
62
+ referenceNumber: string | null;
63
+ paymentDate: string;
64
+ notes: string | null;
65
+ createdAt: Date;
66
+ updatedAt: Date;
67
+ } | null>;
68
+ };
69
+ //# sourceMappingURL=service-supplier-payments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-supplier-payments.d.ts","sourceRoot":"","sources":["../src/service-supplier-payments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACxB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAA;AAoB5B,eAAO,MAAM,6BAA6B;6BACT,kBAAkB,SAAS,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;8BAuE5E,kBAAkB,QAChB,0BAA0B,YACvB,qBAAqB;;;;;;;;;;;;;;;;;;;;8BA2D1B,kBAAkB,MAClB,MAAM,QACJ,0BAA0B,YACvB,qBAAqB;;;;;;;;;;;;;;;;;;;;CA6CjC,CAAA"}
@@ -0,0 +1,136 @@
1
+ import { and, appendActionLedgerMutation, asc, bookings, buildSupplierPaymentCreateActionLedgerInput, buildSupplierPaymentUpdateActionLedgerInput, desc, eq, gte, lte, recomputeSupplierInvoiceBalance, resolveFxMoneyBaseAmount, resolveSupplierPaymentUpdateData, sql, supplierInvoices, supplierPayments, } from "./service-shared.js";
2
+ export const financeSupplierPaymentService = {
3
+ async listSupplierPayments(db, query) {
4
+ const conditions = [];
5
+ if (query.bookingId) {
6
+ conditions.push(eq(supplierPayments.bookingId, query.bookingId));
7
+ }
8
+ if (query.supplierInvoiceId) {
9
+ conditions.push(eq(supplierPayments.supplierInvoiceId, query.supplierInvoiceId));
10
+ }
11
+ if (query.supplierId) {
12
+ conditions.push(eq(supplierPayments.supplierId, query.supplierId));
13
+ }
14
+ if (query.status) {
15
+ conditions.push(eq(supplierPayments.status, query.status));
16
+ }
17
+ if (query.paymentMethod) {
18
+ conditions.push(eq(supplierPayments.paymentMethod, query.paymentMethod));
19
+ }
20
+ if (query.currency) {
21
+ conditions.push(eq(supplierPayments.currency, query.currency));
22
+ }
23
+ if (query.paymentDateFrom) {
24
+ conditions.push(gte(supplierPayments.paymentDate, query.paymentDateFrom));
25
+ }
26
+ if (query.paymentDateTo) {
27
+ conditions.push(lte(supplierPayments.paymentDate, query.paymentDateTo));
28
+ }
29
+ const where = conditions.length > 0 ? and(...conditions) : undefined;
30
+ const sortColumn = (() => {
31
+ switch (query.sortBy) {
32
+ case "amountCents":
33
+ return supplierPayments.amountCents;
34
+ case "status":
35
+ return supplierPayments.status;
36
+ case "paymentDate":
37
+ return supplierPayments.paymentDate;
38
+ default:
39
+ return supplierPayments.createdAt;
40
+ }
41
+ })();
42
+ const sortFn = query.sortDir === "asc" ? asc : desc;
43
+ const [rows, countResult] = await Promise.all([
44
+ db
45
+ .select()
46
+ .from(supplierPayments)
47
+ .where(where)
48
+ .limit(query.limit)
49
+ .offset(query.offset)
50
+ .orderBy(sortFn(sortColumn), desc(supplierPayments.createdAt)),
51
+ db.select({ count: sql `count(*)::int` }).from(supplierPayments).where(where),
52
+ ]);
53
+ return {
54
+ data: rows,
55
+ total: countResult[0]?.count ?? 0,
56
+ limit: query.limit,
57
+ offset: query.offset,
58
+ };
59
+ },
60
+ async createSupplierPayment(db, data, runtime = {}) {
61
+ // Derive the reporting base currency from the booking when present, else
62
+ // from the supplier invoice the payment settles (AP payments may have no
63
+ // booking). See §5.4.
64
+ let targetBaseCurrency = null;
65
+ let fallbackFxRateSetId = null;
66
+ if (data.bookingId) {
67
+ const [booking] = await db
68
+ .select()
69
+ .from(bookings)
70
+ .where(eq(bookings.id, data.bookingId))
71
+ .limit(1);
72
+ targetBaseCurrency = booking?.baseCurrency ?? null;
73
+ fallbackFxRateSetId = booking?.fxRateSetId ?? null;
74
+ }
75
+ else if (data.supplierInvoiceId) {
76
+ const [invoice] = await db
77
+ .select()
78
+ .from(supplierInvoices)
79
+ .where(eq(supplierInvoices.id, data.supplierInvoiceId))
80
+ .limit(1);
81
+ targetBaseCurrency = invoice?.baseCurrency ?? null;
82
+ fallbackFxRateSetId = invoice?.fxRateSetId ?? null;
83
+ }
84
+ const paymentData = await resolveFxMoneyBaseAmount(db, data, {
85
+ ...runtime,
86
+ targetBaseCurrency,
87
+ fallbackFxRateSetId,
88
+ date: data.paymentDate,
89
+ });
90
+ const row = await db.transaction(async (tx) => {
91
+ const [created] = await tx
92
+ .insert(supplierPayments)
93
+ .values({ ...paymentData, paymentInstrumentId: paymentData.paymentInstrumentId ?? null })
94
+ .returning();
95
+ if (created && runtime.actionLedgerContext) {
96
+ await appendActionLedgerMutation(tx, await buildSupplierPaymentCreateActionLedgerInput(runtime.actionLedgerContext, { payment: created }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
97
+ }
98
+ // Keep the settled invoice's paid/balance/status in sync (§10).
99
+ if (created?.supplierInvoiceId) {
100
+ await recomputeSupplierInvoiceBalance(tx, created.supplierInvoiceId);
101
+ }
102
+ return created ?? null;
103
+ });
104
+ return row;
105
+ },
106
+ async updateSupplierPayment(db, id, data, runtime = {}) {
107
+ const [existing] = await db
108
+ .select()
109
+ .from(supplierPayments)
110
+ .where(eq(supplierPayments.id, id))
111
+ .limit(1);
112
+ if (!existing)
113
+ return null;
114
+ const updateData = await resolveSupplierPaymentUpdateData(db, id, data, runtime);
115
+ if (!updateData)
116
+ return null;
117
+ const row = await db.transaction(async (tx) => {
118
+ const [updated] = await tx
119
+ .update(supplierPayments)
120
+ .set({ ...updateData, updatedAt: new Date() })
121
+ .where(eq(supplierPayments.id, id))
122
+ .returning();
123
+ if (updated && runtime.actionLedgerContext) {
124
+ await appendActionLedgerMutation(tx, buildSupplierPaymentUpdateActionLedgerInput(runtime.actionLedgerContext, { payment: updated, changes: updateData }, { authorizationSource: runtime.actionLedgerAuthorizationSource }));
125
+ }
126
+ // Recompute both the previously-linked and newly-linked invoices so a
127
+ // re-pointed or status-changed payment leaves balances consistent (§10).
128
+ const affected = new Set([existing.supplierInvoiceId, updated?.supplierInvoiceId].filter((value) => Boolean(value)));
129
+ for (const invoiceId of affected) {
130
+ await recomputeSupplierInvoiceBalance(tx, invoiceId);
131
+ }
132
+ return updated ?? null;
133
+ });
134
+ return row ?? null;
135
+ },
136
+ };
@@ -0,0 +1,44 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ export interface VoucherMigrationOptions {
3
+ /**
4
+ * When true, report what would happen without writing. Defaults to false.
5
+ */
6
+ dryRun?: boolean;
7
+ /**
8
+ * Per-row hook for progress reporting. Not called on skipped rows.
9
+ */
10
+ onRowMigrated?: (info: {
11
+ paymentInstrumentId: string;
12
+ voucherCode: string;
13
+ }) => void;
14
+ }
15
+ export interface VoucherMigrationSkip {
16
+ paymentInstrumentId: string;
17
+ reason: "already_migrated" | "missing_code" | "missing_currency" | "missing_amount" | "duplicate_code_collision";
18
+ }
19
+ export interface VoucherMigrationResult {
20
+ candidates: number;
21
+ migrated: number;
22
+ skipped: VoucherMigrationSkip[];
23
+ dryRun: boolean;
24
+ }
25
+ /**
26
+ * Backfill the `vouchers` table from legacy voucher rows in
27
+ * `payment_instruments`. A legacy voucher is a row with `instrumentType =
28
+ * 'voucher'` whose code lives in one of `metadata.code`, `external_token`, or
29
+ * `direct_bill_reference`, and whose balance lives in
30
+ * `metadata.remainingAmountCents` (falling back to `metadata.amountCents` when
31
+ * no redemption has touched the row).
32
+ *
33
+ * The migration is idempotent: rows whose code already exists in the new
34
+ * `vouchers` table are skipped so re-running the script after a partial run
35
+ * (or after issuing new vouchers via the first-class API) is safe.
36
+ *
37
+ * Why skip rather than update: the new table treats `code` as a primary lookup
38
+ * key and the legacy path has already been read-only-fallback since #256
39
+ * landed, so any voucher that exists in both tables is by definition already
40
+ * migrated. Picking one source of truth avoids clobbering balances the
41
+ * operator may have adjusted through the new redemption flow.
42
+ */
43
+ export declare function migrateVouchersFromPaymentInstruments(db: PostgresJsDatabase, options?: VoucherMigrationOptions): Promise<VoucherMigrationResult>;
44
+ //# sourceMappingURL=service-vouchers-migration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-vouchers-migration.d.ts","sourceRoot":"","sources":["../src/service-vouchers-migration.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAsCjE,MAAM,WAAW,uBAAuB;IACtC;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,mBAAmB,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACrF;AAED,MAAM,WAAW,oBAAoB;IACnC,mBAAmB,EAAE,MAAM,CAAA;IAC3B,MAAM,EACF,kBAAkB,GAClB,cAAc,GACd,kBAAkB,GAClB,gBAAgB,GAChB,0BAA0B,CAAA;CAC/B;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,oBAAoB,EAAE,CAAA;IAC/B,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qCAAqC,CACzD,EAAE,EAAE,kBAAkB,EACtB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CA6GjC"}
@@ -0,0 +1,148 @@
1
+ import { eq, sql } from "drizzle-orm";
2
+ import { paymentInstruments, vouchers } from "./schema.js";
3
+ /**
4
+ * Pulls a (possibly nested, array-wrapped, or null) value out of a JSONB
5
+ * metadata column. Keeps the narrow runtime checks local so callers can stay
6
+ * declarative about the shape they expect.
7
+ */
8
+ function asRecord(metadata) {
9
+ if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
10
+ return null;
11
+ }
12
+ return metadata;
13
+ }
14
+ function asString(record, key) {
15
+ const value = record?.[key];
16
+ return typeof value === "string" && value.length > 0 ? value : null;
17
+ }
18
+ function asNumber(record, key) {
19
+ const value = record?.[key];
20
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
21
+ }
22
+ function asStringArray(record, key) {
23
+ const value = record?.[key];
24
+ if (!Array.isArray(value))
25
+ return [];
26
+ return value.filter((entry) => typeof entry === "string" && entry.length > 0);
27
+ }
28
+ function asDate(value) {
29
+ if (!value)
30
+ return null;
31
+ const parsed = new Date(value);
32
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
33
+ }
34
+ /**
35
+ * Backfill the `vouchers` table from legacy voucher rows in
36
+ * `payment_instruments`. A legacy voucher is a row with `instrumentType =
37
+ * 'voucher'` whose code lives in one of `metadata.code`, `external_token`, or
38
+ * `direct_bill_reference`, and whose balance lives in
39
+ * `metadata.remainingAmountCents` (falling back to `metadata.amountCents` when
40
+ * no redemption has touched the row).
41
+ *
42
+ * The migration is idempotent: rows whose code already exists in the new
43
+ * `vouchers` table are skipped so re-running the script after a partial run
44
+ * (or after issuing new vouchers via the first-class API) is safe.
45
+ *
46
+ * Why skip rather than update: the new table treats `code` as a primary lookup
47
+ * key and the legacy path has already been read-only-fallback since #256
48
+ * landed, so any voucher that exists in both tables is by definition already
49
+ * migrated. Picking one source of truth avoids clobbering balances the
50
+ * operator may have adjusted through the new redemption flow.
51
+ */
52
+ export async function migrateVouchersFromPaymentInstruments(db, options = {}) {
53
+ const dryRun = options.dryRun ?? false;
54
+ const skipped = [];
55
+ let migrated = 0;
56
+ const candidates = await db
57
+ .select()
58
+ .from(paymentInstruments)
59
+ .where(eq(paymentInstruments.instrumentType, "voucher"));
60
+ for (const instrument of candidates) {
61
+ const metadata = asRecord(instrument.metadata);
62
+ const code = asString(metadata, "code") ?? instrument.externalToken ?? instrument.directBillReference;
63
+ if (!code) {
64
+ skipped.push({ paymentInstrumentId: instrument.id, reason: "missing_code" });
65
+ continue;
66
+ }
67
+ const currency = asString(metadata, "currency");
68
+ if (!currency || currency.length !== 3) {
69
+ skipped.push({ paymentInstrumentId: instrument.id, reason: "missing_currency" });
70
+ continue;
71
+ }
72
+ const initialAmountCents = asNumber(metadata, "amountCents");
73
+ if (initialAmountCents === null || initialAmountCents <= 0) {
74
+ skipped.push({ paymentInstrumentId: instrument.id, reason: "missing_amount" });
75
+ continue;
76
+ }
77
+ const remainingAmountCents = asNumber(metadata, "remainingAmountCents") ?? initialAmountCents;
78
+ const [existing] = await db
79
+ .select({ id: vouchers.id })
80
+ .from(vouchers)
81
+ // agent-quality: raw-sql reviewed -- owner: finance; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
82
+ .where(sql `lower(${vouchers.code}) = ${code.toLowerCase()}`)
83
+ .limit(1);
84
+ if (existing) {
85
+ skipped.push({ paymentInstrumentId: instrument.id, reason: "already_migrated" });
86
+ continue;
87
+ }
88
+ const expiresAt = asDate(asString(metadata, "expiresAt"));
89
+ // OpenTravel uses `effectiveDate`; some legacy payloads also wrote
90
+ // `validFrom` directly. Check both so existing rows aren't silently
91
+ // dropped.
92
+ const validFrom = asDate(asString(metadata, "validFrom")) ?? asDate(asString(metadata, "effectiveDate"));
93
+ const seriesCode = asString(metadata, "seriesCode");
94
+ const bookingIds = asStringArray(metadata, "bookingIds");
95
+ const sourceBookingId = asString(metadata, "bookingId") ?? bookingIds[0] ?? null;
96
+ // Collapse the legacy status/balance pair onto the new enum. If there's no
97
+ // balance left, treat as already spent; otherwise follow the instrument's
98
+ // own active/inactive flag.
99
+ const status = remainingAmountCents <= 0 ? "redeemed" : instrument.status === "active" ? "active" : "void";
100
+ if (dryRun) {
101
+ migrated++;
102
+ options.onRowMigrated?.({ paymentInstrumentId: instrument.id, voucherCode: code });
103
+ continue;
104
+ }
105
+ try {
106
+ await db.insert(vouchers).values({
107
+ code,
108
+ seriesCode,
109
+ status,
110
+ currency: currency.toUpperCase(),
111
+ initialAmountCents,
112
+ remainingAmountCents: Math.max(0, remainingAmountCents),
113
+ issuedToPersonId: instrument.personId ?? null,
114
+ issuedToOrganizationId: instrument.organizationId ?? null,
115
+ // We don't know the original source (refund vs gift vs promo) from the
116
+ // legacy shape, so mark everything as `manual` — operators can reclassify
117
+ // later via PATCH /vouchers/:id.
118
+ sourceType: "manual",
119
+ sourceBookingId,
120
+ notes: instrument.notes ?? null,
121
+ validFrom,
122
+ expiresAt,
123
+ createdAt: instrument.createdAt,
124
+ updatedAt: instrument.updatedAt,
125
+ });
126
+ migrated++;
127
+ options.onRowMigrated?.({ paymentInstrumentId: instrument.id, voucherCode: code });
128
+ }
129
+ catch (error) {
130
+ // Unique-index collision is the only realistic insert failure here
131
+ // (another concurrent migration or a race with a manual issuance). Record
132
+ // it as a skip rather than aborting the batch so a retry finishes the
133
+ // rest.
134
+ const message = error instanceof Error ? error.message : String(error);
135
+ if (message.includes("uidx_vouchers_code") || message.includes("duplicate key")) {
136
+ skipped.push({ paymentInstrumentId: instrument.id, reason: "duplicate_code_collision" });
137
+ continue;
138
+ }
139
+ throw error;
140
+ }
141
+ }
142
+ return {
143
+ candidates: candidates.length,
144
+ migrated,
145
+ skipped,
146
+ dryRun,
147
+ };
148
+ }
@@ -0,0 +1,157 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import type { z } from "zod";
3
+ import type { insertVoucherSchema, redeemVoucherSchema, updateVoucherSchema, voucherListQuerySchema } from "./validation-vouchers.js";
4
+ type CreateVoucherInput = z.infer<typeof insertVoucherSchema>;
5
+ type UpdateVoucherInput = z.infer<typeof updateVoucherSchema>;
6
+ type RedeemVoucherInput = z.infer<typeof redeemVoucherSchema>;
7
+ type VoucherListQuery = z.infer<typeof voucherListQuerySchema>;
8
+ /**
9
+ * Raised by the voucher service. Code + message; route handlers map to HTTP.
10
+ * Reasons the route layer cares about:
11
+ * - `code_in_use` — supplied code collides with an existing voucher
12
+ * - `voucher_not_found` — id-not-found / code-not-found read path
13
+ * - `voucher_inactive` — redeem attempted against non-active status
14
+ * - `voucher_not_started`— validFrom is set and hasn't happened yet
15
+ * - `voucher_expired` — expiresAt has passed
16
+ * - `insufficient_balance` — requested amount > remainingAmountCents
17
+ */
18
+ export declare class VoucherServiceError extends Error {
19
+ readonly code: "code_in_use" | "voucher_not_found" | "voucher_inactive" | "voucher_not_started" | "voucher_expired" | "insufficient_balance";
20
+ constructor(code: "code_in_use" | "voucher_not_found" | "voucher_inactive" | "voucher_not_started" | "voucher_expired" | "insufficient_balance", message?: string);
21
+ }
22
+ export declare const vouchersService: {
23
+ list(db: PostgresJsDatabase, query: VoucherListQuery): Promise<{
24
+ data: {
25
+ id: string;
26
+ code: string;
27
+ seriesCode: string | null;
28
+ status: "expired" | "active" | "void" | "redeemed";
29
+ currency: string;
30
+ initialAmountCents: number;
31
+ remainingAmountCents: number;
32
+ issuedToPersonId: string | null;
33
+ issuedToOrganizationId: string | null;
34
+ sourceType: "manual" | "refund" | "cancellation_credit" | "gift" | "promo";
35
+ sourceBookingId: string | null;
36
+ sourcePaymentId: string | null;
37
+ validFrom: Date | null;
38
+ expiresAt: Date | null;
39
+ notes: string | null;
40
+ issuedByUserId: string | null;
41
+ createdAt: Date;
42
+ updatedAt: Date;
43
+ }[];
44
+ total: number;
45
+ limit: number;
46
+ offset: number;
47
+ }>;
48
+ getById(db: PostgresJsDatabase, id: string): Promise<{
49
+ redemptions: {
50
+ id: string;
51
+ voucherId: string;
52
+ bookingId: string;
53
+ paymentId: string | null;
54
+ amountCents: number;
55
+ createdAt: Date;
56
+ createdByUserId: string | null;
57
+ }[];
58
+ id: string;
59
+ code: string;
60
+ seriesCode: string | null;
61
+ status: "expired" | "active" | "void" | "redeemed";
62
+ currency: string;
63
+ initialAmountCents: number;
64
+ remainingAmountCents: number;
65
+ issuedToPersonId: string | null;
66
+ issuedToOrganizationId: string | null;
67
+ sourceType: "manual" | "refund" | "cancellation_credit" | "gift" | "promo";
68
+ sourceBookingId: string | null;
69
+ sourcePaymentId: string | null;
70
+ validFrom: Date | null;
71
+ expiresAt: Date | null;
72
+ notes: string | null;
73
+ issuedByUserId: string | null;
74
+ createdAt: Date;
75
+ updatedAt: Date;
76
+ } | null>;
77
+ create(db: PostgresJsDatabase, input: CreateVoucherInput, issuedByUserId?: string): Promise<{
78
+ id: string;
79
+ status: "expired" | "active" | "void" | "redeemed";
80
+ createdAt: Date;
81
+ expiresAt: Date | null;
82
+ notes: string | null;
83
+ updatedAt: Date;
84
+ currency: string;
85
+ code: string;
86
+ seriesCode: string | null;
87
+ initialAmountCents: number;
88
+ remainingAmountCents: number;
89
+ issuedToPersonId: string | null;
90
+ issuedToOrganizationId: string | null;
91
+ sourceType: "manual" | "refund" | "cancellation_credit" | "gift" | "promo";
92
+ sourceBookingId: string | null;
93
+ sourcePaymentId: string | null;
94
+ validFrom: Date | null;
95
+ issuedByUserId: string | null;
96
+ } | null>;
97
+ update(db: PostgresJsDatabase, id: string, input: UpdateVoucherInput): Promise<{
98
+ id: string;
99
+ code: string;
100
+ seriesCode: string | null;
101
+ status: "expired" | "active" | "void" | "redeemed";
102
+ currency: string;
103
+ initialAmountCents: number;
104
+ remainingAmountCents: number;
105
+ issuedToPersonId: string | null;
106
+ issuedToOrganizationId: string | null;
107
+ sourceType: "manual" | "refund" | "cancellation_credit" | "gift" | "promo";
108
+ sourceBookingId: string | null;
109
+ sourcePaymentId: string | null;
110
+ validFrom: Date | null;
111
+ expiresAt: Date | null;
112
+ notes: string | null;
113
+ issuedByUserId: string | null;
114
+ createdAt: Date;
115
+ updatedAt: Date;
116
+ } | null>;
117
+ /**
118
+ * Apply a voucher against a booking. Runs in a transaction so
119
+ * `remainingAmountCents` and the redemption row either both land or neither.
120
+ * Guards: voucher must exist, be active, not expired, and have enough
121
+ * balance for the requested amount. When remaining hits zero the voucher
122
+ * flips to `status = 'redeemed'`.
123
+ */
124
+ redeem(db: PostgresJsDatabase, voucherId: string, input: RedeemVoucherInput, userId?: string): Promise<{
125
+ voucher: {
126
+ id: string;
127
+ code: string;
128
+ seriesCode: string | null;
129
+ status: "expired" | "active" | "void" | "redeemed";
130
+ currency: string;
131
+ initialAmountCents: number;
132
+ remainingAmountCents: number;
133
+ issuedToPersonId: string | null;
134
+ issuedToOrganizationId: string | null;
135
+ sourceType: "manual" | "refund" | "cancellation_credit" | "gift" | "promo";
136
+ sourceBookingId: string | null;
137
+ sourcePaymentId: string | null;
138
+ validFrom: Date | null;
139
+ expiresAt: Date | null;
140
+ notes: string | null;
141
+ issuedByUserId: string | null;
142
+ createdAt: Date;
143
+ updatedAt: Date;
144
+ };
145
+ redemption: {
146
+ id: string;
147
+ createdAt: Date;
148
+ bookingId: string;
149
+ amountCents: number;
150
+ paymentId: string | null;
151
+ voucherId: string;
152
+ createdByUserId: string | null;
153
+ } | null;
154
+ }>;
155
+ };
156
+ export {};
157
+ //# sourceMappingURL=service-vouchers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-vouchers.d.ts","sourceRoot":"","sources":["../src/service-vouchers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAG5B,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACvB,MAAM,0BAA0B,CAAA;AAEjC,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC7D,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC7D,KAAK,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC7D,KAAK,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAE9D;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,IAAI,EACT,aAAa,GACb,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,iBAAiB,GACjB,sBAAsB;gBANjB,IAAI,EACT,aAAa,GACb,mBAAmB,GACnB,kBAAkB,GAClB,qBAAqB,GACrB,iBAAiB,GACjB,sBAAsB,EAC1B,OAAO,CAAC,EAAE,MAAM;CAKnB;AAsBD,eAAO,MAAM,eAAe;aACX,kBAAkB,SAAS,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;gBAuCxC,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAW/B,kBAAkB,SAAS,kBAAkB,mBAAmB,MAAM;;;;;;;;;;;;;;;;;;;;eAiCtE,kBAAkB,MAAM,MAAM,SAAS,kBAAkB;;;;;;;;;;;;;;;;;;;;IA0B1E;;;;;;OAMG;eAEG,kBAAkB,aACX,MAAM,SACV,kBAAkB,WAChB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ClB,CAAA"}