@voyantjs/distribution 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,760 @@
1
+ import { availabilitySlots, availabilityStartTimes } from "@voyantjs/availability/schema";
2
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
3
+ import { productOptions, products } from "@voyantjs/products/schema";
4
+ import { suppliers } from "@voyantjs/suppliers/schema";
5
+ import { relations } from "drizzle-orm";
6
+ import { boolean, date, index, integer, jsonb, pgEnum, pgTable, text, timestamp, } from "drizzle-orm/pg-core";
7
+ export const channelKindEnum = pgEnum("channel_kind", [
8
+ "direct",
9
+ "affiliate",
10
+ "ota",
11
+ "reseller",
12
+ "marketplace",
13
+ "api_partner",
14
+ ]);
15
+ export const channelStatusEnum = pgEnum("channel_status", [
16
+ "active",
17
+ "inactive",
18
+ "pending",
19
+ "archived",
20
+ ]);
21
+ export const channelContractStatusEnum = pgEnum("channel_contract_status", [
22
+ "draft",
23
+ "active",
24
+ "expired",
25
+ "terminated",
26
+ ]);
27
+ export const distributionPaymentOwnerEnum = pgEnum("distribution_payment_owner", [
28
+ "operator",
29
+ "channel",
30
+ "split",
31
+ ]);
32
+ export const distributionCancellationOwnerEnum = pgEnum("distribution_cancellation_owner", [
33
+ "operator",
34
+ "channel",
35
+ "mixed",
36
+ ]);
37
+ export const channelCommissionScopeEnum = pgEnum("channel_commission_scope", [
38
+ "booking",
39
+ "product",
40
+ "rate",
41
+ "category",
42
+ ]);
43
+ export const channelCommissionTypeEnum = pgEnum("channel_commission_type", ["fixed", "percentage"]);
44
+ export const channelWebhookStatusEnum = pgEnum("channel_webhook_status", [
45
+ "pending",
46
+ "processed",
47
+ "failed",
48
+ "ignored",
49
+ ]);
50
+ export const channelAllotmentReleaseModeEnum = pgEnum("channel_allotment_release_mode", [
51
+ "automatic",
52
+ "manual",
53
+ ]);
54
+ export const channelAllotmentUnsoldActionEnum = pgEnum("channel_allotment_unsold_action", [
55
+ "release_to_general_pool",
56
+ "expire",
57
+ "retain",
58
+ ]);
59
+ export const channelSettlementRunStatusEnum = pgEnum("channel_settlement_run_status", [
60
+ "draft",
61
+ "open",
62
+ "posted",
63
+ "paid",
64
+ "void",
65
+ ]);
66
+ export const channelSettlementItemStatusEnum = pgEnum("channel_settlement_item_status", [
67
+ "pending",
68
+ "approved",
69
+ "disputed",
70
+ "paid",
71
+ "void",
72
+ ]);
73
+ export const channelReconciliationRunStatusEnum = pgEnum("channel_reconciliation_run_status", [
74
+ "draft",
75
+ "running",
76
+ "completed",
77
+ "archived",
78
+ ]);
79
+ export const channelReconciliationIssueTypeEnum = pgEnum("channel_reconciliation_issue_type", [
80
+ "missing_booking",
81
+ "status_mismatch",
82
+ "amount_mismatch",
83
+ "cancel_mismatch",
84
+ "missing_payout",
85
+ "other",
86
+ ]);
87
+ export const channelReconciliationSeverityEnum = pgEnum("channel_reconciliation_severity", [
88
+ "info",
89
+ "warning",
90
+ "error",
91
+ ]);
92
+ export const channelReconciliationResolutionStatusEnum = pgEnum("channel_reconciliation_resolution_status", ["open", "ignored", "resolved"]);
93
+ export const channelReleaseExecutionStatusEnum = pgEnum("channel_release_execution_status", [
94
+ "pending",
95
+ "completed",
96
+ "skipped",
97
+ "failed",
98
+ ]);
99
+ export const channelReleaseExecutionActionEnum = pgEnum("channel_release_execution_action", [
100
+ "released",
101
+ "expired",
102
+ "retained",
103
+ "manual_override",
104
+ ]);
105
+ export const channelSettlementPolicyFrequencyEnum = pgEnum("channel_settlement_policy_frequency", [
106
+ "manual",
107
+ "daily",
108
+ "weekly",
109
+ "monthly",
110
+ ]);
111
+ export const channelReconciliationPolicyFrequencyEnum = pgEnum("channel_reconciliation_policy_frequency", ["manual", "daily", "weekly", "monthly"]);
112
+ export const channelReleaseScheduleKindEnum = pgEnum("channel_release_schedule_kind", [
113
+ "manual",
114
+ "hourly",
115
+ "daily",
116
+ ]);
117
+ export const channelRemittanceExceptionStatusEnum = pgEnum("channel_remittance_exception_status", [
118
+ "open",
119
+ "investigating",
120
+ "resolved",
121
+ "ignored",
122
+ ]);
123
+ export const channelSettlementApprovalStatusEnum = pgEnum("channel_settlement_approval_status", [
124
+ "pending",
125
+ "approved",
126
+ "rejected",
127
+ ]);
128
+ export const channels = pgTable("channels", {
129
+ id: typeId("channels"),
130
+ name: text("name").notNull(),
131
+ description: text("description"),
132
+ kind: channelKindEnum("kind").notNull(),
133
+ status: channelStatusEnum("status").notNull().default("active"),
134
+ metadata: jsonb("metadata").$type(),
135
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
136
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
137
+ }, (table) => [
138
+ index("idx_channels_kind").on(table.kind),
139
+ index("idx_channels_status").on(table.status),
140
+ ]);
141
+ export const channelContracts = pgTable("channel_contracts", {
142
+ id: typeId("channel_contracts"),
143
+ channelId: typeIdRef("channel_id")
144
+ .notNull()
145
+ .references(() => channels.id, { onDelete: "cascade" }),
146
+ supplierId: typeIdRef("supplier_id").references(() => suppliers.id, { onDelete: "set null" }),
147
+ status: channelContractStatusEnum("status").notNull().default("draft"),
148
+ startsAt: date("starts_at").notNull(),
149
+ endsAt: date("ends_at"),
150
+ paymentOwner: distributionPaymentOwnerEnum("payment_owner").notNull().default("operator"),
151
+ cancellationOwner: distributionCancellationOwnerEnum("cancellation_owner")
152
+ .notNull()
153
+ .default("operator"),
154
+ settlementTerms: text("settlement_terms"),
155
+ notes: text("notes"),
156
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
157
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
158
+ }, (table) => [
159
+ index("idx_channel_contracts_channel").on(table.channelId),
160
+ index("idx_channel_contracts_supplier").on(table.supplierId),
161
+ index("idx_channel_contracts_status").on(table.status),
162
+ ]);
163
+ export const channelCommissionRules = pgTable("channel_commission_rules", {
164
+ id: typeId("channel_commission_rules"),
165
+ contractId: typeIdRef("contract_id")
166
+ .notNull()
167
+ .references(() => channelContracts.id, { onDelete: "cascade" }),
168
+ scope: channelCommissionScopeEnum("scope").notNull(),
169
+ productId: typeIdRef("product_id").references(() => products.id, { onDelete: "set null" }),
170
+ externalRateId: text("external_rate_id"),
171
+ externalCategoryId: text("external_category_id"),
172
+ commissionType: channelCommissionTypeEnum("commission_type").notNull(),
173
+ amountCents: integer("amount_cents"),
174
+ percentBasisPoints: integer("percent_basis_points"),
175
+ validFrom: date("valid_from"),
176
+ validTo: date("valid_to"),
177
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
178
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
179
+ }, (table) => [
180
+ index("idx_channel_commission_rules_contract").on(table.contractId),
181
+ index("idx_channel_commission_rules_product").on(table.productId),
182
+ index("idx_channel_commission_rules_scope").on(table.scope),
183
+ ]);
184
+ export const channelProductMappings = pgTable("channel_product_mappings", {
185
+ id: typeId("channel_product_mappings"),
186
+ channelId: typeIdRef("channel_id")
187
+ .notNull()
188
+ .references(() => channels.id, { onDelete: "cascade" }),
189
+ productId: typeIdRef("product_id")
190
+ .notNull()
191
+ .references(() => products.id, { onDelete: "cascade" }),
192
+ externalProductId: text("external_product_id"),
193
+ externalRateId: text("external_rate_id"),
194
+ externalCategoryId: text("external_category_id"),
195
+ active: boolean("active").notNull().default(true),
196
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
197
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
198
+ }, (table) => [
199
+ index("idx_channel_product_mappings_channel").on(table.channelId),
200
+ index("idx_channel_product_mappings_product").on(table.productId),
201
+ index("idx_channel_product_mappings_active").on(table.active),
202
+ ]);
203
+ export const channelBookingLinks = pgTable("channel_booking_links", {
204
+ id: typeId("channel_booking_links"),
205
+ channelId: typeIdRef("channel_id")
206
+ .notNull()
207
+ .references(() => channels.id, { onDelete: "cascade" }),
208
+ bookingId: text("booking_id").notNull(),
209
+ externalBookingId: text("external_booking_id"),
210
+ externalReference: text("external_reference"),
211
+ externalStatus: text("external_status"),
212
+ bookedAtExternal: timestamp("booked_at_external", { withTimezone: true }),
213
+ lastSyncedAt: timestamp("last_synced_at", { withTimezone: true }),
214
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
215
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
216
+ }, (table) => [
217
+ index("idx_channel_booking_links_channel").on(table.channelId),
218
+ index("idx_channel_booking_links_booking").on(table.bookingId),
219
+ index("idx_channel_booking_links_external_booking").on(table.externalBookingId),
220
+ ]);
221
+ export const channelWebhookEvents = pgTable("channel_webhook_events", {
222
+ id: typeId("channel_webhook_events"),
223
+ channelId: typeIdRef("channel_id")
224
+ .notNull()
225
+ .references(() => channels.id, { onDelete: "cascade" }),
226
+ eventType: text("event_type").notNull(),
227
+ externalEventId: text("external_event_id"),
228
+ payload: jsonb("payload").$type().notNull(),
229
+ receivedAt: timestamp("received_at", { withTimezone: true }).notNull().defaultNow(),
230
+ processedAt: timestamp("processed_at", { withTimezone: true }),
231
+ status: channelWebhookStatusEnum("status").notNull().default("pending"),
232
+ errorMessage: text("error_message"),
233
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
234
+ }, (table) => [
235
+ index("idx_channel_webhook_events_channel").on(table.channelId),
236
+ index("idx_channel_webhook_events_status").on(table.status),
237
+ index("idx_channel_webhook_events_external_event").on(table.externalEventId),
238
+ ]);
239
+ export const channelInventoryAllotments = pgTable("channel_inventory_allotments", {
240
+ id: typeId("channel_inventory_allotments"),
241
+ channelId: typeIdRef("channel_id")
242
+ .notNull()
243
+ .references(() => channels.id, { onDelete: "cascade" }),
244
+ contractId: typeIdRef("contract_id").references(() => channelContracts.id, {
245
+ onDelete: "set null",
246
+ }),
247
+ productId: typeIdRef("product_id")
248
+ .notNull()
249
+ .references(() => products.id, { onDelete: "cascade" }),
250
+ optionId: typeIdRef("option_id").references(() => productOptions.id, { onDelete: "set null" }),
251
+ startTimeId: typeIdRef("start_time_id").references(() => availabilityStartTimes.id, {
252
+ onDelete: "set null",
253
+ }),
254
+ validFrom: date("valid_from"),
255
+ validTo: date("valid_to"),
256
+ guaranteedCapacity: integer("guaranteed_capacity"),
257
+ maxCapacity: integer("max_capacity"),
258
+ active: boolean("active").notNull().default(true),
259
+ notes: text("notes"),
260
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
261
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
262
+ }, (table) => [
263
+ index("idx_channel_inventory_allotments_channel").on(table.channelId),
264
+ index("idx_channel_inventory_allotments_contract").on(table.contractId),
265
+ index("idx_channel_inventory_allotments_product").on(table.productId),
266
+ index("idx_channel_inventory_allotments_option").on(table.optionId),
267
+ index("idx_channel_inventory_allotments_start_time").on(table.startTimeId),
268
+ index("idx_channel_inventory_allotments_active").on(table.active),
269
+ ]);
270
+ export const channelInventoryAllotmentTargets = pgTable("channel_inventory_allotment_targets", {
271
+ id: typeId("channel_inventory_allotment_targets"),
272
+ allotmentId: typeIdRef("allotment_id")
273
+ .notNull()
274
+ .references(() => channelInventoryAllotments.id, { onDelete: "cascade" }),
275
+ slotId: typeIdRef("slot_id").references(() => availabilitySlots.id, { onDelete: "cascade" }),
276
+ startTimeId: typeIdRef("start_time_id").references(() => availabilityStartTimes.id, {
277
+ onDelete: "set null",
278
+ }),
279
+ dateLocal: date("date_local"),
280
+ guaranteedCapacity: integer("guaranteed_capacity"),
281
+ maxCapacity: integer("max_capacity"),
282
+ soldCapacity: integer("sold_capacity"),
283
+ remainingCapacity: integer("remaining_capacity"),
284
+ active: boolean("active").notNull().default(true),
285
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
286
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
287
+ }, (table) => [
288
+ index("idx_channel_inventory_allotment_targets_allotment").on(table.allotmentId),
289
+ index("idx_channel_inventory_allotment_targets_slot").on(table.slotId),
290
+ index("idx_channel_inventory_allotment_targets_start_time").on(table.startTimeId),
291
+ index("idx_channel_inventory_allotment_targets_date").on(table.dateLocal),
292
+ index("idx_channel_inventory_allotment_targets_active").on(table.active),
293
+ ]);
294
+ export const channelInventoryReleaseRules = pgTable("channel_inventory_release_rules", {
295
+ id: typeId("channel_inventory_release_rules"),
296
+ allotmentId: typeIdRef("allotment_id")
297
+ .notNull()
298
+ .references(() => channelInventoryAllotments.id, { onDelete: "cascade" }),
299
+ releaseMode: channelAllotmentReleaseModeEnum("release_mode").notNull().default("automatic"),
300
+ releaseDaysBeforeStart: integer("release_days_before_start"),
301
+ releaseHoursBeforeStart: integer("release_hours_before_start"),
302
+ unsoldAction: channelAllotmentUnsoldActionEnum("unsold_action")
303
+ .notNull()
304
+ .default("release_to_general_pool"),
305
+ notes: text("notes"),
306
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
307
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
308
+ }, (table) => [
309
+ index("idx_channel_inventory_release_rules_allotment").on(table.allotmentId),
310
+ index("idx_channel_inventory_release_rules_mode").on(table.releaseMode),
311
+ ]);
312
+ export const channelSettlementRuns = pgTable("channel_settlement_runs", {
313
+ id: typeId("channel_settlement_runs"),
314
+ channelId: typeIdRef("channel_id")
315
+ .notNull()
316
+ .references(() => channels.id, { onDelete: "cascade" }),
317
+ contractId: typeIdRef("contract_id").references(() => channelContracts.id, {
318
+ onDelete: "set null",
319
+ }),
320
+ status: channelSettlementRunStatusEnum("status").notNull().default("draft"),
321
+ currencyCode: text("currency_code"),
322
+ periodStart: date("period_start"),
323
+ periodEnd: date("period_end"),
324
+ statementReference: text("statement_reference"),
325
+ generatedAt: timestamp("generated_at", { withTimezone: true }),
326
+ postedAt: timestamp("posted_at", { withTimezone: true }),
327
+ paidAt: timestamp("paid_at", { withTimezone: true }),
328
+ notes: text("notes"),
329
+ metadata: jsonb("metadata").$type(),
330
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
331
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
332
+ }, (table) => [
333
+ index("idx_channel_settlement_runs_channel").on(table.channelId),
334
+ index("idx_channel_settlement_runs_contract").on(table.contractId),
335
+ index("idx_channel_settlement_runs_status").on(table.status),
336
+ index("idx_channel_settlement_runs_period").on(table.periodStart, table.periodEnd),
337
+ ]);
338
+ export const channelSettlementItems = pgTable("channel_settlement_items", {
339
+ id: typeId("channel_settlement_items"),
340
+ settlementRunId: typeIdRef("settlement_run_id")
341
+ .notNull()
342
+ .references(() => channelSettlementRuns.id, { onDelete: "cascade" }),
343
+ bookingLinkId: typeIdRef("booking_link_id").references(() => channelBookingLinks.id, {
344
+ onDelete: "set null",
345
+ }),
346
+ bookingId: text("booking_id"),
347
+ commissionRuleId: typeIdRef("commission_rule_id").references(() => channelCommissionRules.id, {
348
+ onDelete: "set null",
349
+ }),
350
+ status: channelSettlementItemStatusEnum("status").notNull().default("pending"),
351
+ grossAmountCents: integer("gross_amount_cents").notNull().default(0),
352
+ commissionAmountCents: integer("commission_amount_cents").notNull().default(0),
353
+ netRemittanceAmountCents: integer("net_remittance_amount_cents").notNull().default(0),
354
+ currencyCode: text("currency_code"),
355
+ remittanceDueAt: timestamp("remittance_due_at", { withTimezone: true }),
356
+ paidAt: timestamp("paid_at", { withTimezone: true }),
357
+ notes: text("notes"),
358
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
359
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
360
+ }, (table) => [
361
+ index("idx_channel_settlement_items_run").on(table.settlementRunId),
362
+ index("idx_channel_settlement_items_booking_link").on(table.bookingLinkId),
363
+ index("idx_channel_settlement_items_booking").on(table.bookingId),
364
+ index("idx_channel_settlement_items_status").on(table.status),
365
+ ]);
366
+ export const channelReconciliationRuns = pgTable("channel_reconciliation_runs", {
367
+ id: typeId("channel_reconciliation_runs"),
368
+ channelId: typeIdRef("channel_id")
369
+ .notNull()
370
+ .references(() => channels.id, { onDelete: "cascade" }),
371
+ contractId: typeIdRef("contract_id").references(() => channelContracts.id, {
372
+ onDelete: "set null",
373
+ }),
374
+ status: channelReconciliationRunStatusEnum("status").notNull().default("draft"),
375
+ periodStart: date("period_start"),
376
+ periodEnd: date("period_end"),
377
+ externalReportReference: text("external_report_reference"),
378
+ startedAt: timestamp("started_at", { withTimezone: true }),
379
+ completedAt: timestamp("completed_at", { withTimezone: true }),
380
+ notes: text("notes"),
381
+ metadata: jsonb("metadata").$type(),
382
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
383
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
384
+ }, (table) => [
385
+ index("idx_channel_reconciliation_runs_channel").on(table.channelId),
386
+ index("idx_channel_reconciliation_runs_contract").on(table.contractId),
387
+ index("idx_channel_reconciliation_runs_status").on(table.status),
388
+ ]);
389
+ export const channelReconciliationItems = pgTable("channel_reconciliation_items", {
390
+ id: typeId("channel_reconciliation_items"),
391
+ reconciliationRunId: typeIdRef("reconciliation_run_id")
392
+ .notNull()
393
+ .references(() => channelReconciliationRuns.id, { onDelete: "cascade" }),
394
+ bookingLinkId: typeIdRef("booking_link_id").references(() => channelBookingLinks.id, {
395
+ onDelete: "set null",
396
+ }),
397
+ bookingId: text("booking_id"),
398
+ externalBookingId: text("external_booking_id"),
399
+ issueType: channelReconciliationIssueTypeEnum("issue_type").notNull().default("other"),
400
+ severity: channelReconciliationSeverityEnum("severity").notNull().default("warning"),
401
+ resolutionStatus: channelReconciliationResolutionStatusEnum("resolution_status")
402
+ .notNull()
403
+ .default("open"),
404
+ notes: text("notes"),
405
+ resolvedAt: timestamp("resolved_at", { withTimezone: true }),
406
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
407
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
408
+ }, (table) => [
409
+ index("idx_channel_reconciliation_items_run").on(table.reconciliationRunId),
410
+ index("idx_channel_reconciliation_items_booking_link").on(table.bookingLinkId),
411
+ index("idx_channel_reconciliation_items_booking").on(table.bookingId),
412
+ index("idx_channel_reconciliation_items_issue").on(table.issueType),
413
+ index("idx_channel_reconciliation_items_resolution").on(table.resolutionStatus),
414
+ ]);
415
+ export const channelInventoryReleaseExecutions = pgTable("channel_inventory_release_executions", {
416
+ id: typeId("channel_inventory_release_executions"),
417
+ allotmentId: typeIdRef("allotment_id")
418
+ .notNull()
419
+ .references(() => channelInventoryAllotments.id, { onDelete: "cascade" }),
420
+ releaseRuleId: typeIdRef("release_rule_id").references(() => channelInventoryReleaseRules.id, {
421
+ onDelete: "set null",
422
+ }),
423
+ targetId: typeIdRef("target_id").references(() => channelInventoryAllotmentTargets.id, {
424
+ onDelete: "set null",
425
+ }),
426
+ slotId: typeIdRef("slot_id").references(() => availabilitySlots.id, { onDelete: "set null" }),
427
+ actionTaken: channelReleaseExecutionActionEnum("action_taken").notNull().default("released"),
428
+ status: channelReleaseExecutionStatusEnum("status").notNull().default("pending"),
429
+ releasedCapacity: integer("released_capacity"),
430
+ executedAt: timestamp("executed_at", { withTimezone: true }),
431
+ notes: text("notes"),
432
+ metadata: jsonb("metadata").$type(),
433
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
434
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
435
+ }, (table) => [
436
+ index("idx_channel_inventory_release_executions_allotment").on(table.allotmentId),
437
+ index("idx_channel_inventory_release_executions_rule").on(table.releaseRuleId),
438
+ index("idx_channel_inventory_release_executions_target").on(table.targetId),
439
+ index("idx_channel_inventory_release_executions_status").on(table.status),
440
+ ]);
441
+ export const channelSettlementPolicies = pgTable("channel_settlement_policies", {
442
+ id: typeId("channel_settlement_policies"),
443
+ channelId: typeIdRef("channel_id")
444
+ .notNull()
445
+ .references(() => channels.id, { onDelete: "cascade" }),
446
+ contractId: typeIdRef("contract_id").references(() => channelContracts.id, {
447
+ onDelete: "set null",
448
+ }),
449
+ frequency: channelSettlementPolicyFrequencyEnum("frequency").notNull().default("manual"),
450
+ autoGenerate: boolean("auto_generate").notNull().default(false),
451
+ approvalRequired: boolean("approval_required").notNull().default(false),
452
+ remittanceDaysAfterPeriodEnd: integer("remittance_days_after_period_end"),
453
+ minimumPayoutAmountCents: integer("minimum_payout_amount_cents"),
454
+ currencyCode: text("currency_code"),
455
+ active: boolean("active").notNull().default(true),
456
+ notes: text("notes"),
457
+ metadata: jsonb("metadata").$type(),
458
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
459
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
460
+ }, (table) => [
461
+ index("idx_channel_settlement_policies_channel").on(table.channelId),
462
+ index("idx_channel_settlement_policies_contract").on(table.contractId),
463
+ index("idx_channel_settlement_policies_frequency").on(table.frequency),
464
+ index("idx_channel_settlement_policies_active").on(table.active),
465
+ ]);
466
+ export const channelReconciliationPolicies = pgTable("channel_reconciliation_policies", {
467
+ id: typeId("channel_reconciliation_policies"),
468
+ channelId: typeIdRef("channel_id")
469
+ .notNull()
470
+ .references(() => channels.id, { onDelete: "cascade" }),
471
+ contractId: typeIdRef("contract_id").references(() => channelContracts.id, {
472
+ onDelete: "set null",
473
+ }),
474
+ frequency: channelReconciliationPolicyFrequencyEnum("frequency").notNull().default("manual"),
475
+ autoRun: boolean("auto_run").notNull().default(false),
476
+ compareGrossAmounts: boolean("compare_gross_amounts").notNull().default(true),
477
+ compareStatuses: boolean("compare_statuses").notNull().default(true),
478
+ compareCancellations: boolean("compare_cancellations").notNull().default(true),
479
+ amountToleranceCents: integer("amount_tolerance_cents"),
480
+ active: boolean("active").notNull().default(true),
481
+ notes: text("notes"),
482
+ metadata: jsonb("metadata").$type(),
483
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
484
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
485
+ }, (table) => [
486
+ index("idx_channel_reconciliation_policies_channel").on(table.channelId),
487
+ index("idx_channel_reconciliation_policies_contract").on(table.contractId),
488
+ index("idx_channel_reconciliation_policies_frequency").on(table.frequency),
489
+ index("idx_channel_reconciliation_policies_active").on(table.active),
490
+ ]);
491
+ export const channelReleaseSchedules = pgTable("channel_release_schedules", {
492
+ id: typeId("channel_release_schedules"),
493
+ releaseRuleId: typeIdRef("release_rule_id")
494
+ .notNull()
495
+ .references(() => channelInventoryReleaseRules.id, { onDelete: "cascade" }),
496
+ scheduleKind: channelReleaseScheduleKindEnum("schedule_kind").notNull().default("manual"),
497
+ nextRunAt: timestamp("next_run_at", { withTimezone: true }),
498
+ lastRunAt: timestamp("last_run_at", { withTimezone: true }),
499
+ active: boolean("active").notNull().default(true),
500
+ notes: text("notes"),
501
+ metadata: jsonb("metadata").$type(),
502
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
503
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
504
+ }, (table) => [
505
+ index("idx_channel_release_schedules_rule").on(table.releaseRuleId),
506
+ index("idx_channel_release_schedules_kind").on(table.scheduleKind),
507
+ index("idx_channel_release_schedules_active").on(table.active),
508
+ ]);
509
+ export const channelRemittanceExceptions = pgTable("channel_remittance_exceptions", {
510
+ id: typeId("channel_remittance_exceptions"),
511
+ channelId: typeIdRef("channel_id")
512
+ .notNull()
513
+ .references(() => channels.id, { onDelete: "cascade" }),
514
+ settlementItemId: typeIdRef("settlement_item_id").references(() => channelSettlementItems.id, {
515
+ onDelete: "set null",
516
+ }),
517
+ reconciliationItemId: typeIdRef("reconciliation_item_id").references(() => channelReconciliationItems.id, { onDelete: "set null" }),
518
+ exceptionType: text("exception_type").notNull(),
519
+ severity: channelReconciliationSeverityEnum("severity").notNull().default("warning"),
520
+ status: channelRemittanceExceptionStatusEnum("status").notNull().default("open"),
521
+ openedAt: timestamp("opened_at", { withTimezone: true }).notNull().defaultNow(),
522
+ resolvedAt: timestamp("resolved_at", { withTimezone: true }),
523
+ notes: text("notes"),
524
+ metadata: jsonb("metadata").$type(),
525
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
526
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
527
+ }, (table) => [
528
+ index("idx_channel_remittance_exceptions_channel").on(table.channelId),
529
+ index("idx_channel_remittance_exceptions_settlement_item").on(table.settlementItemId),
530
+ index("idx_channel_remittance_exceptions_reconciliation_item").on(table.reconciliationItemId),
531
+ index("idx_channel_remittance_exceptions_status").on(table.status),
532
+ ]);
533
+ export const channelSettlementApprovals = pgTable("channel_settlement_approvals", {
534
+ id: typeId("channel_settlement_approvals"),
535
+ settlementRunId: typeIdRef("settlement_run_id")
536
+ .notNull()
537
+ .references(() => channelSettlementRuns.id, { onDelete: "cascade" }),
538
+ approverUserId: text("approver_user_id"),
539
+ status: channelSettlementApprovalStatusEnum("status").notNull().default("pending"),
540
+ decidedAt: timestamp("decided_at", { withTimezone: true }),
541
+ notes: text("notes"),
542
+ metadata: jsonb("metadata").$type(),
543
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
544
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
545
+ }, (table) => [
546
+ index("idx_channel_settlement_approvals_run").on(table.settlementRunId),
547
+ index("idx_channel_settlement_approvals_status").on(table.status),
548
+ ]);
549
+ export const channelsRelations = relations(channels, ({ many }) => ({
550
+ contracts: many(channelContracts),
551
+ productMappings: many(channelProductMappings),
552
+ bookingLinks: many(channelBookingLinks),
553
+ webhookEvents: many(channelWebhookEvents),
554
+ inventoryAllotments: many(channelInventoryAllotments),
555
+ settlementRuns: many(channelSettlementRuns),
556
+ reconciliationRuns: many(channelReconciliationRuns),
557
+ settlementPolicies: many(channelSettlementPolicies),
558
+ reconciliationPolicies: many(channelReconciliationPolicies),
559
+ remittanceExceptions: many(channelRemittanceExceptions),
560
+ }));
561
+ export const channelContractsRelations = relations(channelContracts, ({ one, many }) => ({
562
+ channel: one(channels, { fields: [channelContracts.channelId], references: [channels.id] }),
563
+ supplier: one(suppliers, {
564
+ fields: [channelContracts.supplierId],
565
+ references: [suppliers.id],
566
+ }),
567
+ commissionRules: many(channelCommissionRules),
568
+ inventoryAllotments: many(channelInventoryAllotments),
569
+ settlementRuns: many(channelSettlementRuns),
570
+ reconciliationRuns: many(channelReconciliationRuns),
571
+ }));
572
+ export const channelCommissionRulesRelations = relations(channelCommissionRules, ({ one }) => ({
573
+ contract: one(channelContracts, {
574
+ fields: [channelCommissionRules.contractId],
575
+ references: [channelContracts.id],
576
+ }),
577
+ product: one(products, {
578
+ fields: [channelCommissionRules.productId],
579
+ references: [products.id],
580
+ }),
581
+ }));
582
+ export const channelProductMappingsRelations = relations(channelProductMappings, ({ one }) => ({
583
+ channel: one(channels, {
584
+ fields: [channelProductMappings.channelId],
585
+ references: [channels.id],
586
+ }),
587
+ product: one(products, {
588
+ fields: [channelProductMappings.productId],
589
+ references: [products.id],
590
+ }),
591
+ }));
592
+ export const channelBookingLinksRelations = relations(channelBookingLinks, ({ one }) => ({
593
+ channel: one(channels, {
594
+ fields: [channelBookingLinks.channelId],
595
+ references: [channels.id],
596
+ }),
597
+ }));
598
+ export const channelInventoryAllotmentsRelations = relations(channelInventoryAllotments, ({ one, many }) => ({
599
+ channel: one(channels, {
600
+ fields: [channelInventoryAllotments.channelId],
601
+ references: [channels.id],
602
+ }),
603
+ contract: one(channelContracts, {
604
+ fields: [channelInventoryAllotments.contractId],
605
+ references: [channelContracts.id],
606
+ }),
607
+ product: one(products, {
608
+ fields: [channelInventoryAllotments.productId],
609
+ references: [products.id],
610
+ }),
611
+ option: one(productOptions, {
612
+ fields: [channelInventoryAllotments.optionId],
613
+ references: [productOptions.id],
614
+ }),
615
+ startTime: one(availabilityStartTimes, {
616
+ fields: [channelInventoryAllotments.startTimeId],
617
+ references: [availabilityStartTimes.id],
618
+ }),
619
+ targets: many(channelInventoryAllotmentTargets),
620
+ releaseRules: many(channelInventoryReleaseRules),
621
+ releaseExecutions: many(channelInventoryReleaseExecutions),
622
+ }));
623
+ export const channelInventoryAllotmentTargetsRelations = relations(channelInventoryAllotmentTargets, ({ one }) => ({
624
+ allotment: one(channelInventoryAllotments, {
625
+ fields: [channelInventoryAllotmentTargets.allotmentId],
626
+ references: [channelInventoryAllotments.id],
627
+ }),
628
+ slot: one(availabilitySlots, {
629
+ fields: [channelInventoryAllotmentTargets.slotId],
630
+ references: [availabilitySlots.id],
631
+ }),
632
+ startTime: one(availabilityStartTimes, {
633
+ fields: [channelInventoryAllotmentTargets.startTimeId],
634
+ references: [availabilityStartTimes.id],
635
+ }),
636
+ }));
637
+ export const channelInventoryReleaseRulesRelations = relations(channelInventoryReleaseRules, ({ one, many }) => ({
638
+ allotment: one(channelInventoryAllotments, {
639
+ fields: [channelInventoryReleaseRules.allotmentId],
640
+ references: [channelInventoryAllotments.id],
641
+ }),
642
+ schedules: many(channelReleaseSchedules),
643
+ }));
644
+ export const channelSettlementRunsRelations = relations(channelSettlementRuns, ({ one, many }) => ({
645
+ channel: one(channels, {
646
+ fields: [channelSettlementRuns.channelId],
647
+ references: [channels.id],
648
+ }),
649
+ contract: one(channelContracts, {
650
+ fields: [channelSettlementRuns.contractId],
651
+ references: [channelContracts.id],
652
+ }),
653
+ items: many(channelSettlementItems),
654
+ approvals: many(channelSettlementApprovals),
655
+ }));
656
+ export const channelSettlementItemsRelations = relations(channelSettlementItems, ({ one }) => ({
657
+ settlementRun: one(channelSettlementRuns, {
658
+ fields: [channelSettlementItems.settlementRunId],
659
+ references: [channelSettlementRuns.id],
660
+ }),
661
+ bookingLink: one(channelBookingLinks, {
662
+ fields: [channelSettlementItems.bookingLinkId],
663
+ references: [channelBookingLinks.id],
664
+ }),
665
+ commissionRule: one(channelCommissionRules, {
666
+ fields: [channelSettlementItems.commissionRuleId],
667
+ references: [channelCommissionRules.id],
668
+ }),
669
+ }));
670
+ export const channelReconciliationRunsRelations = relations(channelReconciliationRuns, ({ one, many }) => ({
671
+ channel: one(channels, {
672
+ fields: [channelReconciliationRuns.channelId],
673
+ references: [channels.id],
674
+ }),
675
+ contract: one(channelContracts, {
676
+ fields: [channelReconciliationRuns.contractId],
677
+ references: [channelContracts.id],
678
+ }),
679
+ items: many(channelReconciliationItems),
680
+ }));
681
+ export const channelReconciliationItemsRelations = relations(channelReconciliationItems, ({ one }) => ({
682
+ reconciliationRun: one(channelReconciliationRuns, {
683
+ fields: [channelReconciliationItems.reconciliationRunId],
684
+ references: [channelReconciliationRuns.id],
685
+ }),
686
+ bookingLink: one(channelBookingLinks, {
687
+ fields: [channelReconciliationItems.bookingLinkId],
688
+ references: [channelBookingLinks.id],
689
+ }),
690
+ }));
691
+ export const channelInventoryReleaseExecutionsRelations = relations(channelInventoryReleaseExecutions, ({ one }) => ({
692
+ allotment: one(channelInventoryAllotments, {
693
+ fields: [channelInventoryReleaseExecutions.allotmentId],
694
+ references: [channelInventoryAllotments.id],
695
+ }),
696
+ releaseRule: one(channelInventoryReleaseRules, {
697
+ fields: [channelInventoryReleaseExecutions.releaseRuleId],
698
+ references: [channelInventoryReleaseRules.id],
699
+ }),
700
+ target: one(channelInventoryAllotmentTargets, {
701
+ fields: [channelInventoryReleaseExecutions.targetId],
702
+ references: [channelInventoryAllotmentTargets.id],
703
+ }),
704
+ slot: one(availabilitySlots, {
705
+ fields: [channelInventoryReleaseExecutions.slotId],
706
+ references: [availabilitySlots.id],
707
+ }),
708
+ }));
709
+ export const channelSettlementPoliciesRelations = relations(channelSettlementPolicies, ({ one }) => ({
710
+ channel: one(channels, {
711
+ fields: [channelSettlementPolicies.channelId],
712
+ references: [channels.id],
713
+ }),
714
+ contract: one(channelContracts, {
715
+ fields: [channelSettlementPolicies.contractId],
716
+ references: [channelContracts.id],
717
+ }),
718
+ }));
719
+ export const channelReconciliationPoliciesRelations = relations(channelReconciliationPolicies, ({ one }) => ({
720
+ channel: one(channels, {
721
+ fields: [channelReconciliationPolicies.channelId],
722
+ references: [channels.id],
723
+ }),
724
+ contract: one(channelContracts, {
725
+ fields: [channelReconciliationPolicies.contractId],
726
+ references: [channelContracts.id],
727
+ }),
728
+ }));
729
+ export const channelReleaseSchedulesRelations = relations(channelReleaseSchedules, ({ one }) => ({
730
+ releaseRule: one(channelInventoryReleaseRules, {
731
+ fields: [channelReleaseSchedules.releaseRuleId],
732
+ references: [channelInventoryReleaseRules.id],
733
+ }),
734
+ }));
735
+ export const channelRemittanceExceptionsRelations = relations(channelRemittanceExceptions, ({ one }) => ({
736
+ channel: one(channels, {
737
+ fields: [channelRemittanceExceptions.channelId],
738
+ references: [channels.id],
739
+ }),
740
+ settlementItem: one(channelSettlementItems, {
741
+ fields: [channelRemittanceExceptions.settlementItemId],
742
+ references: [channelSettlementItems.id],
743
+ }),
744
+ reconciliationItem: one(channelReconciliationItems, {
745
+ fields: [channelRemittanceExceptions.reconciliationItemId],
746
+ references: [channelReconciliationItems.id],
747
+ }),
748
+ }));
749
+ export const channelSettlementApprovalsRelations = relations(channelSettlementApprovals, ({ one }) => ({
750
+ settlementRun: one(channelSettlementRuns, {
751
+ fields: [channelSettlementApprovals.settlementRunId],
752
+ references: [channelSettlementRuns.id],
753
+ }),
754
+ }));
755
+ export const channelWebhookEventsRelations = relations(channelWebhookEvents, ({ one }) => ({
756
+ channel: one(channels, {
757
+ fields: [channelWebhookEvents.channelId],
758
+ references: [channels.id],
759
+ }),
760
+ }));