Rebrand from Forte (music-store-specific) to LunarFront (any small business): - Package namespace @forte/* → @lunarfront/* - Database forte/forte_test → lunarfront/lunarfront_test - Docker containers, volumes, connection strings - UI branding, localStorage keys, test emails - All documentation and planning docs Generalize music-specific terminology: - instrumentDescription → itemDescription - instrumentCount → itemCount - instrumentType → itemCategory (on service templates) - New migration 0027_generalize_terminology for column renames - Seed data updated with generic examples - RBAC descriptions updated
183 lines
7.3 KiB
TypeScript
183 lines
7.3 KiB
TypeScript
import {
|
|
pgTable,
|
|
uuid,
|
|
varchar,
|
|
text,
|
|
timestamp,
|
|
boolean,
|
|
integer,
|
|
numeric,
|
|
pgEnum,
|
|
} from 'drizzle-orm/pg-core'
|
|
import { locations } from './stores.js'
|
|
import { accounts } from './accounts.js'
|
|
import { inventoryUnits, products } from './inventory.js'
|
|
import { users } from './users.js'
|
|
|
|
// --- Enums ---
|
|
|
|
export const repairTicketStatusEnum = pgEnum('repair_ticket_status', [
|
|
'new',
|
|
'in_transit',
|
|
'intake',
|
|
'diagnosing',
|
|
'pending_approval',
|
|
'approved',
|
|
'in_progress',
|
|
'pending_parts',
|
|
'ready',
|
|
'picked_up',
|
|
'delivered',
|
|
'cancelled',
|
|
])
|
|
|
|
export const repairLineItemTypeEnum = pgEnum('repair_line_item_type', [
|
|
'labor',
|
|
'part',
|
|
'flat_rate',
|
|
'misc',
|
|
])
|
|
|
|
export const repairConditionInEnum = pgEnum('repair_condition_in', [
|
|
'excellent',
|
|
'good',
|
|
'fair',
|
|
'poor',
|
|
])
|
|
|
|
export const repairBatchStatusEnum = pgEnum('repair_batch_status', [
|
|
'intake',
|
|
'in_progress',
|
|
'pending_approval',
|
|
'approved',
|
|
'completed',
|
|
'delivered',
|
|
'cancelled',
|
|
])
|
|
|
|
export const repairBatchApprovalEnum = pgEnum('repair_batch_approval', [
|
|
'pending',
|
|
'approved',
|
|
'rejected',
|
|
])
|
|
|
|
// --- Tables ---
|
|
|
|
// Defined before repairTickets because tickets FK to batches
|
|
export const repairBatches = pgTable('repair_batch', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
locationId: uuid('location_id').references(() => locations.id),
|
|
batchNumber: varchar('batch_number', { length: 50 }),
|
|
accountId: uuid('account_id')
|
|
.notNull()
|
|
.references(() => accounts.id),
|
|
contactName: varchar('contact_name', { length: 255 }),
|
|
contactPhone: varchar('contact_phone', { length: 50 }),
|
|
contactEmail: varchar('contact_email', { length: 255 }),
|
|
status: repairBatchStatusEnum('status').notNull().default('intake'),
|
|
approvalStatus: repairBatchApprovalEnum('approval_status').notNull().default('pending'),
|
|
approvedBy: uuid('approved_by').references(() => users.id),
|
|
approvedAt: timestamp('approved_at', { withTimezone: true }),
|
|
pickupDate: timestamp('pickup_date', { withTimezone: true }),
|
|
dueDate: timestamp('due_date', { withTimezone: true }),
|
|
completedDate: timestamp('completed_date', { withTimezone: true }),
|
|
deliveredDate: timestamp('delivered_date', { withTimezone: true }),
|
|
itemCount: integer('item_count').notNull().default(0),
|
|
receivedCount: integer('received_count').notNull().default(0),
|
|
estimatedTotal: numeric('estimated_total', { precision: 10, scale: 2 }),
|
|
actualTotal: numeric('actual_total', { precision: 10, scale: 2 }),
|
|
notes: text('notes'),
|
|
legacyId: varchar('legacy_id', { length: 255 }),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
export const repairTickets = pgTable('repair_ticket', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
locationId: uuid('location_id').references(() => locations.id),
|
|
repairBatchId: uuid('repair_batch_id').references(() => repairBatches.id),
|
|
ticketNumber: varchar('ticket_number', { length: 50 }),
|
|
accountId: uuid('account_id').references(() => accounts.id),
|
|
customerName: varchar('customer_name', { length: 255 }).notNull(),
|
|
customerPhone: varchar('customer_phone', { length: 50 }),
|
|
inventoryUnitId: uuid('inventory_unit_id').references(() => inventoryUnits.id),
|
|
itemDescription: text('item_description'),
|
|
serialNumber: varchar('serial_number', { length: 255 }),
|
|
conditionIn: repairConditionInEnum('condition_in'),
|
|
conditionInNotes: text('condition_in_notes'),
|
|
problemDescription: text('problem_description').notNull(),
|
|
technicianNotes: text('technician_notes'),
|
|
status: repairTicketStatusEnum('status').notNull().default('new'),
|
|
assignedTechnicianId: uuid('assigned_technician_id').references(() => users.id),
|
|
estimatedCost: numeric('estimated_cost', { precision: 10, scale: 2 }),
|
|
actualCost: numeric('actual_cost', { precision: 10, scale: 2 }),
|
|
intakeDate: timestamp('intake_date', { withTimezone: true }).notNull().defaultNow(),
|
|
promisedDate: timestamp('promised_date', { withTimezone: true }),
|
|
completedDate: timestamp('completed_date', { withTimezone: true }),
|
|
legacyId: varchar('legacy_id', { length: 255 }),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
export const repairLineItems = pgTable('repair_line_item', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
repairTicketId: uuid('repair_ticket_id')
|
|
.notNull()
|
|
.references(() => repairTickets.id),
|
|
itemType: repairLineItemTypeEnum('item_type').notNull(),
|
|
description: varchar('description', { length: 255 }).notNull(),
|
|
productId: uuid('product_id').references(() => products.id),
|
|
qty: numeric('qty', { precision: 10, scale: 3 }).notNull().default('1'),
|
|
unitPrice: numeric('unit_price', { precision: 10, scale: 2 }).notNull().default('0'),
|
|
totalPrice: numeric('total_price', { precision: 10, scale: 2 }).notNull().default('0'),
|
|
cost: numeric('cost', { precision: 10, scale: 2 }),
|
|
technicianId: uuid('technician_id').references(() => users.id),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
export const repairNoteVisibilityEnum = pgEnum('repair_note_visibility', ['internal', 'customer'])
|
|
|
|
export const repairNotes = pgTable('repair_note', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
repairTicketId: uuid('repair_ticket_id')
|
|
.notNull()
|
|
.references(() => repairTickets.id),
|
|
authorId: uuid('author_id')
|
|
.notNull()
|
|
.references(() => users.id),
|
|
authorName: varchar('author_name', { length: 255 }).notNull(),
|
|
content: text('content').notNull(),
|
|
visibility: repairNoteVisibilityEnum('visibility').notNull().default('internal'),
|
|
ticketStatus: repairTicketStatusEnum('ticket_status'),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
export type RepairNote = typeof repairNotes.$inferSelect
|
|
export type RepairNoteInsert = typeof repairNotes.$inferInsert
|
|
|
|
export const repairServiceTemplates = pgTable('repair_service_template', {
|
|
id: uuid('id').primaryKey().defaultRandom(),
|
|
name: varchar('name', { length: 255 }).notNull(),
|
|
itemCategory: varchar('item_category', { length: 100 }),
|
|
size: varchar('size', { length: 50 }),
|
|
description: text('description'),
|
|
itemType: repairLineItemTypeEnum('item_type').notNull().default('flat_rate'),
|
|
defaultPrice: numeric('default_price', { precision: 10, scale: 2 }).notNull().default('0'),
|
|
defaultCost: numeric('default_cost', { precision: 10, scale: 2 }),
|
|
sortOrder: integer('sort_order').notNull().default(0),
|
|
isActive: boolean('is_active').notNull().default(true),
|
|
createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
|
|
updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
|
|
})
|
|
|
|
// --- Type exports ---
|
|
|
|
export type RepairTicket = typeof repairTickets.$inferSelect
|
|
export type RepairTicketInsert = typeof repairTickets.$inferInsert
|
|
export type RepairLineItem = typeof repairLineItems.$inferSelect
|
|
export type RepairLineItemInsert = typeof repairLineItems.$inferInsert
|
|
export type RepairBatch = typeof repairBatches.$inferSelect
|
|
export type RepairBatchInsert = typeof repairBatches.$inferInsert
|
|
export type RepairServiceTemplate = typeof repairServiceTemplates.$inferSelect
|
|
export type RepairServiceTemplateInsert = typeof repairServiceTemplates.$inferInsert
|