@voyantjs/finance 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.
package/dist/schema.js ADDED
@@ -0,0 +1,816 @@
1
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
+ import { relations } from "drizzle-orm";
3
+ import { boolean, date, index, integer, jsonb, pgEnum, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
4
+ // ---------- enums ----------
5
+ export const invoiceStatusEnum = pgEnum("invoice_status", [
6
+ "draft",
7
+ "sent",
8
+ "partially_paid",
9
+ "paid",
10
+ "overdue",
11
+ "void",
12
+ ]);
13
+ export const paymentMethodEnum = pgEnum("payment_method", [
14
+ "bank_transfer",
15
+ "credit_card",
16
+ "debit_card",
17
+ "cash",
18
+ "cheque",
19
+ "wallet",
20
+ "direct_bill",
21
+ "voucher",
22
+ "other",
23
+ ]);
24
+ export const paymentStatusEnum = pgEnum("payment_status", [
25
+ "pending",
26
+ "completed",
27
+ "failed",
28
+ "refunded",
29
+ ]);
30
+ export const paymentSessionStatusEnum = pgEnum("payment_session_status", [
31
+ "pending",
32
+ "requires_redirect",
33
+ "processing",
34
+ "authorized",
35
+ "paid",
36
+ "failed",
37
+ "cancelled",
38
+ "expired",
39
+ ]);
40
+ export const paymentSessionTargetTypeEnum = pgEnum("payment_session_target_type", [
41
+ "booking",
42
+ "order",
43
+ "invoice",
44
+ "booking_payment_schedule",
45
+ "booking_guarantee",
46
+ "other",
47
+ ]);
48
+ export const paymentInstrumentTypeEnum = pgEnum("payment_instrument_type", [
49
+ "credit_card",
50
+ "debit_card",
51
+ "bank_account",
52
+ "wallet",
53
+ "voucher",
54
+ "direct_bill",
55
+ "cash",
56
+ "other",
57
+ ]);
58
+ export const paymentInstrumentOwnerTypeEnum = pgEnum("payment_instrument_owner_type", [
59
+ "client",
60
+ "supplier",
61
+ "channel",
62
+ "agency",
63
+ "internal",
64
+ "other",
65
+ ]);
66
+ export const paymentInstrumentStatusEnum = pgEnum("payment_instrument_status", [
67
+ "active",
68
+ "inactive",
69
+ "expired",
70
+ "revoked",
71
+ "failed_verification",
72
+ ]);
73
+ export const paymentAuthorizationStatusEnum = pgEnum("payment_authorization_status", [
74
+ "pending",
75
+ "authorized",
76
+ "partially_captured",
77
+ "captured",
78
+ "voided",
79
+ "failed",
80
+ "expired",
81
+ ]);
82
+ export const paymentCaptureStatusEnum = pgEnum("payment_capture_status", [
83
+ "pending",
84
+ "completed",
85
+ "failed",
86
+ "refunded",
87
+ "voided",
88
+ ]);
89
+ export const captureModeEnum = pgEnum("capture_mode", ["automatic", "manual"]);
90
+ export const creditNoteStatusEnum = pgEnum("credit_note_status", ["draft", "issued", "applied"]);
91
+ export const paymentScheduleTypeEnum = pgEnum("payment_schedule_type", [
92
+ "deposit",
93
+ "installment",
94
+ "balance",
95
+ "hold",
96
+ "other",
97
+ ]);
98
+ export const paymentScheduleStatusEnum = pgEnum("payment_schedule_status", [
99
+ "pending",
100
+ "due",
101
+ "paid",
102
+ "waived",
103
+ "cancelled",
104
+ "expired",
105
+ ]);
106
+ export const guaranteeTypeEnum = pgEnum("guarantee_type", [
107
+ "deposit",
108
+ "credit_card",
109
+ "preauth",
110
+ "card_on_file",
111
+ "bank_transfer",
112
+ "voucher",
113
+ "agency_letter",
114
+ "other",
115
+ ]);
116
+ export const guaranteeStatusEnum = pgEnum("guarantee_status", [
117
+ "pending",
118
+ "active",
119
+ "released",
120
+ "failed",
121
+ "cancelled",
122
+ "expired",
123
+ ]);
124
+ export const taxScopeEnum = pgEnum("tax_scope", ["included", "excluded", "withheld"]);
125
+ export const commissionRecipientTypeEnum = pgEnum("commission_recipient_type", [
126
+ "channel",
127
+ "affiliate",
128
+ "agency",
129
+ "agent",
130
+ "internal",
131
+ "supplier",
132
+ "other",
133
+ ]);
134
+ export const commissionModelEnum = pgEnum("commission_model", [
135
+ "percentage",
136
+ "fixed",
137
+ "markup",
138
+ "net",
139
+ ]);
140
+ export const commissionStatusEnum = pgEnum("commission_status", [
141
+ "pending",
142
+ "accrued",
143
+ "payable",
144
+ "paid",
145
+ "void",
146
+ ]);
147
+ export const invoiceTypeEnum = pgEnum("invoice_type", ["invoice", "proforma", "credit_note"]);
148
+ export const invoiceNumberResetStrategyEnum = pgEnum("invoice_number_reset_strategy", [
149
+ "never",
150
+ "annual",
151
+ "monthly",
152
+ ]);
153
+ export const invoiceNumberSeriesScopeEnum = pgEnum("invoice_number_series_scope", [
154
+ "invoice",
155
+ "proforma",
156
+ "credit_note",
157
+ ]);
158
+ export const invoiceRenditionFormatEnum = pgEnum("invoice_rendition_format", [
159
+ "html",
160
+ "pdf",
161
+ "xml",
162
+ "json",
163
+ ]);
164
+ export const invoiceRenditionStatusEnum = pgEnum("invoice_rendition_status", [
165
+ "pending",
166
+ "ready",
167
+ "failed",
168
+ "stale",
169
+ ]);
170
+ export const invoiceTemplateBodyFormatEnum = pgEnum("invoice_template_body_format", [
171
+ "html",
172
+ "markdown",
173
+ "lexical_json",
174
+ ]);
175
+ export const taxRegimeCodeEnum = pgEnum("tax_regime_code", [
176
+ "standard",
177
+ "reduced",
178
+ "exempt",
179
+ "reverse_charge",
180
+ "margin_scheme_art311",
181
+ "zero_rated",
182
+ "out_of_scope",
183
+ "other",
184
+ ]);
185
+ // ---------- payment_instruments ----------
186
+ export const paymentInstruments = pgTable("payment_instruments", {
187
+ id: typeId("payment_instruments"),
188
+ ownerType: paymentInstrumentOwnerTypeEnum("owner_type").notNull().default("client"),
189
+ personId: text("person_id"),
190
+ organizationId: text("organization_id"),
191
+ supplierId: text("supplier_id"),
192
+ channelId: text("channel_id"),
193
+ instrumentType: paymentInstrumentTypeEnum("instrument_type").notNull(),
194
+ status: paymentInstrumentStatusEnum("status").notNull().default("active"),
195
+ label: text("label").notNull(),
196
+ provider: text("provider"),
197
+ brand: text("brand"),
198
+ last4: text("last4"),
199
+ holderName: text("holder_name"),
200
+ expiryMonth: integer("expiry_month"),
201
+ expiryYear: integer("expiry_year"),
202
+ externalToken: text("external_token"),
203
+ externalCustomerId: text("external_customer_id"),
204
+ billingEmail: text("billing_email"),
205
+ billingAddress: text("billing_address"),
206
+ directBillReference: text("direct_bill_reference"),
207
+ notes: text("notes"),
208
+ metadata: jsonb("metadata"),
209
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
210
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
211
+ }, (table) => [
212
+ index("idx_payment_instruments_owner_type").on(table.ownerType),
213
+ index("idx_payment_instruments_person").on(table.personId),
214
+ index("idx_payment_instruments_organization").on(table.organizationId),
215
+ index("idx_payment_instruments_supplier").on(table.supplierId),
216
+ index("idx_payment_instruments_channel").on(table.channelId),
217
+ index("idx_payment_instruments_status").on(table.status),
218
+ index("idx_payment_instruments_type").on(table.instrumentType),
219
+ ]);
220
+ // ---------- payment_sessions ----------
221
+ export const paymentSessions = pgTable("payment_sessions", {
222
+ id: typeId("payment_sessions"),
223
+ targetType: paymentSessionTargetTypeEnum("target_type").notNull().default("other"),
224
+ targetId: text("target_id"),
225
+ bookingId: text("booking_id"),
226
+ orderId: text("order_id"),
227
+ invoiceId: typeIdRef("invoice_id").references(() => invoices.id, { onDelete: "set null" }),
228
+ bookingPaymentScheduleId: typeIdRef("booking_payment_schedule_id").references(() => bookingPaymentSchedules.id, { onDelete: "set null" }),
229
+ bookingGuaranteeId: typeIdRef("booking_guarantee_id").references(() => bookingGuarantees.id, {
230
+ onDelete: "set null",
231
+ }),
232
+ paymentInstrumentId: typeIdRef("payment_instrument_id").references(() => paymentInstruments.id, { onDelete: "set null" }),
233
+ paymentAuthorizationId: typeIdRef("payment_authorization_id").references(() => paymentAuthorizations.id, { onDelete: "set null" }),
234
+ paymentCaptureId: typeIdRef("payment_capture_id").references(() => paymentCaptures.id, {
235
+ onDelete: "set null",
236
+ }),
237
+ paymentId: typeIdRef("payment_id").references(() => payments.id, {
238
+ onDelete: "set null",
239
+ }),
240
+ status: paymentSessionStatusEnum("status").notNull().default("pending"),
241
+ provider: text("provider"),
242
+ providerSessionId: text("provider_session_id"),
243
+ providerPaymentId: text("provider_payment_id"),
244
+ externalReference: text("external_reference"),
245
+ idempotencyKey: text("idempotency_key"),
246
+ clientReference: text("client_reference"),
247
+ currency: text("currency").notNull(),
248
+ amountCents: integer("amount_cents").notNull(),
249
+ paymentMethod: paymentMethodEnum("payment_method"),
250
+ payerPersonId: text("payer_person_id"),
251
+ payerOrganizationId: text("payer_organization_id"),
252
+ payerEmail: text("payer_email"),
253
+ payerName: text("payer_name"),
254
+ redirectUrl: text("redirect_url"),
255
+ returnUrl: text("return_url"),
256
+ cancelUrl: text("cancel_url"),
257
+ callbackUrl: text("callback_url"),
258
+ expiresAt: timestamp("expires_at", { withTimezone: true }),
259
+ completedAt: timestamp("completed_at", { withTimezone: true }),
260
+ failedAt: timestamp("failed_at", { withTimezone: true }),
261
+ cancelledAt: timestamp("cancelled_at", { withTimezone: true }),
262
+ expiredAt: timestamp("expired_at", { withTimezone: true }),
263
+ failureCode: text("failure_code"),
264
+ failureMessage: text("failure_message"),
265
+ notes: text("notes"),
266
+ providerPayload: jsonb("provider_payload").$type(),
267
+ metadata: jsonb("metadata").$type(),
268
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
269
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
270
+ }, (table) => [
271
+ index("idx_payment_sessions_target").on(table.targetType, table.targetId),
272
+ index("idx_payment_sessions_booking").on(table.bookingId),
273
+ index("idx_payment_sessions_order").on(table.orderId),
274
+ index("idx_payment_sessions_invoice").on(table.invoiceId),
275
+ index("idx_payment_sessions_schedule").on(table.bookingPaymentScheduleId),
276
+ index("idx_payment_sessions_guarantee").on(table.bookingGuaranteeId),
277
+ index("idx_payment_sessions_status").on(table.status),
278
+ index("idx_payment_sessions_provider").on(table.provider),
279
+ index("idx_payment_sessions_provider_session").on(table.providerSessionId),
280
+ index("idx_payment_sessions_expires_at").on(table.expiresAt),
281
+ uniqueIndex("uidx_payment_sessions_idempotency").on(table.idempotencyKey),
282
+ uniqueIndex("uidx_payment_sessions_provider_session").on(table.provider, table.providerSessionId),
283
+ ]);
284
+ // ---------- payment_authorizations ----------
285
+ export const paymentAuthorizations = pgTable("payment_authorizations", {
286
+ id: typeId("payment_authorizations"),
287
+ bookingId: text("booking_id"),
288
+ orderId: text("order_id"),
289
+ invoiceId: typeIdRef("invoice_id").references(() => invoices.id, { onDelete: "set null" }),
290
+ bookingGuaranteeId: typeIdRef("booking_guarantee_id"),
291
+ paymentInstrumentId: typeIdRef("payment_instrument_id").references(() => paymentInstruments.id, {
292
+ onDelete: "set null",
293
+ }),
294
+ status: paymentAuthorizationStatusEnum("status").notNull().default("pending"),
295
+ captureMode: captureModeEnum("capture_mode").notNull().default("manual"),
296
+ currency: text("currency").notNull(),
297
+ amountCents: integer("amount_cents").notNull(),
298
+ provider: text("provider"),
299
+ externalAuthorizationId: text("external_authorization_id"),
300
+ approvalCode: text("approval_code"),
301
+ authorizedAt: timestamp("authorized_at", { withTimezone: true }),
302
+ expiresAt: timestamp("expires_at", { withTimezone: true }),
303
+ voidedAt: timestamp("voided_at", { withTimezone: true }),
304
+ notes: text("notes"),
305
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
306
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
307
+ }, (table) => [
308
+ index("idx_payment_authorizations_booking").on(table.bookingId),
309
+ index("idx_payment_authorizations_order").on(table.orderId),
310
+ index("idx_payment_authorizations_invoice").on(table.invoiceId),
311
+ index("idx_payment_authorizations_guarantee").on(table.bookingGuaranteeId),
312
+ index("idx_payment_authorizations_instrument").on(table.paymentInstrumentId),
313
+ index("idx_payment_authorizations_status").on(table.status),
314
+ ]);
315
+ // ---------- payment_captures ----------
316
+ export const paymentCaptures = pgTable("payment_captures", {
317
+ id: typeId("payment_captures"),
318
+ paymentAuthorizationId: typeIdRef("payment_authorization_id").references(() => paymentAuthorizations.id, { onDelete: "set null" }),
319
+ invoiceId: typeIdRef("invoice_id").references(() => invoices.id, { onDelete: "set null" }),
320
+ status: paymentCaptureStatusEnum("status").notNull().default("pending"),
321
+ currency: text("currency").notNull(),
322
+ amountCents: integer("amount_cents").notNull(),
323
+ provider: text("provider"),
324
+ externalCaptureId: text("external_capture_id"),
325
+ capturedAt: timestamp("captured_at", { withTimezone: true }),
326
+ settledAt: timestamp("settled_at", { withTimezone: true }),
327
+ notes: text("notes"),
328
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
329
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
330
+ }, (table) => [
331
+ index("idx_payment_captures_authorization").on(table.paymentAuthorizationId),
332
+ index("idx_payment_captures_invoice").on(table.invoiceId),
333
+ index("idx_payment_captures_status").on(table.status),
334
+ ]);
335
+ // ---------- booking_payment_schedules ----------
336
+ export const bookingPaymentSchedules = pgTable("booking_payment_schedules", {
337
+ id: typeId("booking_payment_schedules"),
338
+ bookingId: text("booking_id").notNull(),
339
+ bookingItemId: text("booking_item_id"),
340
+ scheduleType: paymentScheduleTypeEnum("schedule_type").notNull().default("balance"),
341
+ status: paymentScheduleStatusEnum("status").notNull().default("pending"),
342
+ dueDate: date("due_date").notNull(),
343
+ currency: text("currency").notNull(),
344
+ amountCents: integer("amount_cents").notNull(),
345
+ notes: text("notes"),
346
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
347
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
348
+ }, (table) => [
349
+ index("idx_booking_payment_schedules_booking").on(table.bookingId),
350
+ index("idx_booking_payment_schedules_item").on(table.bookingItemId),
351
+ index("idx_booking_payment_schedules_status").on(table.status),
352
+ index("idx_booking_payment_schedules_due_date").on(table.dueDate),
353
+ ]);
354
+ // ---------- booking_guarantees ----------
355
+ export const bookingGuarantees = pgTable("booking_guarantees", {
356
+ id: typeId("booking_guarantees"),
357
+ bookingId: text("booking_id").notNull(),
358
+ bookingPaymentScheduleId: typeIdRef("booking_payment_schedule_id").references(() => bookingPaymentSchedules.id, { onDelete: "set null" }),
359
+ bookingItemId: text("booking_item_id"),
360
+ guaranteeType: guaranteeTypeEnum("guarantee_type").notNull(),
361
+ status: guaranteeStatusEnum("status").notNull().default("pending"),
362
+ paymentInstrumentId: typeIdRef("payment_instrument_id").references(() => paymentInstruments.id, {
363
+ onDelete: "set null",
364
+ }),
365
+ paymentAuthorizationId: typeIdRef("payment_authorization_id").references(() => paymentAuthorizations.id, { onDelete: "set null" }),
366
+ currency: text("currency"),
367
+ amountCents: integer("amount_cents"),
368
+ provider: text("provider"),
369
+ referenceNumber: text("reference_number"),
370
+ guaranteedAt: timestamp("guaranteed_at", { withTimezone: true }),
371
+ expiresAt: timestamp("expires_at", { withTimezone: true }),
372
+ releasedAt: timestamp("released_at", { withTimezone: true }),
373
+ notes: text("notes"),
374
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
375
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
376
+ }, (table) => [
377
+ index("idx_booking_guarantees_booking").on(table.bookingId),
378
+ index("idx_booking_guarantees_schedule").on(table.bookingPaymentScheduleId),
379
+ index("idx_booking_guarantees_item").on(table.bookingItemId),
380
+ index("idx_booking_guarantees_instrument").on(table.paymentInstrumentId),
381
+ index("idx_booking_guarantees_authorization").on(table.paymentAuthorizationId),
382
+ index("idx_booking_guarantees_status").on(table.status),
383
+ ]);
384
+ // ---------- booking_item_tax_lines ----------
385
+ export const bookingItemTaxLines = pgTable("booking_item_tax_lines", {
386
+ id: typeId("booking_item_tax_lines"),
387
+ bookingItemId: text("booking_item_id").notNull(),
388
+ code: text("code"),
389
+ name: text("name").notNull(),
390
+ jurisdiction: text("jurisdiction"),
391
+ scope: taxScopeEnum("scope").notNull().default("excluded"),
392
+ currency: text("currency").notNull(),
393
+ amountCents: integer("amount_cents").notNull(),
394
+ rateBasisPoints: integer("rate_basis_points"),
395
+ includedInPrice: boolean("included_in_price").notNull().default(false),
396
+ remittanceParty: text("remittance_party"),
397
+ sortOrder: integer("sort_order").notNull().default(0),
398
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
399
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
400
+ }, (table) => [
401
+ index("idx_booking_item_tax_lines_item").on(table.bookingItemId),
402
+ index("idx_booking_item_tax_lines_scope").on(table.scope),
403
+ ]);
404
+ // ---------- booking_item_commissions ----------
405
+ export const bookingItemCommissions = pgTable("booking_item_commissions", {
406
+ id: typeId("booking_item_commissions"),
407
+ bookingItemId: text("booking_item_id").notNull(),
408
+ channelId: text("channel_id"),
409
+ recipientType: commissionRecipientTypeEnum("recipient_type").notNull(),
410
+ commissionModel: commissionModelEnum("commission_model").notNull().default("percentage"),
411
+ currency: text("currency"),
412
+ amountCents: integer("amount_cents"),
413
+ rateBasisPoints: integer("rate_basis_points"),
414
+ status: commissionStatusEnum("status").notNull().default("pending"),
415
+ payableAt: date("payable_at"),
416
+ paidAt: date("paid_at"),
417
+ notes: text("notes"),
418
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
419
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
420
+ }, (table) => [
421
+ index("idx_booking_item_commissions_item").on(table.bookingItemId),
422
+ index("idx_booking_item_commissions_channel").on(table.channelId),
423
+ index("idx_booking_item_commissions_status").on(table.status),
424
+ ]);
425
+ // ---------- invoices ----------
426
+ export const invoices = pgTable("invoices", {
427
+ id: typeId("invoices"),
428
+ invoiceNumber: text("invoice_number").notNull().unique(),
429
+ invoiceType: invoiceTypeEnum("invoice_type").notNull().default("invoice"),
430
+ seriesId: typeIdRef("series_id"),
431
+ sequence: integer("sequence"),
432
+ templateId: typeIdRef("template_id"),
433
+ taxRegimeId: typeIdRef("tax_regime_id"),
434
+ language: text("language"),
435
+ bookingId: text("booking_id").notNull(),
436
+ personId: text("person_id"),
437
+ organizationId: text("organization_id"),
438
+ status: invoiceStatusEnum("status").notNull().default("draft"),
439
+ currency: text("currency").notNull(),
440
+ baseCurrency: text("base_currency"),
441
+ fxRateSetId: text("fx_rate_set_id"),
442
+ subtotalCents: integer("subtotal_cents").notNull().default(0),
443
+ baseSubtotalCents: integer("base_subtotal_cents"),
444
+ taxCents: integer("tax_cents").notNull().default(0),
445
+ baseTaxCents: integer("base_tax_cents"),
446
+ totalCents: integer("total_cents").notNull().default(0),
447
+ baseTotalCents: integer("base_total_cents"),
448
+ paidCents: integer("paid_cents").notNull().default(0),
449
+ basePaidCents: integer("base_paid_cents"),
450
+ balanceDueCents: integer("balance_due_cents").notNull().default(0),
451
+ baseBalanceDueCents: integer("base_balance_due_cents"),
452
+ commissionPercent: integer("commission_percent"),
453
+ commissionAmountCents: integer("commission_amount_cents"),
454
+ issueDate: date("issue_date").notNull(),
455
+ dueDate: date("due_date").notNull(),
456
+ notes: text("notes"),
457
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
458
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
459
+ }, (table) => [
460
+ index("idx_invoices_booking").on(table.bookingId),
461
+ index("idx_invoices_person").on(table.personId),
462
+ index("idx_invoices_organization").on(table.organizationId),
463
+ index("idx_invoices_status").on(table.status),
464
+ index("idx_invoices_fx_rate_set").on(table.fxRateSetId),
465
+ index("idx_invoices_number").on(table.invoiceNumber),
466
+ index("idx_invoices_due_date").on(table.dueDate),
467
+ ]);
468
+ // ---------- invoice_line_items ----------
469
+ export const invoiceLineItems = pgTable("invoice_line_items", {
470
+ id: typeId("invoice_line_items"),
471
+ invoiceId: typeIdRef("invoice_id")
472
+ .notNull()
473
+ .references(() => invoices.id, { onDelete: "cascade" }),
474
+ bookingItemId: text("booking_item_id"),
475
+ description: text("description").notNull(),
476
+ quantity: integer("quantity").notNull().default(1),
477
+ unitPriceCents: integer("unit_price_cents").notNull(),
478
+ totalCents: integer("total_cents").notNull(),
479
+ taxRate: integer("tax_rate"),
480
+ sortOrder: integer("sort_order").notNull().default(0),
481
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
482
+ }, (table) => [
483
+ index("idx_invoice_line_items_invoice").on(table.invoiceId),
484
+ index("idx_invoice_line_items_booking_item").on(table.bookingItemId),
485
+ ]);
486
+ // ---------- payments ----------
487
+ export const payments = pgTable("payments", {
488
+ id: typeId("payments"),
489
+ invoiceId: typeIdRef("invoice_id")
490
+ .notNull()
491
+ .references(() => invoices.id, { onDelete: "restrict" }),
492
+ amountCents: integer("amount_cents").notNull(),
493
+ currency: text("currency").notNull(),
494
+ baseCurrency: text("base_currency"),
495
+ baseAmountCents: integer("base_amount_cents"),
496
+ fxRateSetId: text("fx_rate_set_id"),
497
+ paymentMethod: paymentMethodEnum("payment_method").notNull(),
498
+ paymentInstrumentId: typeIdRef("payment_instrument_id").references(() => paymentInstruments.id, {
499
+ onDelete: "set null",
500
+ }),
501
+ paymentAuthorizationId: typeIdRef("payment_authorization_id").references(() => paymentAuthorizations.id, { onDelete: "set null" }),
502
+ paymentCaptureId: typeIdRef("payment_capture_id").references(() => paymentCaptures.id, {
503
+ onDelete: "set null",
504
+ }),
505
+ status: paymentStatusEnum("status").notNull().default("pending"),
506
+ referenceNumber: text("reference_number"),
507
+ paymentDate: date("payment_date").notNull(),
508
+ notes: text("notes"),
509
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
510
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
511
+ }, (table) => [
512
+ index("idx_payments_invoice").on(table.invoiceId),
513
+ index("idx_payments_fx_rate_set").on(table.fxRateSetId),
514
+ index("idx_payments_instrument").on(table.paymentInstrumentId),
515
+ index("idx_payments_authorization").on(table.paymentAuthorizationId),
516
+ index("idx_payments_capture").on(table.paymentCaptureId),
517
+ index("idx_payments_status").on(table.status),
518
+ index("idx_payments_date").on(table.paymentDate),
519
+ ]);
520
+ // ---------- credit_notes ----------
521
+ export const creditNotes = pgTable("credit_notes", {
522
+ id: typeId("credit_notes"),
523
+ creditNoteNumber: text("credit_note_number").notNull().unique(),
524
+ invoiceId: typeIdRef("invoice_id")
525
+ .notNull()
526
+ .references(() => invoices.id, { onDelete: "restrict" }),
527
+ status: creditNoteStatusEnum("status").notNull().default("draft"),
528
+ amountCents: integer("amount_cents").notNull(),
529
+ currency: text("currency").notNull(),
530
+ baseCurrency: text("base_currency"),
531
+ baseAmountCents: integer("base_amount_cents"),
532
+ fxRateSetId: text("fx_rate_set_id"),
533
+ reason: text("reason").notNull(),
534
+ notes: text("notes"),
535
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
536
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
537
+ }, (table) => [
538
+ index("idx_credit_notes_invoice").on(table.invoiceId),
539
+ index("idx_credit_notes_fx_rate_set").on(table.fxRateSetId),
540
+ index("idx_credit_notes_number").on(table.creditNoteNumber),
541
+ ]);
542
+ // ---------- credit_note_line_items ----------
543
+ export const creditNoteLineItems = pgTable("credit_note_line_items", {
544
+ id: typeId("credit_note_line_items"),
545
+ creditNoteId: typeIdRef("credit_note_id")
546
+ .notNull()
547
+ .references(() => creditNotes.id, { onDelete: "cascade" }),
548
+ description: text("description").notNull(),
549
+ quantity: integer("quantity").notNull().default(1),
550
+ unitPriceCents: integer("unit_price_cents").notNull(),
551
+ totalCents: integer("total_cents").notNull(),
552
+ sortOrder: integer("sort_order").notNull().default(0),
553
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
554
+ }, (table) => [index("idx_credit_note_line_items_credit_note").on(table.creditNoteId)]);
555
+ // ---------- supplier_payments ----------
556
+ export const supplierPayments = pgTable("supplier_payments", {
557
+ id: typeId("supplier_payments"),
558
+ bookingId: text("booking_id").notNull(),
559
+ supplierId: text("supplier_id"),
560
+ bookingSupplierStatusId: text("booking_supplier_status_id"),
561
+ amountCents: integer("amount_cents").notNull(),
562
+ currency: text("currency").notNull(),
563
+ baseCurrency: text("base_currency"),
564
+ baseAmountCents: integer("base_amount_cents"),
565
+ fxRateSetId: text("fx_rate_set_id"),
566
+ paymentMethod: paymentMethodEnum("payment_method").notNull(),
567
+ paymentInstrumentId: typeIdRef("payment_instrument_id").references(() => paymentInstruments.id, {
568
+ onDelete: "set null",
569
+ }),
570
+ status: paymentStatusEnum("status").notNull().default("pending"),
571
+ referenceNumber: text("reference_number"),
572
+ paymentDate: date("payment_date").notNull(),
573
+ notes: text("notes"),
574
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
575
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
576
+ }, (table) => [
577
+ index("idx_supplier_payments_booking").on(table.bookingId),
578
+ index("idx_supplier_payments_supplier").on(table.supplierId),
579
+ index("idx_supplier_payments_fx_rate_set").on(table.fxRateSetId),
580
+ index("idx_supplier_payments_instrument").on(table.paymentInstrumentId),
581
+ index("idx_supplier_payments_status").on(table.status),
582
+ index("idx_supplier_payments_date").on(table.paymentDate),
583
+ ]);
584
+ // ---------- finance_notes ----------
585
+ export const financeNotes = pgTable("finance_notes", {
586
+ id: typeId("finance_notes"),
587
+ invoiceId: typeIdRef("invoice_id")
588
+ .notNull()
589
+ .references(() => invoices.id, { onDelete: "cascade" }),
590
+ authorId: text("author_id").notNull(),
591
+ content: text("content").notNull(),
592
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
593
+ }, (table) => [index("idx_finance_notes_invoice").on(table.invoiceId)]);
594
+ // ---------- invoice_number_series ----------
595
+ export const invoiceNumberSeries = pgTable("invoice_number_series", {
596
+ id: typeId("invoice_number_series"),
597
+ code: text("code").notNull().unique(),
598
+ name: text("name").notNull(),
599
+ prefix: text("prefix").notNull().default(""),
600
+ separator: text("separator").notNull().default(""),
601
+ padLength: integer("pad_length").notNull().default(4),
602
+ currentSequence: integer("current_sequence").notNull().default(0),
603
+ resetStrategy: invoiceNumberResetStrategyEnum("reset_strategy").notNull().default("never"),
604
+ resetAt: timestamp("reset_at", { withTimezone: true }),
605
+ scope: invoiceNumberSeriesScopeEnum("scope").notNull().default("invoice"),
606
+ active: boolean("active").notNull().default(true),
607
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
608
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
609
+ }, (table) => [
610
+ index("idx_invoice_number_series_scope").on(table.scope),
611
+ index("idx_invoice_number_series_active").on(table.active),
612
+ ]);
613
+ // ---------- invoice_templates ----------
614
+ export const invoiceTemplates = pgTable("invoice_templates", {
615
+ id: typeId("invoice_templates"),
616
+ name: text("name").notNull(),
617
+ slug: text("slug").notNull().unique(),
618
+ language: text("language").notNull().default("en"),
619
+ jurisdiction: text("jurisdiction"),
620
+ bodyFormat: invoiceTemplateBodyFormatEnum("body_format").notNull().default("html"),
621
+ body: text("body").notNull(),
622
+ cssStyles: text("css_styles"),
623
+ isDefault: boolean("is_default").notNull().default(false),
624
+ active: boolean("active").notNull().default(true),
625
+ metadata: jsonb("metadata"),
626
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
627
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
628
+ }, (table) => [
629
+ index("idx_invoice_templates_language").on(table.language),
630
+ index("idx_invoice_templates_jurisdiction").on(table.jurisdiction),
631
+ index("idx_invoice_templates_default").on(table.isDefault),
632
+ index("idx_invoice_templates_active").on(table.active),
633
+ ]);
634
+ // ---------- invoice_renditions ----------
635
+ export const invoiceRenditions = pgTable("invoice_renditions", {
636
+ id: typeId("invoice_renditions"),
637
+ invoiceId: typeIdRef("invoice_id")
638
+ .notNull()
639
+ .references(() => invoices.id, { onDelete: "cascade" }),
640
+ templateId: typeIdRef("template_id").references(() => invoiceTemplates.id, {
641
+ onDelete: "set null",
642
+ }),
643
+ format: invoiceRenditionFormatEnum("format").notNull().default("pdf"),
644
+ status: invoiceRenditionStatusEnum("status").notNull().default("pending"),
645
+ storageKey: text("storage_key"),
646
+ fileSize: integer("file_size"),
647
+ checksum: text("checksum"),
648
+ language: text("language"),
649
+ errorMessage: text("error_message"),
650
+ generatedAt: timestamp("generated_at", { withTimezone: true }),
651
+ metadata: jsonb("metadata"),
652
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
653
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
654
+ }, (table) => [
655
+ index("idx_invoice_renditions_invoice").on(table.invoiceId),
656
+ index("idx_invoice_renditions_template").on(table.templateId),
657
+ index("idx_invoice_renditions_status").on(table.status),
658
+ index("idx_invoice_renditions_format").on(table.format),
659
+ ]);
660
+ // ---------- tax_regimes ----------
661
+ export const taxRegimes = pgTable("tax_regimes", {
662
+ id: typeId("tax_regimes"),
663
+ code: taxRegimeCodeEnum("code").notNull(),
664
+ name: text("name").notNull(),
665
+ jurisdiction: text("jurisdiction"),
666
+ ratePercent: integer("rate_percent"),
667
+ description: text("description"),
668
+ legalReference: text("legal_reference"),
669
+ active: boolean("active").notNull().default(true),
670
+ metadata: jsonb("metadata"),
671
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
672
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
673
+ }, (table) => [
674
+ index("idx_tax_regimes_code").on(table.code),
675
+ index("idx_tax_regimes_jurisdiction").on(table.jurisdiction),
676
+ index("idx_tax_regimes_active").on(table.active),
677
+ ]);
678
+ // ---------- invoice_external_refs ----------
679
+ export const invoiceExternalRefs = pgTable("invoice_external_refs", {
680
+ id: typeId("invoice_external_refs"),
681
+ invoiceId: typeIdRef("invoice_id")
682
+ .notNull()
683
+ .references(() => invoices.id, { onDelete: "cascade" }),
684
+ provider: text("provider").notNull(),
685
+ externalId: text("external_id"),
686
+ externalNumber: text("external_number"),
687
+ externalUrl: text("external_url"),
688
+ status: text("status"),
689
+ metadata: jsonb("metadata"),
690
+ syncedAt: timestamp("synced_at", { withTimezone: true }),
691
+ syncError: text("sync_error"),
692
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
693
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
694
+ }, (table) => [
695
+ index("idx_invoice_external_refs_invoice").on(table.invoiceId),
696
+ index("idx_invoice_external_refs_provider").on(table.provider),
697
+ uniqueIndex("uq_invoice_external_refs_invoice_provider").on(table.invoiceId, table.provider),
698
+ ]);
699
+ // ---------- relations ----------
700
+ export const invoicesRelations = relations(invoices, ({ many }) => ({
701
+ lineItems: many(invoiceLineItems),
702
+ payments: many(payments),
703
+ creditNotes: many(creditNotes),
704
+ notes: many(financeNotes),
705
+ authorizations: many(paymentAuthorizations),
706
+ captures: many(paymentCaptures),
707
+ }));
708
+ export const paymentInstrumentsRelations = relations(paymentInstruments, ({ many }) => ({
709
+ guarantees: many(bookingGuarantees),
710
+ payments: many(payments),
711
+ supplierPayments: many(supplierPayments),
712
+ authorizations: many(paymentAuthorizations),
713
+ }));
714
+ export const paymentAuthorizationsRelations = relations(paymentAuthorizations, ({ one, many }) => ({
715
+ invoice: one(invoices, {
716
+ fields: [paymentAuthorizations.invoiceId],
717
+ references: [invoices.id],
718
+ }),
719
+ paymentInstrument: one(paymentInstruments, {
720
+ fields: [paymentAuthorizations.paymentInstrumentId],
721
+ references: [paymentInstruments.id],
722
+ }),
723
+ bookingGuarantee: one(bookingGuarantees, {
724
+ fields: [paymentAuthorizations.bookingGuaranteeId],
725
+ references: [bookingGuarantees.id],
726
+ relationName: "guarantee_authorization",
727
+ }),
728
+ captures: many(paymentCaptures),
729
+ payments: many(payments),
730
+ }));
731
+ export const paymentCapturesRelations = relations(paymentCaptures, ({ one, many }) => ({
732
+ paymentAuthorization: one(paymentAuthorizations, {
733
+ fields: [paymentCaptures.paymentAuthorizationId],
734
+ references: [paymentAuthorizations.id],
735
+ }),
736
+ invoice: one(invoices, {
737
+ fields: [paymentCaptures.invoiceId],
738
+ references: [invoices.id],
739
+ }),
740
+ payments: many(payments),
741
+ }));
742
+ export const bookingPaymentSchedulesRelations = relations(bookingPaymentSchedules, ({ many }) => ({
743
+ guarantees: many(bookingGuarantees),
744
+ }));
745
+ export const bookingGuaranteesRelations = relations(bookingGuarantees, ({ one }) => ({
746
+ bookingPaymentSchedule: one(bookingPaymentSchedules, {
747
+ fields: [bookingGuarantees.bookingPaymentScheduleId],
748
+ references: [bookingPaymentSchedules.id],
749
+ }),
750
+ paymentInstrument: one(paymentInstruments, {
751
+ fields: [bookingGuarantees.paymentInstrumentId],
752
+ references: [paymentInstruments.id],
753
+ }),
754
+ paymentAuthorization: one(paymentAuthorizations, {
755
+ fields: [bookingGuarantees.paymentAuthorizationId],
756
+ references: [paymentAuthorizations.id],
757
+ relationName: "guarantee_authorization",
758
+ }),
759
+ }));
760
+ export const bookingItemTaxLinesRelations = relations(bookingItemTaxLines, () => ({}));
761
+ export const bookingItemCommissionsRelations = relations(bookingItemCommissions, () => ({}));
762
+ export const invoiceLineItemsRelations = relations(invoiceLineItems, ({ one }) => ({
763
+ invoice: one(invoices, { fields: [invoiceLineItems.invoiceId], references: [invoices.id] }),
764
+ }));
765
+ export const paymentsRelations = relations(payments, ({ one }) => ({
766
+ invoice: one(invoices, { fields: [payments.invoiceId], references: [invoices.id] }),
767
+ paymentInstrument: one(paymentInstruments, {
768
+ fields: [payments.paymentInstrumentId],
769
+ references: [paymentInstruments.id],
770
+ }),
771
+ paymentAuthorization: one(paymentAuthorizations, {
772
+ fields: [payments.paymentAuthorizationId],
773
+ references: [paymentAuthorizations.id],
774
+ }),
775
+ paymentCapture: one(paymentCaptures, {
776
+ fields: [payments.paymentCaptureId],
777
+ references: [paymentCaptures.id],
778
+ }),
779
+ }));
780
+ export const creditNotesRelations = relations(creditNotes, ({ one, many }) => ({
781
+ invoice: one(invoices, { fields: [creditNotes.invoiceId], references: [invoices.id] }),
782
+ lineItems: many(creditNoteLineItems),
783
+ }));
784
+ export const creditNoteLineItemsRelations = relations(creditNoteLineItems, ({ one }) => ({
785
+ creditNote: one(creditNotes, {
786
+ fields: [creditNoteLineItems.creditNoteId],
787
+ references: [creditNotes.id],
788
+ }),
789
+ }));
790
+ export const supplierPaymentsRelations = relations(supplierPayments, ({ one }) => ({
791
+ paymentInstrument: one(paymentInstruments, {
792
+ fields: [supplierPayments.paymentInstrumentId],
793
+ references: [paymentInstruments.id],
794
+ }),
795
+ }));
796
+ export const financeNotesRelations = relations(financeNotes, ({ one }) => ({
797
+ invoice: one(invoices, { fields: [financeNotes.invoiceId], references: [invoices.id] }),
798
+ }));
799
+ export const invoiceRenditionsRelations = relations(invoiceRenditions, ({ one }) => ({
800
+ invoice: one(invoices, { fields: [invoiceRenditions.invoiceId], references: [invoices.id] }),
801
+ template: one(invoiceTemplates, {
802
+ fields: [invoiceRenditions.templateId],
803
+ references: [invoiceTemplates.id],
804
+ }),
805
+ }));
806
+ export const invoiceExternalRefsRelations = relations(invoiceExternalRefs, ({ one }) => ({
807
+ invoice: one(invoices, {
808
+ fields: [invoiceExternalRefs.invoiceId],
809
+ references: [invoices.id],
810
+ }),
811
+ }));
812
+ export const invoiceNumberSeriesRelations = relations(invoiceNumberSeries, () => ({}));
813
+ export const invoiceTemplatesRelations = relations(invoiceTemplates, ({ many }) => ({
814
+ renditions: many(invoiceRenditions),
815
+ }));
816
+ export const taxRegimesRelations = relations(taxRegimes, () => ({}));