@axova/shared 1.0.0 → 1.0.2

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 (33) hide show
  1. package/dist/index.d.ts +0 -1
  2. package/dist/index.js +0 -2
  3. package/dist/middleware/storeOwnership.js +3 -22
  4. package/dist/middleware/storeValidationMiddleware.js +39 -16
  5. package/dist/schemas/admin/admin-schema.d.ts +2 -2
  6. package/dist/schemas/ai-moderation/ai-moderation-schema.d.ts +2 -2
  7. package/dist/schemas/index.d.ts +0 -26
  8. package/dist/schemas/index.js +3 -121
  9. package/dist/schemas/store/storefront-config-schema.d.ts +1320 -0
  10. package/dist/schemas/store/storefront-config-schema.js +109 -0
  11. package/dist/utils/subdomain.d.ts +1 -1
  12. package/dist/utils/subdomain.js +15 -10
  13. package/package.json +1 -1
  14. package/src/index.ts +0 -3
  15. package/src/middleware/storeOwnership.ts +3 -21
  16. package/src/middleware/storeValidationMiddleware.ts +50 -17
  17. package/src/schemas/index.ts +5 -189
  18. package/src/utils/subdomain.ts +15 -11
  19. package/nul +0 -8
  20. package/src/schemas/compliance/compliance-schema.ts +0 -927
  21. package/src/schemas/compliance/kyc-schema.ts +0 -649
  22. package/src/schemas/customer/customer-schema.ts +0 -576
  23. package/src/schemas/inventory/inventory-tables.ts +0 -1927
  24. package/src/schemas/inventory/lot-tables.ts +0 -799
  25. package/src/schemas/order/order-schema.ts +0 -1400
  26. package/src/schemas/product/discount-relations.ts +0 -44
  27. package/src/schemas/product/discount-schema.ts +0 -464
  28. package/src/schemas/product/product-relations.ts +0 -187
  29. package/src/schemas/product/product-schema.ts +0 -955
  30. package/src/schemas/store/ethiopian_business_api.md.resolved +0 -212
  31. package/src/schemas/store/store-audit-schema.ts +0 -1257
  32. package/src/schemas/store/store-schema.ts +0 -661
  33. package/src/schemas/store/store-settings-schema.ts +0 -231
@@ -1,1927 +0,0 @@
1
- import { createId } from "@paralleldrive/cuid2";
2
- import {
3
- boolean,
4
- decimal,
5
- index,
6
- integer,
7
- jsonb,
8
- pgEnum,
9
- pgTable,
10
- text,
11
- timestamp,
12
- unique,
13
- varchar,
14
- } from "drizzle-orm/pg-core";
15
- import { z } from "zod";
16
- import {
17
- AuditTrailSchema,
18
- BusinessHoursSchema,
19
- ContactInfoSchema,
20
- CuidSchema,
21
- GeoLocationSchema,
22
- } from "../common/common-schemas";
23
-
24
- // =====================================================
25
- // ENUMS
26
- // =====================================================
27
-
28
- export const inventoryLocationTypeEnum = pgEnum("inventory_location_type", [
29
- "WAREHOUSE",
30
- "POS",
31
- ]);
32
- export const inventoryStatusEnum = pgEnum("inventory_status", [
33
- "IN_STOCK",
34
- "OUT_OF_STOCK",
35
- "RESERVED",
36
- "DAMAGED",
37
- "IN_TRANSIT",
38
- "QUARANTINED",
39
- "RETURNED",
40
- "EXPIRED",
41
- "LOST",
42
- "ADJUSTED",
43
- ]);
44
-
45
- export const damageTypeEnum = pgEnum("damage_type", [
46
- "PHYSICAL_DAMAGE",
47
- "WATER_DAMAGE",
48
- "FIRE_DAMAGE",
49
- "MANUFACTURING_DEFECT",
50
- "PACKAGING_DAMAGE",
51
- "EXPIRED",
52
- "CONTAMINATED",
53
- "MISSING_PARTS",
54
- "WRONG_ITEM",
55
- "CUSTOMER_RETURN_DAMAGED",
56
- "TRANSIT_DAMAGE",
57
- "STORAGE_DAMAGE",
58
- "THEFT_PARTIAL",
59
- "OBSOLETE",
60
- "OTHER",
61
- ]);
62
-
63
- export const damageSeverityEnum = pgEnum("damage_severity", [
64
- "MINOR",
65
- "MODERATE",
66
- "SEVERE",
67
- "COSMETIC",
68
- ]);
69
-
70
- export const movementTypeEnum = pgEnum("movement_type", [
71
- "PURCHASE_RECEIPT",
72
- "TRANSFER_IN",
73
- "RETURN_FROM_CUSTOMER",
74
- "PRODUCTION_COMPLETE",
75
- "ADJUSTMENT_INCREASE",
76
- "FOUND_INVENTORY",
77
- "SALE",
78
- "TRANSFER_OUT",
79
- "RETURN_TO_SUPPLIER",
80
- "DAMAGED_GOODS",
81
- "EXPIRED_GOODS",
82
- "THEFT_LOSS",
83
- "ADJUSTMENT_DECREASE",
84
- "WASTE",
85
- "SAMPLE",
86
- "PROMOTIONAL_USE",
87
- "LOCATION_TRANSFER",
88
- "ZONE_TRANSFER",
89
- "BIN_TRANSFER",
90
- "CYCLE_COUNT_ADJUSTMENT",
91
- "PHYSICAL_COUNT_ADJUSTMENT",
92
- "RESERVE",
93
- "UNRESERVE",
94
- "ALLOCATE",
95
- "DEALLOCATE",
96
- "MARK_DAMAGED",
97
- "REPAIR_DAMAGED",
98
- "DISPOSE_DAMAGED",
99
- "QUARANTINE",
100
- "RELEASE_QUARANTINE",
101
- "STOCK_RECONCILIATION",
102
- ]);
103
-
104
- export const movementStatusEnum = pgEnum("movement_status", [
105
- "DRAFT",
106
- "PENDING",
107
- "IN_PROGRESS",
108
- "COMPLETED",
109
- "CANCELLED",
110
- "FAILED",
111
- ]);
112
-
113
- export const warehouseStatusEnum = pgEnum("warehouse_status", [
114
- "ACTIVE",
115
- "INACTIVE",
116
- "CLOSED",
117
- ]);
118
- export const warehouseTypeEnum = pgEnum("warehouse_type", [
119
- "DISTRIBUTION_CENTER",
120
- "FULFILLMENT_CENTER",
121
- "COLD_STORAGE",
122
- "BULK_STORAGE",
123
- "CROSS_DOCK",
124
- "RETAIL_WAREHOUSE",
125
- "MANUFACTURING_WAREHOUSE",
126
- "3PL_WAREHOUSE",
127
- ]);
128
-
129
- // =====================================================
130
- // Zod Enums and Schemas (co-located for single-source-of-truth)
131
- // =====================================================
132
-
133
- export const POSLocationTypeEnum = z.enum([
134
- "RETAIL",
135
- "KIOSK",
136
- "POPUP",
137
- "OTHER",
138
- ]);
139
- export const POSLocationStatusEnum = z.enum(["ACTIVE", "INACTIVE", "CLOSED"]);
140
-
141
- export const WarehouseStatusEnum = z.enum(["ACTIVE", "INACTIVE", "CLOSED"]);
142
- export const WarehouseTypeEnum = z.enum([
143
- "DISTRIBUTION_CENTER",
144
- "FULFILLMENT_CENTER",
145
- "COLD_STORAGE",
146
- "BULK_STORAGE",
147
- "CROSS_DOCK",
148
- "RETAIL_WAREHOUSE",
149
- "MANUFACTURING_WAREHOUSE",
150
- "3PL_WAREHOUSE",
151
- ]);
152
-
153
- export const InventoryStatusEnum = z.enum([
154
- "IN_STOCK",
155
- "OUT_OF_STOCK",
156
- "RESERVED",
157
- "DAMAGED",
158
- "IN_TRANSIT",
159
- "QUARANTINED",
160
- "RETURNED",
161
- "EXPIRED",
162
- "LOST",
163
- "ADJUSTED",
164
- ]);
165
- export const LocationTypeEnum = z.enum(["WAREHOUSE", "POS"]);
166
-
167
- export const InventoryTransferStatusEnum = z.enum([
168
- "PENDING",
169
- "IN_TRANSIT",
170
- "COMPLETED",
171
- "CANCELLED",
172
- "FAILED",
173
- "PARTIAL",
174
- "RETURNED",
175
- ]);
176
- export const InventoryTransferTypeEnum = z.enum([
177
- "WAREHOUSE_TO_WAREHOUSE",
178
- "WAREHOUSE_TO_POS",
179
- "POS_TO_WAREHOUSE",
180
- "POS_TO_POS",
181
- "SUPPLIER_TO_WAREHOUSE",
182
- "WAREHOUSE_TO_CUSTOMER",
183
- "INTERNAL_TRANSFER",
184
- ]);
185
-
186
- export const PurchaseOrderStatusEnum = z.enum([
187
- "DRAFT",
188
- "SENT",
189
- "ACKNOWLEDGED",
190
- "APPROVED",
191
- "PENDING_APPROVAL",
192
- "PARTIALLY_RECEIVED",
193
- "RECEIVED",
194
- "COMPLETED",
195
- "CANCELLED",
196
- "DISPUTED",
197
- ]);
198
-
199
- export const SupplierStatusEnum = z.enum([
200
- "ACTIVE",
201
- "INACTIVE",
202
- "SUSPENDED",
203
- "UNDER_REVIEW",
204
- "PENDING_APPROVAL",
205
- "BLACKLISTED",
206
- ]);
207
- export const SupplierTypeEnum = z.enum([
208
- "MANUFACTURER",
209
- "DISTRIBUTOR",
210
- "WHOLESALER",
211
- "DROPSHIPPER",
212
- "SERVICE_PROVIDER",
213
- "LOCAL_VENDOR",
214
- "INTERNATIONAL_VENDOR",
215
- "BROKER",
216
- "IMPORTER",
217
- "EXPORTER",
218
- "RETAILER",
219
- "RESELLER",
220
- "CONTRACTOR",
221
- "CONSULTANT",
222
- "PARTS_SUPPLIER",
223
- "RAW_MATERIALS_SUPPLIER",
224
- "PACKAGING_SUPPLIER",
225
- "EQUIPMENT_SUPPLIER",
226
- "MAINTENANCE_SUPPLIER",
227
- "LOGISTICS_PROVIDER",
228
- "FREIGHT_FORWARDER",
229
- "CUSTOMS_BROKER",
230
- "TECHNOLOGY_VENDOR",
231
- "SOFTWARE_VENDOR",
232
- "HARDWARE_VENDOR",
233
- "OFFICE_SUPPLIES_VENDOR",
234
- "UTILITIES_PROVIDER",
235
- "CLEANING_SERVICES",
236
- "SECURITY_SERVICES",
237
- "MARKETING_SERVICES",
238
- "PROFESSIONAL_SERVICES",
239
- "TEMPORARY_STAFFING",
240
- "SPECIALIZED_SUPPLIER",
241
- "OTHER",
242
- ]);
243
- export const SupplierRatingEnum = z.enum([
244
- "EXCELLENT",
245
- "GOOD",
246
- "AVERAGE",
247
- "POOR",
248
- "UNRATED",
249
- ]);
250
-
251
- export const QualityStatusEnum = z.enum([
252
- "PENDING_INSPECTION",
253
- "PASSED",
254
- "FAILED",
255
- "CONDITIONALLY_PASSED",
256
- "QUARANTINED",
257
- "REJECTED",
258
- "REWORK_REQUIRED",
259
- "RELEASED",
260
- "HOLD",
261
- ]);
262
- export const InspectionTypeEnum = z.enum([
263
- "INCOMING_INSPECTION",
264
- "IN_PROCESS_INSPECTION",
265
- "OUTGOING_INSPECTION",
266
- "RANDOM_INSPECTION",
267
- "CUSTOMER_COMPLAINT_INSPECTION",
268
- "SUPPLIER_AUDIT",
269
- "PERIODIC_REVIEW",
270
- "EXPIRY_CHECK",
271
- "DAMAGE_ASSESSMENT",
272
- ]);
273
- export const QualityGradeEnum = z.enum(["A", "B", "C", "D", "F"]);
274
- export const DefectSeverityEnum = z.enum([
275
- "CRITICAL",
276
- "MAJOR",
277
- "MINOR",
278
- "COSMETIC",
279
- ]);
280
-
281
- // Zod schemas for key resources
282
- export const InventorySchema = z.object({
283
- id: CuidSchema,
284
- storeId: z.string(),
285
- productId: z.string(),
286
- variantId: z.string().optional(),
287
- sku: z.string(),
288
- barcode: z.string(),
289
- locationId: z.string(),
290
- locationType: LocationTypeEnum,
291
- quantity: z.number().int().nonnegative(),
292
- reserved: z.number().int().nonnegative().optional(),
293
- committed: z.number().int().nonnegative().optional(),
294
- unitCost: z.number().nonnegative().optional(),
295
- status: InventoryStatusEnum.default("IN_STOCK"),
296
- batchNumber: z.string().optional(),
297
- lotNumber: z.string().optional(),
298
- expiryDate: z.coerce.date().optional(),
299
- lowStockThreshold: z.number().int().nonnegative().optional(),
300
- criticalStockThreshold: z.number().int().nonnegative().optional(),
301
- available: z.number().int().nonnegative().default(0),
302
- notes: z.string().optional(),
303
- metadata: z.record(z.any()).optional(),
304
- version: z.number().int().default(1),
305
- isActive: z.boolean().default(true),
306
- createdAt: z.date(),
307
- updatedAt: z.date(),
308
- createdBy: z.string().optional(),
309
- updatedBy: z.string().optional(),
310
- });
311
-
312
- export const InventoryMovementSchema = z
313
- .object({
314
- id: CuidSchema,
315
- storeId: z.string(),
316
- movementNumber: z.string(),
317
- movementType: z.enum([
318
- "PURCHASE_RECEIPT",
319
- "TRANSFER_IN",
320
- "RETURN_FROM_CUSTOMER",
321
- "PRODUCTION_COMPLETE",
322
- "ADJUSTMENT_INCREASE",
323
- "FOUND_INVENTORY",
324
- "SALE",
325
- "TRANSFER_OUT",
326
- "RETURN_TO_SUPPLIER",
327
- "DAMAGED_GOODS",
328
- "EXPIRED_GOODS",
329
- "THEFT_LOSS",
330
- "ADJUSTMENT_DECREASE",
331
- "WASTE",
332
- "SAMPLE",
333
- "PROMOTIONAL_USE",
334
- "LOCATION_TRANSFER",
335
- "ZONE_TRANSFER",
336
- "BIN_TRANSFER",
337
- "CYCLE_COUNT_ADJUSTMENT",
338
- "PHYSICAL_COUNT_ADJUSTMENT",
339
- "RESERVE",
340
- "UNRESERVE",
341
- "ALLOCATE",
342
- "DEALLOCATE",
343
- ]),
344
- status: z.enum([
345
- "DRAFT",
346
- "PENDING",
347
- "IN_PROGRESS",
348
- "COMPLETED",
349
- "CANCELLED",
350
- "FAILED",
351
- ]),
352
- productId: z.string(),
353
- variantId: z.string().optional(),
354
- sku: z.string(),
355
- quantityMoved: z.number(),
356
- fromLocationId: z.string().optional(),
357
- toLocationId: z.string().optional(),
358
- unitCost: z.number().optional(),
359
- reason: z.string().optional(),
360
- movementDate: z.coerce.date(),
361
- createdAt: z.date(),
362
- updatedAt: z.date(),
363
- })
364
- .catchall(z.any());
365
-
366
- export const InventoryTransferSchema = z
367
- .object({ id: CuidSchema })
368
- .catchall(z.any());
369
- export const QualityControlSchema = z
370
- .object({
371
- id: CuidSchema,
372
- qcNumber: z.string(),
373
- inspectedBy: z.string(),
374
- inspectionDate: z.date(),
375
- createdAt: z.date(),
376
- updatedAt: z.date(),
377
- })
378
- .catchall(z.any());
379
- export const QualityTemplateSchema = z
380
- .object({
381
- id: CuidSchema,
382
- createdAt: z.date(),
383
- updatedAt: z.date(),
384
- createdBy: z.string().optional(),
385
- updatedBy: z.string().optional(),
386
- })
387
- .catchall(z.any());
388
- export const SupplierQualityRatingSchema = z
389
- .object({
390
- id: CuidSchema,
391
- reviewedBy: z.string().optional(),
392
- reviewedAt: z.date().optional(),
393
- createdAt: z.date(),
394
- updatedAt: z.date(),
395
- })
396
- .catchall(z.any());
397
-
398
- export const POSLocationSchema = z.object({
399
- id: CuidSchema,
400
- storeId: z.string(),
401
- code: z.string(),
402
- name: z.string(),
403
- displayName: z.string().optional(),
404
- type: POSLocationTypeEnum,
405
- posType: POSLocationTypeEnum.optional(),
406
- status: POSLocationStatusEnum,
407
- geoLocation: GeoLocationSchema,
408
- address: z
409
- .object({
410
- street: z.string().optional(),
411
- line1: z.string().optional(),
412
- line2: z.string().optional(),
413
- city: z.string(),
414
- state: z.string(),
415
- postalCode: z.string(),
416
- country: z.string(),
417
- coordinates: z.object({ lat: z.number(), lng: z.number() }).optional(),
418
- })
419
- .optional(),
420
- timezone: z.string().default("UTC"),
421
- primaryContact: ContactInfoSchema.optional(),
422
- managementContacts: z.array(ContactInfoSchema).optional(),
423
- emergencyContact: ContactInfoSchema.optional(),
424
- businessHours: BusinessHoursSchema.optional(),
425
- posSystemInfo: z
426
- .object({
427
- systemName: z.string().optional(),
428
- version: z.string().optional(),
429
- lastSync: z.coerce.date().optional(),
430
- supportedPaymentMethods: z.array(z.string()).optional(),
431
- isActive: z.boolean().default(true),
432
- })
433
- .optional(),
434
- allowBackorders: z.boolean().default(false).optional(),
435
- autoFulfillment: z.boolean().default(true).optional(),
436
- supportedFeatures: z
437
- .array(
438
- z.enum([
439
- "CASH_PAYMENT",
440
- "CARD_PAYMENT",
441
- "MOBILE_PAYMENT",
442
- "GIFT_CARDS",
443
- "LAYAWAY",
444
- "RETURNS_EXCHANGES",
445
- "PRODUCT_LOOKUP",
446
- "INVENTORY_CHECK",
447
- "CUSTOMER_ORDERS",
448
- "RESERVATIONS",
449
- "LOYALTY_PROGRAM",
450
- "PROMOTIONS",
451
- "TAX_CALCULATION",
452
- "RECEIPT_PRINTING",
453
- "EMAIL_RECEIPTS",
454
- "BARCODE_SCANNING",
455
- "PRICE_CHECKING",
456
- ]),
457
- )
458
- .optional(),
459
- hardware: z
460
- .array(
461
- z.object({
462
- id: z.string(),
463
- type: z.enum([
464
- "POS_TERMINAL",
465
- "CASH_REGISTER",
466
- "BARCODE_SCANNER",
467
- "RECEIPT_PRINTER",
468
- "CARD_READER",
469
- "SCALE",
470
- "SECURITY_CAMERA",
471
- "CASH_DRAWER",
472
- "DISPLAY_MONITOR",
473
- "TABLET",
474
- ]),
475
- brand: z.string().optional(),
476
- model: z.string().optional(),
477
- serialNumber: z.string().optional(),
478
- status: z.enum(["ACTIVE", "MAINTENANCE", "INACTIVE"]),
479
- lastMaintenance: z.coerce.date().optional(),
480
- }),
481
- )
482
- .optional(),
483
- inventorySettings: z
484
- .object({
485
- allowNegativeInventory: z.boolean().default(false),
486
- autoReorderEnabled: z.boolean().default(false),
487
- lowStockWarningEnabled: z.boolean().default(true),
488
- stockCountRequired: z.boolean().default(false),
489
- barcodeRequired: z.boolean().default(false),
490
- })
491
- .optional(),
492
- salesSettings: z
493
- .object({
494
- taxRate: z.number().min(0).max(100).optional(),
495
- taxExemptAvailable: z.boolean().default(false),
496
- discountingEnabled: z.boolean().default(true),
497
- maxDiscountPercent: z.number().min(0).max(100).optional(),
498
- returnsEnabled: z.boolean().default(true),
499
- returnDayLimit: z.number().int().nonnegative().optional(),
500
- receiptRequired: z.boolean().default(true),
501
- })
502
- .optional(),
503
- customerServices: z
504
- .array(
505
- z.enum([
506
- "PERSONAL_SHOPPING",
507
- "ALTERATIONS",
508
- "GIFT_WRAPPING",
509
- "DELIVERY",
510
- "INSTALLATION",
511
- "REPAIR_SERVICE",
512
- "CONSULTATION",
513
- "TRAINING",
514
- "RENTAL",
515
- "CUSTOM_ORDERS",
516
- ]),
517
- )
518
- .optional(),
519
- operationalCosts: z
520
- .object({
521
- monthlyRent: z.number().nonnegative().optional(),
522
- utilities: z.number().nonnegative().optional(),
523
- labor: z.number().nonnegative().optional(),
524
- maintenance: z.number().nonnegative().optional(),
525
- insurance: z.number().nonnegative().optional(),
526
- currency: z.string().length(3).default("USD"),
527
- })
528
- .optional(),
529
- securityFeatures: z.array(z.string()).optional(),
530
- complianceRequirements: z.array(z.string()).optional(),
531
- lastSecurityAudit: z.coerce.date().optional(),
532
- description: z.string().optional(),
533
- notes: z.string().optional(),
534
- internalNotes: z.string().optional(),
535
- metadata: z.record(z.any()).optional(),
536
- customAttributes: z.record(z.any()).optional(),
537
- version: z.number().int().default(1),
538
- isActive: z.boolean().default(true),
539
- createdAt: z.date(),
540
- updatedAt: z.date(),
541
- createdBy: z.string().optional(),
542
- updatedBy: z.string().optional(),
543
- auditTrail: z.array(AuditTrailSchema).optional(),
544
- });
545
-
546
- export const WarehouseSchema = z.object({
547
- id: CuidSchema,
548
- storeId: z.string(),
549
- code: z.string(),
550
- name: z.string(),
551
- displayName: z.string().optional(),
552
- type: WarehouseTypeEnum,
553
- status: WarehouseStatusEnum,
554
- address: z
555
- .object({
556
- street: z.string(),
557
- city: z.string(),
558
- state: z.string(),
559
- postalCode: z.string(),
560
- country: z.string(),
561
- coordinates: z.object({ lat: z.number(), lng: z.number() }).optional(),
562
- })
563
- .optional(),
564
- timezone: z.string().default("UTC"),
565
- primaryContact: z
566
- .object({ name: z.string(), email: z.string(), phone: z.string() })
567
- .optional(),
568
- totalArea: z.number().nonnegative().optional(),
569
- storageArea: z.number().nonnegative().optional(),
570
- ceilingHeight: z.number().nonnegative().optional(),
571
- capacity: z
572
- .object({
573
- volumetric: z.number().nonnegative().optional(),
574
- weight: z.number().nonnegative().optional(),
575
- palletPositions: z.number().int().nonnegative().optional(),
576
- pickingLocations: z.number().int().nonnegative().optional(),
577
- unit: z.string().optional(),
578
- })
579
- .optional(),
580
- zones: z
581
- .array(
582
- z.object({
583
- id: z.string(),
584
- code: z.string(),
585
- name: z.string(),
586
- type: z.string(),
587
- description: z.string().optional(),
588
- capacity: z.number().nonnegative().optional(),
589
- temperature: z
590
- .object({ min: z.number(), max: z.number(), unit: z.string() })
591
- .optional(),
592
- humidity: z
593
- .object({
594
- min: z.number().min(0).max(100),
595
- max: z.number().min(0).max(100),
596
- })
597
- .optional(),
598
- binLocations: z
599
- .array(
600
- z.object({
601
- id: z.string(),
602
- code: z.string(),
603
- row: z.string().optional(),
604
- bay: z.string().optional(),
605
- level: z.string().optional(),
606
- capacity: z.number().nonnegative().optional(),
607
- isActive: z.boolean().default(true),
608
- }),
609
- )
610
- .optional(),
611
- isActive: z.boolean().default(true),
612
- }),
613
- )
614
- .optional(),
615
- description: z.string().optional(),
616
- notes: z.string().optional(),
617
- internalNotes: z.string().optional(),
618
- metadata: z.record(z.any()).optional(),
619
- version: z.number().int().default(1),
620
- isActive: z.boolean().default(true),
621
- createdAt: z.date(),
622
- updatedAt: z.date(),
623
- createdBy: z.string().optional(),
624
- updatedBy: z.string().optional(),
625
- auditTrail: z.array(AuditTrailSchema).optional(),
626
- });
627
-
628
- // =====================================================
629
- // INVENTORY TABLE
630
- // =====================================================
631
-
632
- export const inventory = pgTable(
633
- "inventory",
634
- {
635
- id: text("id")
636
- .primaryKey()
637
- .$defaultFn(() => createId()),
638
- storeId: text("store_id").notNull(),
639
- productId: text("product_id").notNull(),
640
- variantId: text("variant_id"),
641
- sku: varchar("sku", { length: 255 }).notNull(),
642
- barcode: varchar("barcode", { length: 255 }).notNull(),
643
- locationId: text("location_id").notNull(),
644
- locationType: inventoryLocationTypeEnum("location_type").notNull(),
645
-
646
- // Zone and Bin Information
647
- zoneId: text("zone_id"),
648
- binLocation: varchar("bin_location", { length: 100 }),
649
-
650
- // Batch and Serial Tracking
651
- batchNumber: varchar("batch_number", { length: 255 }),
652
- lotNumber: varchar("lot_number", { length: 255 }),
653
- serialNumbers: jsonb("serial_numbers").$type<string[]>(),
654
-
655
- // Quantity Management
656
- quantity: integer("quantity").notNull().default(0),
657
- reserved: integer("reserved").notNull().default(0),
658
- available: integer("available").notNull().default(0),
659
- committed: integer("committed").notNull().default(0),
660
- inTransit: integer("in_transit").notNull().default(0),
661
- onOrder: integer("on_order").notNull().default(0),
662
-
663
- // Stock Level Management
664
- reorderPoint: integer("reorder_point"),
665
- maxStockLevel: integer("max_stock_level"),
666
- safetyStock: integer("safety_stock").notNull().default(0),
667
-
668
- // Unit of Measure
669
- baseUnitId: text("base_unit_id").notNull(),
670
- unitOfMeasure: varchar("unit_of_measure", { length: 50 })
671
- .notNull()
672
- .default("EACH"),
673
-
674
- // Cost Information
675
- unitCost: decimal("unit_cost", { precision: 12, scale: 4 }),
676
- averageCost: decimal("average_cost", { precision: 12, scale: 4 }),
677
- lastCost: decimal("last_cost", { precision: 12, scale: 4 }),
678
- standardCost: decimal("standard_cost", { precision: 12, scale: 4 }),
679
- costingMethod: varchar("costing_method", { length: 20 }),
680
-
681
- // Status and Condition
682
- status: inventoryStatusEnum("status").notNull().default("IN_STOCK"),
683
- condition: varchar("condition", { length: 100 }),
684
- qualityGrade: varchar("quality_grade", { length: 50 }),
685
-
686
- // Date Information
687
- expiryDate: timestamp("expiry_date", { withTimezone: true }),
688
- manufactureDate: timestamp("manufacture_date", { withTimezone: true }),
689
- receivedDate: timestamp("received_date", { withTimezone: true }),
690
- lastCountedAt: timestamp("last_counted_at", { withTimezone: true }),
691
- lastMovementDate: timestamp("last_movement_date", { withTimezone: true }),
692
-
693
- // Supplier Information
694
- supplierId: text("supplier_id"),
695
- supplierSku: varchar("supplier_sku", { length: 255 }),
696
-
697
- // Alert Thresholds
698
- lowStockThreshold: integer("low_stock_threshold"),
699
- criticalStockThreshold: integer("critical_stock_threshold"),
700
- expiryWarningDays: integer("expiry_warning_days").notNull().default(30),
701
-
702
- // Tracking Configuration
703
- trackSerial: boolean("track_serial").notNull().default(false),
704
- trackBatch: boolean("track_batch").notNull().default(false),
705
- trackExpiry: boolean("track_expiry").notNull().default(false),
706
-
707
- // Damaged Stock Tracking
708
- damagedQuantity: integer("damaged_quantity").notNull().default(0),
709
- damageType: damageTypeEnum("damage_type"),
710
- damageSeverity: damageSeverityEnum("damage_severity"),
711
- damageReason: text("damage_reason"),
712
- damageValue: decimal("damage_value", { precision: 12, scale: 4 }),
713
- damageDate: timestamp("damage_date", { withTimezone: true }),
714
- damageReportedBy: text("damage_reported_by"),
715
- damageNotes: text("damage_notes"),
716
- isRepairable: boolean("is_repairable").notNull().default(false),
717
- repairCost: decimal("repair_cost", { precision: 12, scale: 4 }),
718
- disposalDate: timestamp("disposal_date", { withTimezone: true }),
719
- disposalMethod: varchar("disposal_method", { length: 100 }),
720
- insuranceClaim: jsonb("insurance_claim").$type<{
721
- claimNumber?: string;
722
- amount?: number;
723
- status?: string;
724
- filedDate?: string;
725
- resolvedDate?: string;
726
- notes?: string;
727
- }>(),
728
-
729
- // Quality Tracking
730
- qualityScore: integer("quality_score"),
731
- lastQualityCheck: timestamp("last_quality_check", { withTimezone: true }),
732
-
733
- // Quarantine Tracking
734
- quarantinedQuantity: integer("quarantined_quantity").notNull().default(0),
735
- quarantineReason: text("quarantine_reason"),
736
- quarantineDate: timestamp("quarantine_date", { withTimezone: true }),
737
- quarantineReleaseDate: timestamp("quarantine_release_date", { withTimezone: true }),
738
-
739
- // Multi-location Tracking
740
- isVirtualLocation: boolean("is_virtual_location").notNull().default(false),
741
- parentInventoryId: text("parent_inventory_id"),
742
-
743
- // ABC Classification
744
- abcClassification: varchar("abc_classification", { length: 1 }),
745
-
746
- // Notes and Metadata
747
- notes: text("notes"),
748
- internalNotes: text("internal_notes"),
749
- metadata: jsonb("metadata").$type<Record<string, any>>().default({}),
750
- customAttributes: jsonb("custom_attributes")
751
- .$type<Record<string, any>>()
752
- .default({}),
753
-
754
- // Version Control
755
- version: integer("version").notNull().default(1),
756
- isActive: boolean("is_active").notNull().default(true),
757
-
758
- // Timestamps
759
- createdAt: timestamp("created_at", { withTimezone: true })
760
- .defaultNow()
761
- .notNull(),
762
- updatedAt: timestamp("updated_at", { withTimezone: true })
763
- .defaultNow()
764
- .notNull(),
765
- createdBy: text("created_by"),
766
- updatedBy: text("updated_by"),
767
- },
768
- (table) => ({
769
- // Performance indexes
770
- storeIdIndex: index("idx_inventory_store_id").on(table.storeId),
771
- productIdIndex: index("idx_inventory_product_id").on(table.productId),
772
- locationIdIndex: index("idx_inventory_location_id").on(table.locationId),
773
- skuIndex: index("idx_inventory_sku").on(table.sku),
774
- barcodeIndex: index("idx_inventory_barcode").on(table.barcode),
775
- statusIndex: index("idx_inventory_status").on(table.status),
776
-
777
- // Unique constraints
778
- uniqueProductLocation: unique("idx_inventory_product_location_unique").on(
779
- table.storeId,
780
- table.productId,
781
- table.locationId,
782
- table.variantId,
783
- ),
784
- uniqueSkuBarcode: unique("idx_inventory_sku_barcode_unique").on(
785
- table.storeId,
786
- table.locationId,
787
- table.sku,
788
- table.barcode,
789
- ),
790
-
791
- // Quantity and alerts indexes
792
- quantityIndex: index("idx_inventory_quantity").on(table.quantity),
793
- lowStockIndex: index("idx_inventory_low_stock").on(table.lowStockThreshold),
794
- expiryIndex: index("idx_inventory_expiry").on(table.expiryDate),
795
- }),
796
- );
797
-
798
- // =====================================================
799
- // INVENTORY MOVEMENTS TABLE
800
- // =====================================================
801
-
802
- export const inventoryMovements = pgTable(
803
- "inventory_movements",
804
- {
805
- id: text("id")
806
- .primaryKey()
807
- .$defaultFn(() => createId()),
808
- storeId: text("store_id").notNull(),
809
- movementNumber: varchar("movement_number", { length: 100 }).notNull(),
810
-
811
- // Movement Classification
812
- movementType: movementTypeEnum("movement_type").notNull(),
813
- reason: varchar("reason", { length: 255 }),
814
- status: movementStatusEnum("status").notNull().default("DRAFT"),
815
-
816
- // Product Information
817
- productId: text("product_id").notNull(),
818
- variantId: text("variant_id"),
819
- sku: varchar("sku", { length: 255 }).notNull(),
820
- productName: varchar("product_name", { length: 255 }),
821
-
822
- // Location Information
823
- fromLocationId: text("from_location_id"),
824
- fromLocationType: varchar("from_location_type", { length: 50 }),
825
- fromZoneId: text("from_zone_id"),
826
- fromBinLocation: varchar("from_bin_location", { length: 100 }),
827
-
828
- toLocationId: text("to_location_id"),
829
- toLocationType: varchar("to_location_type", { length: 50 }),
830
- toZoneId: text("to_zone_id"),
831
- toBinLocation: varchar("to_bin_location", { length: 100 }),
832
-
833
- // Quantity Information
834
- quantityMoved: integer("quantity_moved").notNull(),
835
- unitOfMeasure: varchar("unit_of_measure", { length: 50 })
836
- .notNull()
837
- .default("EACH"),
838
-
839
- // Batch and Serial Tracking
840
- batchNumber: varchar("batch_number", { length: 255 }),
841
- lotNumber: varchar("lot_number", { length: 255 }),
842
- serialNumbers: jsonb("serial_numbers").$type<string[]>(),
843
- expiryDate: timestamp("expiry_date", { withTimezone: true }),
844
- manufacturingDate: timestamp("manufacturing_date", { withTimezone: true }),
845
-
846
- // Cost Information
847
- unitCost: decimal("unit_cost", { precision: 12, scale: 4 }),
848
- totalCost: decimal("total_cost", { precision: 12, scale: 4 }),
849
- costingMethod: varchar("costing_method", { length: 20 }),
850
-
851
- // Reference Information
852
- referenceType: varchar("reference_type", { length: 50 }),
853
- referenceId: text("reference_id"),
854
- referenceNumber: varchar("reference_number", { length: 100 }),
855
-
856
- // Quality and Condition
857
- conditionBefore: varchar("condition_before", { length: 100 }),
858
- conditionAfter: varchar("condition_after", { length: 100 }),
859
- qualityGrade: varchar("quality_grade", { length: 50 }),
860
-
861
- // Date Information
862
- movementDate: timestamp("movement_date", { withTimezone: true }).notNull(),
863
- scheduledDate: timestamp("scheduled_date", { withTimezone: true }),
864
- completedDate: timestamp("completed_date", { withTimezone: true }),
865
-
866
- // Processing Information
867
- processedBy: text("processed_by"),
868
- approvedBy: text("approved_by"),
869
- approvedAt: timestamp("approved_at", { withTimezone: true }),
870
-
871
- // Notes
872
- notes: text("notes"),
873
- internalNotes: text("internal_notes"),
874
-
875
- // Timestamps
876
- createdAt: timestamp("created_at", { withTimezone: true })
877
- .defaultNow()
878
- .notNull(),
879
- updatedAt: timestamp("updated_at", { withTimezone: true })
880
- .defaultNow()
881
- .notNull(),
882
- createdBy: text("created_by"),
883
- updatedBy: text("updated_by"),
884
- },
885
- (table) => ({
886
- // Performance indexes
887
- storeIdIndex: index("idx_movements_store_id").on(table.storeId),
888
- productIdIndex: index("idx_movements_product_id").on(table.productId),
889
- movementTypeIndex: index("idx_movements_type").on(table.movementType),
890
- statusIndex: index("idx_movements_status").on(table.status),
891
- movementDateIndex: index("idx_movements_date").on(table.movementDate),
892
-
893
- // Unique movement number per store
894
- uniqueMovementNumber: unique("idx_movements_number_unique").on(
895
- table.storeId,
896
- table.movementNumber,
897
- ),
898
- }),
899
- );
900
-
901
- // =====================================================
902
- // WAREHOUSES TABLE
903
- // =====================================================
904
-
905
- export const warehouses = pgTable(
906
- "warehouses",
907
- {
908
- id: text("id")
909
- .primaryKey()
910
- .$defaultFn(() => createId()),
911
- storeId: text("store_id").notNull(),
912
- code: varchar("code", { length: 100 }).notNull(),
913
- name: varchar("name", { length: 255 }).notNull(),
914
- displayName: varchar("display_name", { length: 255 }),
915
- type: warehouseTypeEnum("type").notNull(),
916
- status: warehouseStatusEnum("status").notNull().default("ACTIVE"),
917
-
918
- // Location Information
919
- address: jsonb("address").$type<{
920
- street: string;
921
- city: string;
922
- state: string;
923
- postalCode: string;
924
- country: string;
925
- coordinates?: { lat: number; lng: number };
926
- }>(),
927
- timezone: varchar("timezone", { length: 50 }).notNull().default("UTC"),
928
-
929
- // Contact Information
930
- primaryContact: jsonb("primary_contact").$type<{
931
- name: string;
932
- email: string;
933
- phone: string;
934
- }>(),
935
-
936
- // Physical Characteristics
937
- totalArea: decimal("total_area", { precision: 10, scale: 2 }),
938
- storageArea: decimal("storage_area", { precision: 10, scale: 2 }),
939
- ceilingHeight: decimal("ceiling_height", { precision: 8, scale: 2 }),
940
- numberOfDocks: integer("number_of_docks"),
941
-
942
- // Capacity Management
943
- capacity: jsonb("capacity").$type<{
944
- volumetric?: number;
945
- weight?: number;
946
- palletPositions?: number;
947
- pickingLocations?: number;
948
- unit?: string;
949
- }>(),
950
-
951
- // Zone Configuration
952
- zones: jsonb("zones")
953
- .$type<
954
- Array<{
955
- id: string;
956
- code: string;
957
- name: string;
958
- type: string;
959
- description?: string;
960
- capacity?: number;
961
- temperature?: { min: number; max: number; unit: string };
962
- humidity?: { min: number; max: number };
963
- isActive: boolean;
964
- }>
965
- >()
966
- .default([]),
967
-
968
- // Notes and Metadata
969
- description: text("description"),
970
- notes: text("notes"),
971
- internalNotes: text("internal_notes"),
972
- metadata: jsonb("metadata").$type<Record<string, any>>().default({}),
973
-
974
- // Version Control
975
- version: integer("version").notNull().default(1),
976
- isActive: boolean("is_active").notNull().default(true),
977
-
978
- // Timestamps
979
- createdAt: timestamp("created_at", { withTimezone: true })
980
- .defaultNow()
981
- .notNull(),
982
- updatedAt: timestamp("updated_at", { withTimezone: true })
983
- .defaultNow()
984
- .notNull(),
985
- createdBy: text("created_by"),
986
- updatedBy: text("updated_by"),
987
- },
988
- (table) => ({
989
- // Performance indexes
990
- storeIdIndex: index("idx_warehouses_store_id").on(table.storeId),
991
- statusIndex: index("idx_warehouses_status").on(table.status),
992
- typeIndex: index("idx_warehouses_type").on(table.type),
993
-
994
- // Unique constraints
995
- uniqueCodePerStore: unique("idx_warehouses_code_unique").on(
996
- table.storeId,
997
- table.code,
998
- ),
999
- }),
1000
- );
1001
-
1002
- // =====================================================
1003
- // POS LOCATIONS TABLE
1004
- // =====================================================
1005
-
1006
- export const posLocations = pgTable(
1007
- "pos_locations",
1008
- {
1009
- id: text("id")
1010
- .primaryKey()
1011
- .$defaultFn(() => createId()),
1012
- storeId: text("store_id").notNull(),
1013
- code: varchar("code", { length: 100 }).notNull(),
1014
- name: varchar("name", { length: 255 }).notNull(),
1015
- displayName: varchar("display_name", { length: 255 }),
1016
- status: varchar("status", { length: 20 }).notNull().default("ACTIVE"),
1017
-
1018
- // Location Information
1019
- // Keep simple address for backward compatibility
1020
- address: jsonb("address").$type<{
1021
- street: string;
1022
- city: string;
1023
- state: string;
1024
- postalCode: string;
1025
- country: string;
1026
- coordinates?: { lat: number; lng: number };
1027
- }>(),
1028
- // Advanced geo location object
1029
- geoLocation: jsonb("geo_location").$type<{
1030
- lat: number;
1031
- lng: number;
1032
- address?: {
1033
- line1: string;
1034
- line2?: string;
1035
- city: string;
1036
- state: string;
1037
- postalCode: string;
1038
- country: string;
1039
- };
1040
- }>(),
1041
- timezone: varchar("timezone", { length: 50 }).notNull().default("UTC"),
1042
-
1043
- // Contact Information
1044
- primaryContact: jsonb("primary_contact").$type<{
1045
- name?: string;
1046
- email?: string;
1047
- phone?: string;
1048
- alternatePhone?: string;
1049
- }>(),
1050
- managementContacts: jsonb("management_contacts").$type<
1051
- Array<{
1052
- name?: string;
1053
- email?: string;
1054
- phone?: string;
1055
- alternatePhone?: string;
1056
- }>
1057
- >(),
1058
- emergencyContact: jsonb("emergency_contact").$type<{
1059
- name?: string;
1060
- email?: string;
1061
- phone?: string;
1062
- }>(),
1063
-
1064
- // Business Hours
1065
- businessHours: jsonb("business_hours").$type<{
1066
- timezone?: string;
1067
- monday?: { open: string; close: string; closed?: boolean };
1068
- tuesday?: { open: string; close: string; closed?: boolean };
1069
- wednesday?: { open: string; close: string; closed?: boolean };
1070
- thursday?: { open: string; close: string; closed?: boolean };
1071
- friday?: { open: string; close: string; closed?: boolean };
1072
- saturday?: { open: string; close: string; closed?: boolean };
1073
- sunday?: { open: string; close: string; closed?: boolean };
1074
- holidays?: Array<{ date: string; name: string; closed?: boolean }>;
1075
- }>(),
1076
-
1077
- // Physical Characteristics
1078
- floorArea: decimal("floor_area", { precision: 10, scale: 2 }),
1079
- storageArea: decimal("storage_area", { precision: 10, scale: 2 }),
1080
- customerArea: decimal("customer_area", { precision: 10, scale: 2 }),
1081
- numberOfRegister: integer("number_of_register"),
1082
- parkingSpaces: integer("parking_spaces"),
1083
-
1084
- // POS Configuration
1085
- posType: varchar("pos_type", { length: 50 }).notNull().default("RETAIL"),
1086
- allowBackorders: boolean("allow_backorders").notNull().default(false),
1087
- autoFulfillment: boolean("auto_fulfillment").notNull().default(true),
1088
-
1089
- // Equipment and Technology
1090
- posSystemInfo: jsonb("pos_system_info").$type<{
1091
- systemName?: string;
1092
- version?: string;
1093
- lastSync?: Date;
1094
- supportedPaymentMethods?: string[];
1095
- isActive?: boolean;
1096
- }>(),
1097
- supportedFeatures: jsonb("supported_features").$type<string[]>(),
1098
- hardware:
1099
- jsonb("hardware").$type<
1100
- Array<{
1101
- id: string;
1102
- type:
1103
- | "POS_TERMINAL"
1104
- | "CASH_REGISTER"
1105
- | "BARCODE_SCANNER"
1106
- | "RECEIPT_PRINTER"
1107
- | "CARD_READER"
1108
- | "SCALE"
1109
- | "SECURITY_CAMERA"
1110
- | "CASH_DRAWER"
1111
- | "DISPLAY_MONITOR"
1112
- | "TABLET";
1113
- brand?: string;
1114
- model?: string;
1115
- serialNumber?: string;
1116
- status: "ACTIVE" | "MAINTENANCE" | "INACTIVE";
1117
- lastMaintenance?: Date;
1118
- }>
1119
- >(),
1120
-
1121
- // Inventory & Sales Configuration
1122
- inventorySettings: jsonb("inventory_settings").$type<{
1123
- allowNegativeInventory?: boolean;
1124
- autoReorderEnabled?: boolean;
1125
- lowStockWarningEnabled?: boolean;
1126
- stockCountRequired?: boolean;
1127
- barcodeRequired?: boolean;
1128
- }>(),
1129
- salesSettings: jsonb("sales_settings").$type<{
1130
- taxRate?: number;
1131
- taxExemptAvailable?: boolean;
1132
- discountingEnabled?: boolean;
1133
- maxDiscountPercent?: number;
1134
- returnsEnabled?: boolean;
1135
- returnDayLimit?: number;
1136
- receiptRequired?: boolean;
1137
- }>(),
1138
-
1139
- // Customer Services
1140
- customerServices: jsonb("customer_services").$type<string[]>(),
1141
-
1142
- // Financial Information
1143
- operationalCosts: jsonb("operational_costs").$type<{
1144
- monthlyRent?: number;
1145
- utilities?: number;
1146
- labor?: number;
1147
- maintenance?: number;
1148
- insurance?: number;
1149
- currency?: string;
1150
- }>(),
1151
-
1152
- // Security and Compliance
1153
- securityFeatures: jsonb("security_features").$type<string[]>(),
1154
- complianceRequirements: jsonb("compliance_requirements").$type<string[]>(),
1155
- lastSecurityAudit: timestamp("last_security_audit", { withTimezone: true }),
1156
-
1157
- // Notes and Metadata
1158
- description: text("description"),
1159
- notes: text("notes"),
1160
- internalNotes: text("internal_notes"),
1161
- metadata: jsonb("metadata").$type<Record<string, any>>().default({}),
1162
- customAttributes: jsonb("custom_attributes")
1163
- .$type<Record<string, any>>()
1164
- .default({}),
1165
-
1166
- // Version Control
1167
- version: integer("version").notNull().default(1),
1168
- isActive: boolean("is_active").notNull().default(true),
1169
-
1170
- // Timestamps & Audit
1171
- createdAt: timestamp("created_at", { withTimezone: true })
1172
- .defaultNow()
1173
- .notNull(),
1174
- updatedAt: timestamp("updated_at", { withTimezone: true })
1175
- .defaultNow()
1176
- .notNull(),
1177
- createdBy: text("created_by"),
1178
- updatedBy: text("updated_by"),
1179
- auditTrail: jsonb("audit_trail").$type<Array<Record<string, any>>>(),
1180
- },
1181
- (table) => ({
1182
- // Performance indexes
1183
- storeIdIndex: index("idx_pos_locations_store_id").on(table.storeId),
1184
- statusIndex: index("idx_pos_locations_status").on(table.status),
1185
- posTypeIndex: index("idx_pos_locations_pos_type").on(table.posType),
1186
-
1187
- // Unique constraints
1188
- uniqueCodePerStore: unique("idx_pos_locations_code_unique").on(
1189
- table.storeId,
1190
- table.code,
1191
- ),
1192
- }),
1193
- );
1194
-
1195
- // =====================================================
1196
- // INVENTORY TRANSFERS TABLE
1197
- // =====================================================
1198
-
1199
- export const inventoryTransferStatusEnum = pgEnum("inventory_transfer_status", [
1200
- "PENDING",
1201
- "IN_TRANSIT",
1202
- "COMPLETED",
1203
- "CANCELLED",
1204
- "FAILED",
1205
- "PARTIAL",
1206
- "RETURNED",
1207
- ]);
1208
-
1209
- export const inventoryTransferTypeEnum = pgEnum("inventory_transfer_type", [
1210
- "WAREHOUSE_TO_WAREHOUSE",
1211
- "WAREHOUSE_TO_POS",
1212
- "POS_TO_WAREHOUSE",
1213
- "POS_TO_POS",
1214
- "SUPPLIER_TO_WAREHOUSE",
1215
- "WAREHOUSE_TO_CUSTOMER",
1216
- "INTERNAL_TRANSFER",
1217
- ]);
1218
-
1219
- export const inventoryTransfers = pgTable(
1220
- "inventory_transfers",
1221
- {
1222
- id: text("id")
1223
- .primaryKey()
1224
- .$defaultFn(() => createId()),
1225
- storeId: text("store_id").notNull(),
1226
- transferNumber: varchar("transfer_number", { length: 100 }).notNull(),
1227
-
1228
- // Location Information
1229
- fromLocationId: text("from_location_id").notNull(),
1230
- fromLocationType: varchar("from_location_type", { length: 50 }).notNull(),
1231
- toLocationId: text("to_location_id").notNull(),
1232
- toLocationType: varchar("to_location_type", { length: 50 }).notNull(),
1233
-
1234
- // Transfer Details
1235
- status: inventoryTransferStatusEnum("status").notNull().default("PENDING"),
1236
- transferType: inventoryTransferTypeEnum("transfer_type").notNull(),
1237
- priority: varchar("priority", { length: 20 }).notNull().default("NORMAL"),
1238
-
1239
- // Shipping and Tracking
1240
- shippingMethod: varchar("shipping_method", { length: 100 }),
1241
- trackingNumber: varchar("tracking_number", { length: 100 }),
1242
- carrierName: varchar("carrier_name", { length: 100 }),
1243
-
1244
- // Cost Information
1245
- shippingCost: decimal("shipping_cost", { precision: 12, scale: 4 }).default(
1246
- "0",
1247
- ),
1248
- totalCost: decimal("total_cost", { precision: 12, scale: 4 }),
1249
- currency: varchar("currency", { length: 3 }).notNull().default("USD"),
1250
-
1251
- // Date Management
1252
- requestedDate: timestamp("requested_date", { withTimezone: true }),
1253
- scheduledDate: timestamp("scheduled_date", { withTimezone: true }),
1254
- shippedDate: timestamp("shipped_date", { withTimezone: true }),
1255
- expectedDeliveryDate: timestamp("expected_delivery_date", {
1256
- withTimezone: true,
1257
- }),
1258
- actualDeliveryDate: timestamp("actual_delivery_date", {
1259
- withTimezone: true,
1260
- }),
1261
- initiatedAt: timestamp("initiated_at", { withTimezone: true }).notNull(),
1262
- completedAt: timestamp("completed_at", { withTimezone: true }),
1263
- cancelledAt: timestamp("cancelled_at", { withTimezone: true }),
1264
-
1265
- // Authorization and Approval
1266
- requiresApproval: boolean("requires_approval").notNull().default(false),
1267
- approvedBy: text("approved_by"),
1268
- approvedAt: timestamp("approved_at", { withTimezone: true }),
1269
- rejectedBy: text("rejected_by"),
1270
- rejectedAt: timestamp("rejected_at", { withTimezone: true }),
1271
- rejectionReason: text("rejection_reason"),
1272
-
1273
- // Document References
1274
- referenceOrderNumber: varchar("reference_order_number", { length: 100 }),
1275
- internalReference: varchar("internal_reference", { length: 100 }),
1276
- externalReference: varchar("external_reference", { length: 100 }),
1277
-
1278
- // Quality Control
1279
- requiresInspection: boolean("requires_inspection").notNull().default(false),
1280
- inspectedBy: text("inspected_by"),
1281
- inspectedAt: timestamp("inspected_at", { withTimezone: true }),
1282
- qualityNotes: text("quality_notes"),
1283
-
1284
- // Discrepancy Tracking
1285
- hasDiscrepancies: boolean("has_discrepancies").notNull().default(false),
1286
- discrepancyNotes: text("discrepancy_notes"),
1287
-
1288
- // Notes
1289
- notes: text("notes"),
1290
- internalNotes: text("internal_notes"),
1291
- shippingInstructions: text("shipping_instructions"),
1292
-
1293
- // Timestamps
1294
- createdAt: timestamp("created_at", { withTimezone: true })
1295
- .defaultNow()
1296
- .notNull(),
1297
- updatedAt: timestamp("updated_at", { withTimezone: true })
1298
- .defaultNow()
1299
- .notNull(),
1300
- createdBy: text("created_by"),
1301
- updatedBy: text("updated_by"),
1302
- },
1303
- (table) => ({
1304
- storeIdIndex: index("idx_transfers_store_id").on(table.storeId),
1305
- statusIndex: index("idx_transfers_status").on(table.status),
1306
- transferNumberIndex: index("idx_transfers_number").on(table.transferNumber),
1307
- uniqueTransferNumber: unique("idx_transfers_number_unique").on(
1308
- table.storeId,
1309
- table.transferNumber,
1310
- ),
1311
- }),
1312
- );
1313
-
1314
- export const inventoryTransferItems = pgTable(
1315
- "inventory_transfer_items",
1316
- {
1317
- id: text("id")
1318
- .primaryKey()
1319
- .$defaultFn(() => createId()),
1320
- transferId: text("transfer_id").notNull(),
1321
- productId: text("product_id").notNull(),
1322
- variantId: text("variant_id"),
1323
- sku: varchar("sku", { length: 255 }).notNull(),
1324
- quantity: integer("quantity").notNull(),
1325
- receivedQuantity: integer("received_quantity").default(0),
1326
- batchNumber: varchar("batch_number", { length: 255 }),
1327
- lotNumber: varchar("lot_number", { length: 255 }),
1328
- serialNumbers: jsonb("serial_numbers").$type<string[]>(),
1329
- expiryDate: timestamp("expiry_date", { withTimezone: true }),
1330
- metadata: jsonb("metadata").$type<Record<string, any>>().default({}),
1331
-
1332
- createdAt: timestamp("created_at", { withTimezone: true })
1333
- .defaultNow()
1334
- .notNull(),
1335
- updatedAt: timestamp("updated_at", { withTimezone: true })
1336
- .defaultNow()
1337
- .notNull(),
1338
- },
1339
- (table) => ({
1340
- transferIdIndex: index("idx_transfer_items_transfer_id").on(
1341
- table.transferId,
1342
- ),
1343
- productIdIndex: index("idx_transfer_items_product_id").on(table.productId),
1344
- }),
1345
- );
1346
-
1347
- // =====================================================
1348
- // QUALITY CONTROLS TABLE
1349
- // =====================================================
1350
-
1351
- export const qualityStatusEnum = pgEnum("quality_status", [
1352
- "PENDING_INSPECTION",
1353
- "PASSED",
1354
- "FAILED",
1355
- "CONDITIONALLY_PASSED",
1356
- "QUARANTINED",
1357
- "REJECTED",
1358
- "REWORK_REQUIRED",
1359
- "RELEASED",
1360
- "HOLD",
1361
- ]);
1362
-
1363
- export const inspectionTypeEnum = pgEnum("inspection_type", [
1364
- "INCOMING_INSPECTION",
1365
- "IN_PROCESS_INSPECTION",
1366
- "OUTGOING_INSPECTION",
1367
- "RANDOM_INSPECTION",
1368
- "CUSTOMER_COMPLAINT_INSPECTION",
1369
- "SUPPLIER_AUDIT",
1370
- "PERIODIC_REVIEW",
1371
- "EXPIRY_CHECK",
1372
- "DAMAGE_ASSESSMENT",
1373
- ]);
1374
-
1375
- export const qualityControls = pgTable(
1376
- "quality_controls",
1377
- {
1378
- id: text("id")
1379
- .primaryKey()
1380
- .$defaultFn(() => createId()),
1381
- storeId: text("store_id").notNull(),
1382
- qcNumber: varchar("qc_number", { length: 100 }).notNull(),
1383
-
1384
- // Product Information
1385
- productId: text("product_id").notNull(),
1386
- variantId: text("variant_id"),
1387
- sku: varchar("sku", { length: 255 }).notNull(),
1388
- productName: varchar("product_name", { length: 255 }),
1389
-
1390
- // Batch/Lot Information
1391
- lotId: text("lot_id"), // FK to inventory_lots
1392
- batchNumber: varchar("batch_number", { length: 100 }),
1393
- lotNumber: varchar("lot_number", { length: 100 }),
1394
- serialNumbers: jsonb("serial_numbers"),
1395
- autoQuarantined: boolean("auto_quarantined").notNull().default(false),
1396
-
1397
- // Location and Quantity
1398
- locationId: text("location_id").notNull(),
1399
- quantity: integer("quantity").notNull(),
1400
- sampleSize: integer("sample_size"),
1401
-
1402
- // Inspection Details
1403
- inspectionType: inspectionTypeEnum("inspection_type").notNull(),
1404
- inspectionDate: timestamp("inspection_date", {
1405
- withTimezone: true,
1406
- }).notNull(),
1407
- inspectedBy: text("inspected_by").notNull(),
1408
- inspectionDuration: integer("inspection_duration"), // minutes
1409
-
1410
- // Quality Assessment
1411
- overallStatus: qualityStatusEnum("overall_status").notNull(),
1412
- qualityGrade: varchar("quality_grade", { length: 20 }),
1413
- qualityScore: decimal("quality_score", { precision: 5, scale: 2 }),
1414
-
1415
- // Inspection Criteria and Results
1416
- criteria: jsonb("criteria").notNull(),
1417
- defects: jsonb("defects"),
1418
- measurements: jsonb("measurements"),
1419
- certificates: jsonb("certificates"),
1420
-
1421
- // Documentation
1422
- imageUrls: jsonb("image_urls"),
1423
- documentUrls: jsonb("document_urls"),
1424
-
1425
- // Supplier Information (for incoming inspections)
1426
- supplierId: text("supplier_id"),
1427
- supplierName: varchar("supplier_name", { length: 255 }),
1428
- purchaseOrderNumber: varchar("purchase_order_number", { length: 100 }),
1429
-
1430
- // Action Required
1431
- actionRequired: boolean("action_required").notNull().default(false),
1432
- correctionActions: jsonb("correction_actions"),
1433
-
1434
- // Follow-up Requirements
1435
- requiresReInspection: boolean("requires_re_inspection")
1436
- .notNull()
1437
- .default(false),
1438
- reInspectionDate: timestamp("re_inspection_date", { withTimezone: true }),
1439
- reInspectionNotes: text("re_inspection_notes"),
1440
-
1441
- // Disposition
1442
- dispositionDate: timestamp("disposition_date", { withTimezone: true }),
1443
- dispositionAction: varchar("disposition_action", { length: 50 }),
1444
- dispositionNotes: text("disposition_notes"),
1445
- dispositionBy: text("disposition_by"),
1446
-
1447
- // Status Updates
1448
- completedAt: timestamp("completed_at", { withTimezone: true }),
1449
- approvedBy: text("approved_by"),
1450
- approvedAt: timestamp("approved_at", { withTimezone: true }),
1451
-
1452
- // Customer Notification
1453
- customerNotified: boolean("customer_notified").notNull().default(false),
1454
- customerNotificationDate: timestamp("customer_notification_date", {
1455
- withTimezone: true,
1456
- }),
1457
- customerResponse: text("customer_response"),
1458
-
1459
- // Notes
1460
- notes: text("notes"),
1461
-
1462
- // Timestamps
1463
- createdAt: timestamp("created_at", { withTimezone: true })
1464
- .defaultNow()
1465
- .notNull(),
1466
- updatedAt: timestamp("updated_at", { withTimezone: true })
1467
- .defaultNow()
1468
- .notNull(),
1469
- createdBy: text("created_by"),
1470
- updatedBy: text("updated_by"),
1471
- },
1472
- (table) => ({
1473
- storeIdIndex: index("idx_quality_controls_store_id").on(table.storeId),
1474
- qcNumberIndex: index("idx_quality_controls_qc_number").on(table.qcNumber),
1475
- statusIndex: index("idx_quality_controls_status").on(table.overallStatus),
1476
- inspectionDateIndex: index("idx_quality_controls_inspection_date").on(
1477
- table.inspectionDate,
1478
- ),
1479
- uniqueQcNumber: unique("idx_quality_controls_number_unique").on(
1480
- table.storeId,
1481
- table.qcNumber,
1482
- ),
1483
- }),
1484
- );
1485
-
1486
- export const qualityTemplates = pgTable(
1487
- "quality_templates",
1488
- {
1489
- id: text("id")
1490
- .primaryKey()
1491
- .$defaultFn(() => createId()),
1492
- storeId: text("store_id").notNull(),
1493
- name: varchar("name", { length: 255 }).notNull(),
1494
- version: varchar("version", { length: 50 }).notNull(),
1495
- isActive: boolean("is_active").notNull().default(true),
1496
-
1497
- // Template Configuration
1498
- criteria: jsonb("criteria").$type<any[]>().default([]),
1499
- inspectionTypes: jsonb("inspection_types").$type<string[]>().default([]),
1500
-
1501
- // Notes
1502
- description: text("description"),
1503
- notes: text("notes"),
1504
-
1505
- // Timestamps
1506
- createdAt: timestamp("created_at", { withTimezone: true })
1507
- .defaultNow()
1508
- .notNull(),
1509
- updatedAt: timestamp("updated_at", { withTimezone: true })
1510
- .defaultNow()
1511
- .notNull(),
1512
- createdBy: text("created_by"),
1513
- updatedBy: text("updated_by"),
1514
- },
1515
- (table) => ({
1516
- storeIdIndex: index("idx_quality_templates_store_id").on(table.storeId),
1517
- nameIndex: index("idx_quality_templates_name").on(table.name),
1518
- isActiveIndex: index("idx_quality_templates_active").on(table.isActive),
1519
- }),
1520
- );
1521
-
1522
- // =====================================================
1523
- // SUPPLIER QUALITY RATINGS TABLE
1524
- // =====================================================
1525
-
1526
- export const supplierQualityRatings = pgTable(
1527
- "supplier_quality_ratings",
1528
- {
1529
- id: text("id")
1530
- .primaryKey()
1531
- .$defaultFn(() => createId()),
1532
- storeId: text("store_id").notNull(),
1533
- supplierId: text("supplier_id").notNull(),
1534
-
1535
- // Rating Period
1536
- ratingPeriod: jsonb("rating_period")
1537
- .$type<{
1538
- startDate: Date;
1539
- endDate: Date;
1540
- }>()
1541
- .notNull(),
1542
-
1543
- // Inspection Metrics
1544
- totalInspections: integer("total_inspections").notNull(),
1545
- passedInspections: integer("passed_inspections").notNull(),
1546
- failedInspections: integer("failed_inspections").notNull(),
1547
-
1548
- // Performance Metrics
1549
- qualityScore: decimal("quality_score", { precision: 5, scale: 2 }),
1550
- onTimeDeliveryRate: decimal("on_time_delivery_rate", {
1551
- precision: 5,
1552
- scale: 2,
1553
- }),
1554
- defectRate: decimal("defect_rate", { precision: 5, scale: 2 }),
1555
-
1556
- // Overall Rating
1557
- overallRating: varchar("overall_rating", { length: 20 }),
1558
-
1559
- // Notes
1560
- notes: text("notes"),
1561
-
1562
- // Timestamps
1563
- createdAt: timestamp("created_at", { withTimezone: true })
1564
- .defaultNow()
1565
- .notNull(),
1566
- updatedAt: timestamp("updated_at", { withTimezone: true })
1567
- .defaultNow()
1568
- .notNull(),
1569
- createdBy: text("created_by"),
1570
- updatedBy: text("updated_by"),
1571
- },
1572
- (table) => ({
1573
- storeIdIndex: index("idx_supplier_quality_ratings_store_id").on(
1574
- table.storeId,
1575
- ),
1576
- supplierIdIndex: index("idx_supplier_quality_ratings_supplier_id").on(
1577
- table.supplierId,
1578
- ),
1579
- }),
1580
- );
1581
-
1582
- // =====================================================
1583
- // SUPPLIERS TABLE
1584
- // =====================================================
1585
-
1586
- export const supplierStatusEnum = pgEnum("supplier_status", [
1587
- "ACTIVE",
1588
- "INACTIVE",
1589
- "SUSPENDED",
1590
- "UNDER_REVIEW",
1591
- "PENDING_APPROVAL",
1592
- "BLACKLISTED",
1593
- ]);
1594
-
1595
- export const supplierTypeEnum = pgEnum("supplier_type", [
1596
- "MANUFACTURER",
1597
- "DISTRIBUTOR",
1598
- "WHOLESALER",
1599
- "DROPSHIPPER",
1600
- "SERVICE_PROVIDER",
1601
- "LOCAL_VENDOR",
1602
- "INTERNATIONAL_VENDOR",
1603
- "BROKER",
1604
- "IMPORTER",
1605
- "EXPORTER",
1606
- "RETAILER",
1607
- "RESELLER",
1608
- "CONTRACTOR",
1609
- "CONSULTANT",
1610
- "PARTS_SUPPLIER",
1611
- "RAW_MATERIALS_SUPPLIER",
1612
- "PACKAGING_SUPPLIER",
1613
- "EQUIPMENT_SUPPLIER",
1614
- "MAINTENANCE_SUPPLIER",
1615
- "LOGISTICS_PROVIDER",
1616
- "FREIGHT_FORWARDER",
1617
- "CUSTOMS_BROKER",
1618
- "TECHNOLOGY_VENDOR",
1619
- "SOFTWARE_VENDOR",
1620
- "HARDWARE_VENDOR",
1621
- "OFFICE_SUPPLIES_VENDOR",
1622
- "UTILITIES_PROVIDER",
1623
- "CLEANING_SERVICES",
1624
- "SECURITY_SERVICES",
1625
- "MARKETING_SERVICES",
1626
- "PROFESSIONAL_SERVICES",
1627
- "TEMPORARY_STAFFING",
1628
- "SPECIALIZED_SUPPLIER",
1629
- "OTHER",
1630
- ]);
1631
-
1632
- export const supplierRatingEnum = pgEnum("supplier_rating", [
1633
- "EXCELLENT",
1634
- "GOOD",
1635
- "AVERAGE",
1636
- "POOR",
1637
- "UNRATED",
1638
- ]);
1639
-
1640
- export const suppliers = pgTable(
1641
- "suppliers",
1642
- {
1643
- id: text("id")
1644
- .primaryKey()
1645
- .$defaultFn(() => createId()),
1646
- storeId: text("store_id").notNull(),
1647
- name: varchar("name", { length: 255 }).notNull(),
1648
- code: varchar("code", { length: 100 }).notNull(),
1649
- status: supplierStatusEnum("status").notNull().default("ACTIVE"),
1650
- type: supplierTypeEnum("type").notNull().default("MANUFACTURER"),
1651
-
1652
- // Contact Information
1653
- primaryContact: jsonb("primary_contact").$type<{
1654
- name?: string;
1655
- email?: string;
1656
- phone?: string;
1657
- alternatePhone?: string;
1658
- }>(),
1659
-
1660
- // Address Information
1661
- address: jsonb("address").$type<{
1662
- street: string;
1663
- city: string;
1664
- state: string;
1665
- postalCode: string;
1666
- country: string;
1667
- }>(),
1668
- billingAddress: jsonb("billing_address").$type<{
1669
- street: string;
1670
- city: string;
1671
- state: string;
1672
- postalCode: string;
1673
- country: string;
1674
- }>(),
1675
-
1676
- // Payment Terms
1677
- paymentTerms: jsonb("payment_terms").$type<{
1678
- termsDays: number;
1679
- discountDays?: number;
1680
- discountPercentage?: number;
1681
- penaltyRate?: number;
1682
- }>(),
1683
-
1684
- // Business Information
1685
- taxId: varchar("tax_id", { length: 100 }),
1686
- businessLicense: varchar("business_license", { length: 100 }),
1687
- certifications: jsonb("certifications").$type<string[]>().default([]),
1688
-
1689
- // Performance Metrics
1690
- rating: supplierRatingEnum("rating"),
1691
- onTimeDeliveryRate: decimal("on_time_delivery_rate", {
1692
- precision: 5,
1693
- scale: 2,
1694
- }),
1695
- qualityRating: decimal("quality_rating", { precision: 5, scale: 2 }),
1696
-
1697
- // Business Terms
1698
- minimumOrderAmount: decimal("minimum_order_amount", {
1699
- precision: 12,
1700
- scale: 4,
1701
- }),
1702
- leadTimeDays: integer("lead_time_days"),
1703
- deliveryMethod: varchar("delivery_method", { length: 100 }),
1704
- currency: varchar("currency", { length: 3 }).notNull().default("USD"),
1705
-
1706
- // Metadata
1707
- tags: jsonb("tags").$type<string[]>().default([]),
1708
- notes: text("notes"),
1709
- metadata: jsonb("metadata").$type<Record<string, any>>().default({}),
1710
-
1711
- // Status
1712
- isActive: boolean("is_active").notNull().default(true),
1713
-
1714
- // Timestamps
1715
- createdAt: timestamp("created_at", { withTimezone: true })
1716
- .defaultNow()
1717
- .notNull(),
1718
- updatedAt: timestamp("updated_at", { withTimezone: true })
1719
- .defaultNow()
1720
- .notNull(),
1721
- createdBy: text("created_by"),
1722
- updatedBy: text("updated_by"),
1723
- },
1724
- (table) => ({
1725
- storeIdIndex: index("idx_suppliers_store_id").on(table.storeId),
1726
- statusIndex: index("idx_suppliers_status").on(table.status),
1727
- typeIndex: index("idx_suppliers_type").on(table.type),
1728
- ratingIndex: index("idx_suppliers_rating").on(table.rating),
1729
- uniqueCodePerStore: unique("idx_suppliers_code_unique").on(
1730
- table.storeId,
1731
- table.code,
1732
- ),
1733
- }),
1734
- );
1735
-
1736
- // =====================================================
1737
- // PURCHASE ORDERS TABLE
1738
- // =====================================================
1739
-
1740
- export const purchaseOrderStatusEnum = pgEnum("purchase_order_status", [
1741
- "DRAFT",
1742
- "SENT",
1743
- "ACKNOWLEDGED",
1744
- "APPROVED",
1745
- "PENDING_APPROVAL",
1746
- "PARTIALLY_RECEIVED",
1747
- "RECEIVED",
1748
- "COMPLETED",
1749
- "CANCELLED",
1750
- "DISPUTED",
1751
- ]);
1752
-
1753
- export const purchaseOrders = pgTable(
1754
- "purchase_orders",
1755
- {
1756
- id: text("id")
1757
- .primaryKey()
1758
- .$defaultFn(() => createId()),
1759
- storeId: text("store_id").notNull(),
1760
- supplierId: text("supplier_id").notNull(),
1761
- orderNumber: varchar("order_number", { length: 100 }).notNull(),
1762
- status: purchaseOrderStatusEnum("status").notNull().default("DRAFT"),
1763
-
1764
- // Order Details
1765
- orderDate: timestamp("order_date", { withTimezone: true }).notNull(),
1766
- requestedDeliveryDate: timestamp("requested_delivery_date", {
1767
- withTimezone: true,
1768
- }),
1769
- expectedDeliveryDate: timestamp("expected_delivery_date", {
1770
- withTimezone: true,
1771
- }),
1772
- actualDeliveryDate: timestamp("actual_delivery_date", {
1773
- withTimezone: true,
1774
- }),
1775
-
1776
- // Financial Information
1777
- subtotal: decimal("subtotal", { precision: 12, scale: 4 }).notNull(),
1778
- taxAmount: decimal("tax_amount", { precision: 12, scale: 4 }).default("0"),
1779
- discountAmount: decimal("discount_amount", {
1780
- precision: 12,
1781
- scale: 4,
1782
- }).default("0"),
1783
- shippingAmount: decimal("shipping_amount", {
1784
- precision: 12,
1785
- scale: 4,
1786
- }).default("0"),
1787
- totalAmount: decimal("total_amount", { precision: 12, scale: 4 }).notNull(),
1788
- currency: varchar("currency", { length: 3 }).notNull().default("USD"),
1789
-
1790
- // Shipping Information
1791
- shippingAddress: jsonb("shipping_address").$type<{
1792
- street: string;
1793
- city: string;
1794
- state: string;
1795
- postalCode: string;
1796
- country: string;
1797
- }>(),
1798
-
1799
- // Payment Terms
1800
- paymentTerms: varchar("payment_terms", { length: 50 }).notNull(),
1801
-
1802
- // Status Tracking
1803
- approvedBy: text("approved_by"),
1804
- approvedAt: timestamp("approved_at", { withTimezone: true }),
1805
- sentDate: timestamp("sent_date", { withTimezone: true }),
1806
- acknowledgedDate: timestamp("acknowledged_date", { withTimezone: true }),
1807
-
1808
- // Notes
1809
- notes: text("notes"),
1810
- internalNotes: text("internal_notes"),
1811
-
1812
- // Timestamps
1813
- createdAt: timestamp("created_at", { withTimezone: true })
1814
- .defaultNow()
1815
- .notNull(),
1816
- updatedAt: timestamp("updated_at", { withTimezone: true })
1817
- .defaultNow()
1818
- .notNull(),
1819
- createdBy: text("created_by"),
1820
- updatedBy: text("updated_by"),
1821
- },
1822
- (table) => ({
1823
- storeIdIndex: index("idx_purchase_orders_store_id").on(table.storeId),
1824
- supplierIdIndex: index("idx_purchase_orders_supplier_id").on(
1825
- table.supplierId,
1826
- ),
1827
- statusIndex: index("idx_purchase_orders_status").on(table.status),
1828
- orderDateIndex: index("idx_purchase_orders_order_date").on(table.orderDate),
1829
- uniqueOrderNumber: unique("idx_purchase_orders_number_unique").on(
1830
- table.storeId,
1831
- table.orderNumber,
1832
- ),
1833
- }),
1834
- );
1835
-
1836
- export const purchaseOrderItems = pgTable(
1837
- "purchase_order_items",
1838
- {
1839
- id: text("id")
1840
- .primaryKey()
1841
- .$defaultFn(() => createId()),
1842
- orderId: text("order_id").notNull(),
1843
- productId: text("product_id").notNull(),
1844
- variantId: text("variant_id"),
1845
- sku: varchar("sku", { length: 255 }).notNull(),
1846
-
1847
- // Quantity and Pricing
1848
- quantity: integer("quantity").notNull(),
1849
- receivedQuantity: integer("received_quantity").default(0),
1850
- unitPrice: decimal("unit_price", { precision: 12, scale: 4 }).notNull(),
1851
- totalPrice: decimal("total_price", { precision: 12, scale: 4 }).notNull(),
1852
- taxRate: decimal("tax_rate", { precision: 5, scale: 2 }).default("0"),
1853
- discountRate: decimal("discount_rate", { precision: 5, scale: 2 }).default(
1854
- "0",
1855
- ),
1856
-
1857
- // Notes
1858
- notes: text("notes"),
1859
-
1860
- // Timestamps
1861
- createdAt: timestamp("created_at", { withTimezone: true })
1862
- .defaultNow()
1863
- .notNull(),
1864
- updatedAt: timestamp("updated_at", { withTimezone: true })
1865
- .defaultNow()
1866
- .notNull(),
1867
- },
1868
- (table) => ({
1869
- orderIdIndex: index("idx_purchase_order_items_order_id").on(table.orderId),
1870
- productIdIndex: index("idx_purchase_order_items_product_id").on(
1871
- table.productId,
1872
- ),
1873
- }),
1874
- );
1875
-
1876
- export const productSuppliers = pgTable(
1877
- "product_suppliers",
1878
- {
1879
- id: text("id")
1880
- .primaryKey()
1881
- .$defaultFn(() => createId()),
1882
- storeId: text("store_id").notNull(),
1883
- productId: text("product_id").notNull(),
1884
- supplierId: text("supplier_id").notNull(),
1885
-
1886
- // Supplier Product Information
1887
- supplierSku: varchar("supplier_sku", { length: 255 }),
1888
- supplierProductName: varchar("supplier_product_name", { length: 255 }),
1889
-
1890
- // Pricing and Terms
1891
- unitCost: decimal("unit_cost", { precision: 12, scale: 4 }),
1892
- cost: decimal("cost", { precision: 12, scale: 4 }),
1893
- currency: varchar("currency", { length: 3 }).notNull().default("USD"),
1894
- minimumOrderQuantity: integer("minimum_order_quantity"),
1895
- leadTime: integer("lead_time"),
1896
- packSize: integer("pack_size").default(1),
1897
- availability: varchar("availability", { length: 20 }).default("IN_STOCK"),
1898
-
1899
- // Status
1900
- isActive: boolean("is_active").notNull().default(true),
1901
- isPreferred: boolean("is_preferred").notNull().default(false),
1902
-
1903
- // Timestamps
1904
- createdAt: timestamp("created_at", { withTimezone: true })
1905
- .defaultNow()
1906
- .notNull(),
1907
- updatedAt: timestamp("updated_at", { withTimezone: true })
1908
- .defaultNow()
1909
- .notNull(),
1910
- lastOrderDate: timestamp("last_order_date", { withTimezone: true }),
1911
- lastCostUpdate: timestamp("last_cost_update", { withTimezone: true }),
1912
- },
1913
- (table) => ({
1914
- storeIdIndex: index("idx_product_suppliers_store_id").on(table.storeId),
1915
- productIdIndex: index("idx_product_suppliers_product_id").on(
1916
- table.productId,
1917
- ),
1918
- supplierIdIndex: index("idx_product_suppliers_supplier_id").on(
1919
- table.supplierId,
1920
- ),
1921
- uniqueProductSupplier: unique("idx_product_suppliers_unique").on(
1922
- table.storeId,
1923
- table.productId,
1924
- table.supplierId,
1925
- ),
1926
- }),
1927
- );