This commit is contained in:
jason
2026-03-16 14:38:00 -05:00
commit 3d05e3929d
193 changed files with 40238 additions and 0 deletions

View File

@@ -0,0 +1,139 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL PRIMARY KEY,
"email" TEXT NOT NULL,
"passwordHash" TEXT NOT NULL,
"firstName" TEXT NOT NULL,
"lastName" TEXT NOT NULL,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Role" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Permission" (
"id" TEXT NOT NULL PRIMARY KEY,
"key" TEXT NOT NULL,
"description" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "UserRole" (
"userId" TEXT NOT NULL,
"roleId" TEXT NOT NULL,
"assignedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"assignedBy" TEXT,
PRIMARY KEY ("userId", "roleId"),
CONSTRAINT "UserRole_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "UserRole_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "RolePermission" (
"roleId" TEXT NOT NULL,
"permissionId" TEXT NOT NULL,
"grantedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("roleId", "permissionId"),
CONSTRAINT "RolePermission_permissionId_fkey" FOREIGN KEY ("permissionId") REFERENCES "Permission" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "RolePermission_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "Role" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "CompanyProfile" (
"id" TEXT NOT NULL PRIMARY KEY,
"companyName" TEXT NOT NULL,
"legalName" TEXT NOT NULL,
"email" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"website" TEXT NOT NULL,
"taxId" TEXT NOT NULL,
"addressLine1" TEXT NOT NULL,
"addressLine2" TEXT NOT NULL,
"city" TEXT NOT NULL,
"state" TEXT NOT NULL,
"postalCode" TEXT NOT NULL,
"country" TEXT NOT NULL,
"primaryColor" TEXT NOT NULL DEFAULT '#185ADB',
"accentColor" TEXT NOT NULL DEFAULT '#00A6A6',
"surfaceColor" TEXT NOT NULL DEFAULT '#F4F7FB',
"fontFamily" TEXT NOT NULL DEFAULT 'Manrope',
"logoFileId" TEXT,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "CompanyProfile_logoFileId_fkey" FOREIGN KEY ("logoFileId") REFERENCES "FileAttachment" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "FileAttachment" (
"id" TEXT NOT NULL PRIMARY KEY,
"originalName" TEXT NOT NULL,
"storedName" TEXT NOT NULL,
"mimeType" TEXT NOT NULL,
"sizeBytes" INTEGER NOT NULL,
"relativePath" TEXT NOT NULL,
"ownerType" TEXT NOT NULL,
"ownerId" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Customer" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"addressLine1" TEXT NOT NULL,
"addressLine2" TEXT NOT NULL,
"city" TEXT NOT NULL,
"state" TEXT NOT NULL,
"postalCode" TEXT NOT NULL,
"country" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "Vendor" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"email" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"addressLine1" TEXT NOT NULL,
"addressLine2" TEXT NOT NULL,
"city" TEXT NOT NULL,
"state" TEXT NOT NULL,
"postalCode" TEXT NOT NULL,
"country" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Role_name_key" ON "Role"("name");
-- CreateIndex
CREATE UNIQUE INDEX "Permission_key_key" ON "Permission"("key");
-- CreateIndex
CREATE UNIQUE INDEX "CompanyProfile_logoFileId_key" ON "CompanyProfile"("logoFileId");

View File

@@ -0,0 +1,7 @@
ALTER TABLE "Customer" ADD COLUMN "status" TEXT NOT NULL DEFAULT 'ACTIVE';
ALTER TABLE "Vendor" ADD COLUMN "status" TEXT NOT NULL DEFAULT 'ACTIVE';
CREATE INDEX "Customer_status_idx" ON "Customer"("status");
CREATE INDEX "Vendor_status_idx" ON "Vendor"("status");

View File

@@ -0,0 +1,19 @@
CREATE TABLE "CrmContactEntry" (
"id" TEXT NOT NULL PRIMARY KEY,
"type" TEXT NOT NULL DEFAULT 'NOTE',
"summary" TEXT NOT NULL,
"body" TEXT NOT NULL,
"contactAt" DATETIME NOT NULL,
"customerId" TEXT,
"vendorId" TEXT,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "CrmContactEntry_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "CrmContactEntry_vendorId_fkey" FOREIGN KEY ("vendorId") REFERENCES "Vendor" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "CrmContactEntry_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
CREATE INDEX "CrmContactEntry_customerId_contactAt_idx" ON "CrmContactEntry"("customerId", "contactAt");
CREATE INDEX "CrmContactEntry_vendorId_contactAt_idx" ON "CrmContactEntry"("vendorId", "contactAt");

View File

@@ -0,0 +1,7 @@
ALTER TABLE "Customer" ADD COLUMN "isReseller" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Customer" ADD COLUMN "resellerDiscountPercent" REAL NOT NULL DEFAULT 0;
ALTER TABLE "Customer" ADD COLUMN "parentCustomerId" TEXT REFERENCES "Customer" ("id") ON DELETE SET NULL ON UPDATE CASCADE;
CREATE INDEX "Customer_parentCustomerId_idx" ON "Customer"("parentCustomerId");

View File

@@ -0,0 +1,27 @@
ALTER TABLE "Customer" ADD COLUMN "paymentTerms" TEXT;
ALTER TABLE "Customer" ADD COLUMN "currencyCode" TEXT DEFAULT 'USD';
ALTER TABLE "Customer" ADD COLUMN "taxExempt" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Customer" ADD COLUMN "creditHold" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "paymentTerms" TEXT;
ALTER TABLE "Vendor" ADD COLUMN "currencyCode" TEXT DEFAULT 'USD';
ALTER TABLE "Vendor" ADD COLUMN "taxExempt" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "creditHold" BOOLEAN NOT NULL DEFAULT false;
CREATE TABLE "CrmContact" (
"id" TEXT NOT NULL PRIMARY KEY,
"fullName" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'OTHER',
"email" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"isPrimary" BOOLEAN NOT NULL DEFAULT false,
"customerId" TEXT,
"vendorId" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "CrmContact_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "CrmContact_vendorId_fkey" FOREIGN KEY ("vendorId") REFERENCES "Vendor" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX "CrmContact_customerId_idx" ON "CrmContact"("customerId");
CREATE INDEX "CrmContact_vendorId_idx" ON "CrmContact"("vendorId");

View File

@@ -0,0 +1,11 @@
ALTER TABLE "Customer" ADD COLUMN "lifecycleStage" TEXT NOT NULL DEFAULT 'ACTIVE';
ALTER TABLE "Customer" ADD COLUMN "preferredAccount" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Customer" ADD COLUMN "strategicAccount" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Customer" ADD COLUMN "requiresApproval" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Customer" ADD COLUMN "blockedAccount" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "lifecycleStage" TEXT NOT NULL DEFAULT 'ACTIVE';
ALTER TABLE "Vendor" ADD COLUMN "preferredAccount" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "strategicAccount" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "requiresApproval" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "Vendor" ADD COLUMN "blockedAccount" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -0,0 +1,33 @@
CREATE TABLE "InventoryItem" (
"id" TEXT NOT NULL PRIMARY KEY,
"sku" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"type" TEXT NOT NULL,
"status" TEXT NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"isSellable" BOOLEAN NOT NULL DEFAULT true,
"isPurchasable" BOOLEAN NOT NULL DEFAULT true,
"defaultCost" REAL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
CREATE TABLE "InventoryBomLine" (
"id" TEXT NOT NULL PRIMARY KEY,
"parentItemId" TEXT NOT NULL,
"componentItemId" TEXT NOT NULL,
"quantity" REAL NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"position" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryBomLine_parentItemId_fkey" FOREIGN KEY ("parentItemId") REFERENCES "InventoryItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventoryBomLine_componentItemId_fkey" FOREIGN KEY ("componentItemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "InventoryItem_sku_key" ON "InventoryItem"("sku");
CREATE INDEX "InventoryBomLine_parentItemId_position_idx" ON "InventoryBomLine"("parentItemId", "position");
CREATE INDEX "InventoryBomLine_componentItemId_idx" ON "InventoryBomLine"("componentItemId");

View File

@@ -0,0 +1,23 @@
CREATE TABLE "Warehouse" (
"id" TEXT NOT NULL PRIMARY KEY,
"code" TEXT NOT NULL,
"name" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
CREATE TABLE "WarehouseLocation" (
"id" TEXT NOT NULL PRIMARY KEY,
"warehouseId" TEXT NOT NULL,
"code" TEXT NOT NULL,
"name" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "WarehouseLocation_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "Warehouse_code_key" ON "Warehouse"("code");
CREATE UNIQUE INDEX "WarehouseLocation_warehouseId_code_key" ON "WarehouseLocation"("warehouseId", "code");
CREATE INDEX "WarehouseLocation_warehouseId_idx" ON "WarehouseLocation"("warehouseId");

View File

@@ -0,0 +1,27 @@
-- CreateTable
CREATE TABLE "InventoryTransaction" (
"id" TEXT NOT NULL PRIMARY KEY,
"itemId" TEXT NOT NULL,
"warehouseId" TEXT NOT NULL,
"locationId" TEXT NOT NULL,
"transactionType" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"reference" TEXT NOT NULL,
"notes" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryTransaction_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventoryTransaction_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransaction_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransaction_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE INDEX "InventoryTransaction_itemId_createdAt_idx" ON "InventoryTransaction"("itemId", "createdAt");
-- CreateIndex
CREATE INDEX "InventoryTransaction_warehouseId_createdAt_idx" ON "InventoryTransaction"("warehouseId", "createdAt");
-- CreateIndex
CREATE INDEX "InventoryTransaction_locationId_createdAt_idx" ON "InventoryTransaction"("locationId", "createdAt");

View File

@@ -0,0 +1,70 @@
-- CreateTable
CREATE TABLE "SalesQuote" (
"id" TEXT NOT NULL PRIMARY KEY,
"documentNumber" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"issueDate" DATETIME NOT NULL,
"expiresAt" DATETIME,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesQuote_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "SalesQuoteLine" (
"id" TEXT NOT NULL PRIMARY KEY,
"quoteId" TEXT NOT NULL,
"itemId" TEXT NOT NULL,
"description" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"unitPrice" REAL NOT NULL,
"position" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesQuoteLine_quoteId_fkey" FOREIGN KEY ("quoteId") REFERENCES "SalesQuote" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "SalesQuoteLine_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "SalesOrder" (
"id" TEXT NOT NULL PRIMARY KEY,
"documentNumber" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"issueDate" DATETIME NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesOrder_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "SalesOrderLine" (
"id" TEXT NOT NULL PRIMARY KEY,
"orderId" TEXT NOT NULL,
"itemId" TEXT NOT NULL,
"description" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"unitPrice" REAL NOT NULL,
"position" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesOrderLine_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "SalesOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "SalesOrderLine_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "SalesQuote_documentNumber_key" ON "SalesQuote"("documentNumber");
-- CreateIndex
CREATE INDEX "SalesQuoteLine_quoteId_position_idx" ON "SalesQuoteLine"("quoteId", "position");
-- CreateIndex
CREATE UNIQUE INDEX "SalesOrder_documentNumber_key" ON "SalesOrder"("documentNumber");
-- CreateIndex
CREATE INDEX "SalesOrderLine_orderId_position_idx" ON "SalesOrderLine"("orderId", "position");

View File

@@ -0,0 +1 @@
ALTER TABLE "InventoryItem" ADD COLUMN "defaultPrice" REAL;

View File

@@ -0,0 +1,7 @@
ALTER TABLE "SalesQuote" ADD COLUMN "discountPercent" REAL NOT NULL DEFAULT 0;
ALTER TABLE "SalesQuote" ADD COLUMN "taxPercent" REAL NOT NULL DEFAULT 0;
ALTER TABLE "SalesQuote" ADD COLUMN "freightAmount" REAL NOT NULL DEFAULT 0;
ALTER TABLE "SalesOrder" ADD COLUMN "discountPercent" REAL NOT NULL DEFAULT 0;
ALTER TABLE "SalesOrder" ADD COLUMN "taxPercent" REAL NOT NULL DEFAULT 0;
ALTER TABLE "SalesOrder" ADD COLUMN "freightAmount" REAL NOT NULL DEFAULT 0;

View File

@@ -0,0 +1,18 @@
CREATE TABLE "Shipment" (
"id" TEXT NOT NULL PRIMARY KEY,
"shipmentNumber" TEXT NOT NULL,
"salesOrderId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"shipDate" DATETIME,
"carrier" TEXT NOT NULL,
"serviceLevel" TEXT NOT NULL,
"trackingNumber" TEXT NOT NULL,
"packageCount" INTEGER NOT NULL DEFAULT 1,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Shipment_salesOrderId_fkey" FOREIGN KEY ("salesOrderId") REFERENCES "SalesOrder" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "Shipment_shipmentNumber_key" ON "Shipment"("shipmentNumber");
CREATE INDEX "Shipment_salesOrderId_createdAt_idx" ON "Shipment"("salesOrderId", "createdAt");

View File

@@ -0,0 +1,36 @@
-- CreateTable
CREATE TABLE "PurchaseOrder" (
"id" TEXT NOT NULL PRIMARY KEY,
"documentNumber" TEXT NOT NULL,
"vendorId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"issueDate" DATETIME NOT NULL,
"taxPercent" REAL NOT NULL DEFAULT 0,
"freightAmount" REAL NOT NULL DEFAULT 0,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "PurchaseOrder_vendorId_fkey" FOREIGN KEY ("vendorId") REFERENCES "Vendor" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "PurchaseOrderLine" (
"id" TEXT NOT NULL PRIMARY KEY,
"purchaseOrderId" TEXT NOT NULL,
"itemId" TEXT NOT NULL,
"description" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"unitCost" REAL NOT NULL,
"position" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "PurchaseOrderLine_purchaseOrderId_fkey" FOREIGN KEY ("purchaseOrderId") REFERENCES "PurchaseOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "PurchaseOrderLine_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "PurchaseOrder_documentNumber_key" ON "PurchaseOrder"("documentNumber");
-- CreateIndex
CREATE INDEX "PurchaseOrderLine_purchaseOrderId_position_idx" ON "PurchaseOrderLine"("purchaseOrderId", "position");

View File

@@ -0,0 +1,34 @@
CREATE TABLE "PurchaseReceipt" (
"id" TEXT NOT NULL PRIMARY KEY,
"receiptNumber" TEXT NOT NULL,
"purchaseOrderId" TEXT NOT NULL,
"warehouseId" TEXT NOT NULL,
"locationId" TEXT NOT NULL,
"receivedAt" DATETIME NOT NULL,
"notes" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "PurchaseReceipt_purchaseOrderId_fkey" FOREIGN KEY ("purchaseOrderId") REFERENCES "PurchaseOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "PurchaseReceipt_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "PurchaseReceipt_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "PurchaseReceipt_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
CREATE TABLE "PurchaseReceiptLine" (
"id" TEXT NOT NULL PRIMARY KEY,
"purchaseReceiptId" TEXT NOT NULL,
"purchaseOrderLineId" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "PurchaseReceiptLine_purchaseReceiptId_fkey" FOREIGN KEY ("purchaseReceiptId") REFERENCES "PurchaseReceipt" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "PurchaseReceiptLine_purchaseOrderLineId_fkey" FOREIGN KEY ("purchaseOrderLineId") REFERENCES "PurchaseOrderLine" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "PurchaseReceipt_receiptNumber_key" ON "PurchaseReceipt"("receiptNumber");
CREATE INDEX "PurchaseReceipt_purchaseOrderId_createdAt_idx" ON "PurchaseReceipt"("purchaseOrderId", "createdAt");
CREATE INDEX "PurchaseReceipt_warehouseId_createdAt_idx" ON "PurchaseReceipt"("warehouseId", "createdAt");
CREATE INDEX "PurchaseReceipt_locationId_createdAt_idx" ON "PurchaseReceipt"("locationId", "createdAt");
CREATE INDEX "PurchaseReceiptLine_purchaseReceiptId_idx" ON "PurchaseReceiptLine"("purchaseReceiptId");
CREATE INDEX "PurchaseReceiptLine_purchaseOrderLineId_idx" ON "PurchaseReceiptLine"("purchaseOrderLineId");

View File

@@ -0,0 +1,26 @@
CREATE TABLE "Project" (
"id" TEXT NOT NULL PRIMARY KEY,
"projectNumber" TEXT NOT NULL,
"name" TEXT NOT NULL,
"status" TEXT NOT NULL,
"priority" TEXT NOT NULL,
"customerId" TEXT NOT NULL,
"salesQuoteId" TEXT,
"salesOrderId" TEXT,
"shipmentId" TEXT,
"ownerId" TEXT,
"dueDate" DATETIME,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Project_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Project_salesQuoteId_fkey" FOREIGN KEY ("salesQuoteId") REFERENCES "SalesQuote" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Project_salesOrderId_fkey" FOREIGN KEY ("salesOrderId") REFERENCES "SalesOrder" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Project_shipmentId_fkey" FOREIGN KEY ("shipmentId") REFERENCES "Shipment" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Project_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "Project_projectNumber_key" ON "Project"("projectNumber");
CREATE INDEX "Project_customerId_createdAt_idx" ON "Project"("customerId", "createdAt");
CREATE INDEX "Project_ownerId_dueDate_idx" ON "Project"("ownerId", "dueDate");
CREATE INDEX "Project_status_priority_idx" ON "Project"("status", "priority");

View File

@@ -0,0 +1,76 @@
-- CreateTable
CREATE TABLE "WorkOrder" (
"id" TEXT NOT NULL PRIMARY KEY,
"workOrderNumber" TEXT NOT NULL,
"itemId" TEXT NOT NULL,
"projectId" TEXT,
"warehouseId" TEXT NOT NULL,
"locationId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"completedQuantity" INTEGER NOT NULL DEFAULT 0,
"dueDate" DATETIME,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "WorkOrder_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "WorkOrder_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "WorkOrder_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "WorkOrder_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "WorkOrderMaterialIssue" (
"id" TEXT NOT NULL PRIMARY KEY,
"workOrderId" TEXT NOT NULL,
"componentItemId" TEXT NOT NULL,
"warehouseId" TEXT NOT NULL,
"locationId" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"notes" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "WorkOrderMaterialIssue_workOrderId_fkey" FOREIGN KEY ("workOrderId") REFERENCES "WorkOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "WorkOrderMaterialIssue_componentItemId_fkey" FOREIGN KEY ("componentItemId") REFERENCES "InventoryItem" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "WorkOrderMaterialIssue_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "WorkOrderMaterialIssue_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "WorkOrderMaterialIssue_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "WorkOrderCompletion" (
"id" TEXT NOT NULL PRIMARY KEY,
"workOrderId" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"notes" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "WorkOrderCompletion_workOrderId_fkey" FOREIGN KEY ("workOrderId") REFERENCES "WorkOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "WorkOrderCompletion_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "WorkOrder_workOrderNumber_key" ON "WorkOrder"("workOrderNumber");
-- CreateIndex
CREATE INDEX "WorkOrder_itemId_createdAt_idx" ON "WorkOrder"("itemId", "createdAt");
-- CreateIndex
CREATE INDEX "WorkOrder_projectId_dueDate_idx" ON "WorkOrder"("projectId", "dueDate");
-- CreateIndex
CREATE INDEX "WorkOrder_status_dueDate_idx" ON "WorkOrder"("status", "dueDate");
-- CreateIndex
CREATE INDEX "WorkOrder_warehouseId_createdAt_idx" ON "WorkOrder"("warehouseId", "createdAt");
-- CreateIndex
CREATE INDEX "WorkOrderMaterialIssue_workOrderId_createdAt_idx" ON "WorkOrderMaterialIssue"("workOrderId", "createdAt");
-- CreateIndex
CREATE INDEX "WorkOrderMaterialIssue_componentItemId_createdAt_idx" ON "WorkOrderMaterialIssue"("componentItemId", "createdAt");
-- CreateIndex
CREATE INDEX "WorkOrderCompletion_workOrderId_createdAt_idx" ON "WorkOrderCompletion"("workOrderId", "createdAt");

View File

@@ -0,0 +1,25 @@
-- CreateTable
CREATE TABLE "AuthSession" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"lastSeenAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"ipAddress" TEXT,
"userAgent" TEXT,
"revokedAt" DATETIME,
"revokedById" TEXT,
"revokedReason" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "AuthSession_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "AuthSession_revokedById_fkey" FOREIGN KEY ("revokedById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE INDEX "AuthSession_userId_createdAt_idx" ON "AuthSession"("userId", "createdAt");
-- CreateIndex
CREATE INDEX "AuthSession_expiresAt_idx" ON "AuthSession"("expiresAt");
-- CreateIndex
CREATE INDEX "AuthSession_revokedAt_idx" ON "AuthSession"("revokedAt");

View File

@@ -0,0 +1,53 @@
-- AlterTable
ALTER TABLE "SalesQuote" ADD COLUMN "approvedAt" DATETIME;
ALTER TABLE "SalesQuote" ADD COLUMN "approvedById" TEXT;
-- AlterTable
ALTER TABLE "SalesOrder" ADD COLUMN "approvedAt" DATETIME;
ALTER TABLE "SalesOrder" ADD COLUMN "approvedById" TEXT;
-- CreateTable
CREATE TABLE "SalesQuoteRevision" (
"id" TEXT NOT NULL PRIMARY KEY,
"quoteId" TEXT NOT NULL,
"revisionNumber" INTEGER NOT NULL,
"reason" TEXT NOT NULL,
"snapshot" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesQuoteRevision_quoteId_fkey" FOREIGN KEY ("quoteId") REFERENCES "SalesQuote" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "SalesQuoteRevision_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "SalesOrderRevision" (
"id" TEXT NOT NULL PRIMARY KEY,
"orderId" TEXT NOT NULL,
"revisionNumber" INTEGER NOT NULL,
"reason" TEXT NOT NULL,
"snapshot" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "SalesOrderRevision_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "SalesOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "SalesOrderRevision_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE INDEX "SalesQuote_approvedById_idx" ON "SalesQuote"("approvedById");
-- CreateIndex
CREATE INDEX "SalesOrder_approvedById_idx" ON "SalesOrder"("approvedById");
-- CreateIndex
CREATE UNIQUE INDEX "SalesQuoteRevision_quoteId_revisionNumber_key" ON "SalesQuoteRevision"("quoteId", "revisionNumber");
-- CreateIndex
CREATE INDEX "SalesQuoteRevision_quoteId_createdAt_idx" ON "SalesQuoteRevision"("quoteId", "createdAt");
-- CreateIndex
CREATE UNIQUE INDEX "SalesOrderRevision_orderId_revisionNumber_key" ON "SalesOrderRevision"("orderId", "revisionNumber");
-- CreateIndex
CREATE INDEX "SalesOrderRevision_orderId_createdAt_idx" ON "SalesOrderRevision"("orderId", "createdAt");

View File

@@ -0,0 +1,49 @@
CREATE TABLE "ManufacturingStation" (
"id" TEXT NOT NULL PRIMARY KEY,
"code" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"queueDays" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
CREATE TABLE "InventoryItemOperation" (
"id" TEXT NOT NULL PRIMARY KEY,
"itemId" TEXT NOT NULL,
"stationId" TEXT NOT NULL,
"setupMinutes" INTEGER NOT NULL DEFAULT 0,
"runMinutesPerUnit" INTEGER NOT NULL DEFAULT 0,
"moveMinutes" INTEGER NOT NULL DEFAULT 0,
"notes" TEXT NOT NULL,
"position" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryItemOperation_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventoryItemOperation_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "ManufacturingStation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE "WorkOrderOperation" (
"id" TEXT NOT NULL PRIMARY KEY,
"workOrderId" TEXT NOT NULL,
"stationId" TEXT NOT NULL,
"sequence" INTEGER NOT NULL,
"setupMinutes" INTEGER NOT NULL DEFAULT 0,
"runMinutesPerUnit" INTEGER NOT NULL DEFAULT 0,
"moveMinutes" INTEGER NOT NULL DEFAULT 0,
"plannedMinutes" INTEGER NOT NULL DEFAULT 0,
"plannedStart" DATETIME NOT NULL,
"plannedEnd" DATETIME NOT NULL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "WorkOrderOperation_workOrderId_fkey" FOREIGN KEY ("workOrderId") REFERENCES "WorkOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "WorkOrderOperation_stationId_fkey" FOREIGN KEY ("stationId") REFERENCES "ManufacturingStation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE UNIQUE INDEX "ManufacturingStation_code_key" ON "ManufacturingStation"("code");
CREATE INDEX "InventoryItemOperation_itemId_position_idx" ON "InventoryItemOperation"("itemId", "position");
CREATE INDEX "InventoryItemOperation_stationId_idx" ON "InventoryItemOperation"("stationId");
CREATE INDEX "WorkOrderOperation_workOrderId_sequence_idx" ON "WorkOrderOperation"("workOrderId", "sequence");
CREATE INDEX "WorkOrderOperation_stationId_plannedStart_idx" ON "WorkOrderOperation"("stationId", "plannedStart");

View File

@@ -0,0 +1,43 @@
CREATE TABLE "InventoryTransfer" (
"id" TEXT NOT NULL PRIMARY KEY,
"itemId" TEXT NOT NULL,
"fromWarehouseId" TEXT NOT NULL,
"fromLocationId" TEXT NOT NULL,
"toWarehouseId" TEXT NOT NULL,
"toLocationId" TEXT NOT NULL,
"quantity" INTEGER NOT NULL,
"notes" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryTransfer_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventoryTransfer_fromWarehouseId_fkey" FOREIGN KEY ("fromWarehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransfer_fromLocationId_fkey" FOREIGN KEY ("fromLocationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransfer_toWarehouseId_fkey" FOREIGN KEY ("toWarehouseId") REFERENCES "Warehouse" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransfer_toLocationId_fkey" FOREIGN KEY ("toLocationId") REFERENCES "WarehouseLocation" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "InventoryTransfer_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
CREATE TABLE "InventoryReservation" (
"id" TEXT NOT NULL PRIMARY KEY,
"itemId" TEXT NOT NULL,
"warehouseId" TEXT,
"locationId" TEXT,
"workOrderId" TEXT,
"sourceType" TEXT NOT NULL,
"sourceId" TEXT,
"quantity" INTEGER NOT NULL,
"status" TEXT NOT NULL DEFAULT 'ACTIVE',
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryReservation_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "InventoryItem" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventoryReservation_warehouseId_fkey" FOREIGN KEY ("warehouseId") REFERENCES "Warehouse" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "InventoryReservation_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "WarehouseLocation" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "InventoryReservation_workOrderId_fkey" FOREIGN KEY ("workOrderId") REFERENCES "WorkOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX "InventoryTransfer_itemId_createdAt_idx" ON "InventoryTransfer"("itemId", "createdAt");
CREATE INDEX "InventoryReservation_itemId_status_createdAt_idx" ON "InventoryReservation"("itemId", "status", "createdAt");
CREATE INDEX "InventoryReservation_warehouseId_locationId_status_idx" ON "InventoryReservation"("warehouseId", "locationId", "status");
CREATE INDEX "InventoryReservation_workOrderId_status_idx" ON "InventoryReservation"("workOrderId", "status");

View File

@@ -0,0 +1,21 @@
-- CreateTable
CREATE TABLE "AuditEvent" (
"id" TEXT NOT NULL PRIMARY KEY,
"actorId" TEXT,
"entityType" TEXT NOT NULL,
"entityId" TEXT,
"action" TEXT NOT NULL,
"summary" TEXT NOT NULL,
"metadataJson" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "AuditEvent_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE INDEX "AuditEvent_createdAt_idx" ON "AuditEvent"("createdAt");
-- CreateIndex
CREATE INDEX "AuditEvent_entityType_entityId_createdAt_idx" ON "AuditEvent"("entityType", "entityId", "createdAt");
-- CreateIndex
CREATE INDEX "AuditEvent_actorId_createdAt_idx" ON "AuditEvent"("actorId", "createdAt");

View File

@@ -0,0 +1,13 @@
ALTER TABLE "InventoryItem" ADD COLUMN "preferredVendorId" TEXT;
ALTER TABLE "WorkOrder" ADD COLUMN "salesOrderId" TEXT;
ALTER TABLE "WorkOrder" ADD COLUMN "salesOrderLineId" TEXT;
ALTER TABLE "PurchaseOrderLine" ADD COLUMN "salesOrderId" TEXT;
ALTER TABLE "PurchaseOrderLine" ADD COLUMN "salesOrderLineId" TEXT;
CREATE INDEX "InventoryItem_preferredVendorId_idx" ON "InventoryItem"("preferredVendorId");
CREATE INDEX "WorkOrder_salesOrderId_dueDate_idx" ON "WorkOrder"("salesOrderId", "dueDate");
CREATE INDEX "WorkOrder_salesOrderLineId_dueDate_idx" ON "WorkOrder"("salesOrderLineId", "dueDate");
CREATE INDEX "PurchaseOrderLine_salesOrderId_position_idx" ON "PurchaseOrderLine"("salesOrderId", "position");
CREATE INDEX "PurchaseOrderLine_salesOrderLineId_position_idx" ON "PurchaseOrderLine"("salesOrderLineId", "position");

View File

@@ -0,0 +1,19 @@
-- CreateTable
CREATE TABLE "PurchaseOrderRevision" (
"id" TEXT NOT NULL PRIMARY KEY,
"purchaseOrderId" TEXT NOT NULL,
"revisionNumber" INTEGER NOT NULL,
"reason" TEXT NOT NULL,
"snapshot" TEXT NOT NULL,
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "PurchaseOrderRevision_purchaseOrderId_fkey" FOREIGN KEY ("purchaseOrderId") REFERENCES "PurchaseOrder" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "PurchaseOrderRevision_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "PurchaseOrderRevision_purchaseOrderId_revisionNumber_key" ON "PurchaseOrderRevision"("purchaseOrderId", "revisionNumber");
-- CreateIndex
CREATE INDEX "PurchaseOrderRevision_purchaseOrderId_createdAt_idx" ON "PurchaseOrderRevision"("purchaseOrderId", "createdAt");

View File

@@ -0,0 +1,78 @@
-- CreateTable
CREATE TABLE "InventorySkuFamily" (
"id" TEXT NOT NULL PRIMARY KEY,
"code" TEXT NOT NULL,
"sequenceCode" TEXT NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"nextSequenceNumber" INTEGER NOT NULL DEFAULT 1,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "InventorySkuNode" (
"id" TEXT NOT NULL PRIMARY KEY,
"familyId" TEXT NOT NULL,
"parentNodeId" TEXT,
"code" TEXT NOT NULL,
"label" TEXT NOT NULL,
"description" TEXT NOT NULL,
"path" TEXT NOT NULL,
"level" INTEGER NOT NULL,
"sortOrder" INTEGER NOT NULL DEFAULT 0,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventorySkuNode_familyId_fkey" FOREIGN KEY ("familyId") REFERENCES "InventorySkuFamily" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "InventorySkuNode_parentNodeId_fkey" FOREIGN KEY ("parentNodeId") REFERENCES "InventorySkuNode" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_InventoryItem" (
"id" TEXT NOT NULL PRIMARY KEY,
"sku" TEXT NOT NULL,
"skuFamilyId" TEXT,
"skuNodeId" TEXT,
"skuSequenceNumber" INTEGER,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"type" TEXT NOT NULL,
"status" TEXT NOT NULL,
"unitOfMeasure" TEXT NOT NULL,
"isSellable" BOOLEAN NOT NULL DEFAULT true,
"isPurchasable" BOOLEAN NOT NULL DEFAULT true,
"preferredVendorId" TEXT,
"defaultCost" REAL,
"defaultPrice" REAL,
"notes" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "InventoryItem_preferredVendorId_fkey" FOREIGN KEY ("preferredVendorId") REFERENCES "Vendor" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "InventoryItem_skuFamilyId_fkey" FOREIGN KEY ("skuFamilyId") REFERENCES "InventorySkuFamily" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "InventoryItem_skuNodeId_fkey" FOREIGN KEY ("skuNodeId") REFERENCES "InventorySkuNode" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_InventoryItem" ("createdAt", "defaultCost", "defaultPrice", "description", "id", "isPurchasable", "isSellable", "name", "notes", "preferredVendorId", "sku", "status", "type", "unitOfMeasure", "updatedAt") SELECT "createdAt", "defaultCost", "defaultPrice", "description", "id", "isPurchasable", "isSellable", "name", "notes", "preferredVendorId", "sku", "status", "type", "unitOfMeasure", "updatedAt" FROM "InventoryItem";
DROP TABLE "InventoryItem";
ALTER TABLE "new_InventoryItem" RENAME TO "InventoryItem";
CREATE UNIQUE INDEX "InventoryItem_sku_key" ON "InventoryItem"("sku");
CREATE INDEX "InventoryItem_preferredVendorId_idx" ON "InventoryItem"("preferredVendorId");
CREATE INDEX "InventoryItem_skuFamilyId_idx" ON "InventoryItem"("skuFamilyId");
CREATE INDEX "InventoryItem_skuNodeId_idx" ON "InventoryItem"("skuNodeId");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
-- CreateIndex
CREATE UNIQUE INDEX "InventorySkuFamily_code_key" ON "InventorySkuFamily"("code");
-- CreateIndex
CREATE UNIQUE INDEX "InventorySkuFamily_sequenceCode_key" ON "InventorySkuFamily"("sequenceCode");
-- CreateIndex
CREATE UNIQUE INDEX "InventorySkuNode_familyId_path_key" ON "InventorySkuNode"("familyId", "path");
-- CreateIndex
CREATE INDEX "InventorySkuNode_familyId_parentNodeId_sortOrder_idx" ON "InventorySkuNode"("familyId", "parentNodeId", "sortOrder");

View File

@@ -0,0 +1,2 @@
provider = "sqlite"

821
server/prisma/schema.prisma Normal file
View File

@@ -0,0 +1,821 @@
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-3.0.x"]
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
firstName String
lastName String
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userRoles UserRole[]
authSessions AuthSession[] @relation("AuthSessionUser")
revokedAuthSessions AuthSession[] @relation("AuthSessionRevokedBy")
contactEntries CrmContactEntry[]
inventoryTransactions InventoryTransaction[]
purchaseReceipts PurchaseReceipt[]
ownedProjects Project[] @relation("ProjectOwner")
workOrderMaterialIssues WorkOrderMaterialIssue[]
workOrderCompletions WorkOrderCompletion[]
approvedSalesQuotes SalesQuote[] @relation("SalesQuoteApprovedBy")
approvedSalesOrders SalesOrder[] @relation("SalesOrderApprovedBy")
salesQuoteRevisionsCreated SalesQuoteRevision[] @relation("SalesQuoteRevisionCreatedBy")
salesOrderRevisionsCreated SalesOrderRevision[] @relation("SalesOrderRevisionCreatedBy")
purchaseOrderRevisionsCreated PurchaseOrderRevision[]
inventoryTransfersCreated InventoryTransfer[] @relation("InventoryTransferCreatedBy")
auditEvents AuditEvent[]
}
model Role {
id String @id @default(cuid())
name String @unique
description String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userRoles UserRole[]
rolePermissions RolePermission[]
}
model Permission {
id String @id @default(cuid())
key String @unique
description String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
rolePermissions RolePermission[]
}
model UserRole {
userId String
roleId String
assignedAt DateTime @default(now())
assignedBy String?
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([userId, roleId])
}
model RolePermission {
roleId String
permissionId String
grantedAt DateTime @default(now())
permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
@@id([roleId, permissionId])
}
model AuthSession {
id String @id @default(cuid())
userId String
expiresAt DateTime
lastSeenAt DateTime @default(now())
ipAddress String?
userAgent String?
revokedAt DateTime?
revokedById String?
revokedReason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation("AuthSessionUser", fields: [userId], references: [id], onDelete: Cascade)
revokedBy User? @relation("AuthSessionRevokedBy", fields: [revokedById], references: [id], onDelete: SetNull)
@@index([userId, createdAt])
@@index([expiresAt])
@@index([revokedAt])
}
model CompanyProfile {
id String @id @default(cuid())
companyName String
legalName String
email String
phone String
website String
taxId String
addressLine1 String
addressLine2 String
city String
state String
postalCode String
country String
primaryColor String @default("#185ADB")
accentColor String @default("#00A6A6")
surfaceColor String @default("#F4F7FB")
fontFamily String @default("Manrope")
logoFileId String? @unique
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
logoFile FileAttachment? @relation("CompanyLogo", fields: [logoFileId], references: [id], onDelete: SetNull)
}
model FileAttachment {
id String @id @default(cuid())
originalName String
storedName String
mimeType String
sizeBytes Int
relativePath String
ownerType String
ownerId String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
companyLogoFor CompanyProfile? @relation("CompanyLogo")
}
model InventoryItem {
id String @id @default(cuid())
sku String @unique
skuFamilyId String?
skuNodeId String?
skuSequenceNumber Int?
name String
description String
type String
status String
unitOfMeasure String
isSellable Boolean @default(true)
isPurchasable Boolean @default(true)
preferredVendorId String?
defaultCost Float?
defaultPrice Float?
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bomLines InventoryBomLine[] @relation("InventoryBomParent")
usedInBomLines InventoryBomLine[] @relation("InventoryBomComponent")
inventoryTransactions InventoryTransaction[]
salesQuoteLines SalesQuoteLine[]
salesOrderLines SalesOrderLine[]
purchaseOrderLines PurchaseOrderLine[]
workOrders WorkOrder[]
workOrderMaterialIssues WorkOrderMaterialIssue[]
operations InventoryItemOperation[]
reservations InventoryReservation[]
transfers InventoryTransfer[]
preferredVendor Vendor? @relation(fields: [preferredVendorId], references: [id], onDelete: SetNull)
skuFamily InventorySkuFamily? @relation(fields: [skuFamilyId], references: [id], onDelete: SetNull)
skuNode InventorySkuNode? @relation(fields: [skuNodeId], references: [id], onDelete: SetNull)
@@index([preferredVendorId])
@@index([skuFamilyId])
@@index([skuNodeId])
}
model InventorySkuFamily {
id String @id @default(cuid())
code String @unique
sequenceCode String @unique
name String
description String
nextSequenceNumber Int @default(1)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
nodes InventorySkuNode[]
items InventoryItem[]
}
model InventorySkuNode {
id String @id @default(cuid())
familyId String
parentNodeId String?
code String
label String
description String
path String
level Int
sortOrder Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
family InventorySkuFamily @relation(fields: [familyId], references: [id], onDelete: Cascade)
parentNode InventorySkuNode? @relation("InventorySkuNodeTree", fields: [parentNodeId], references: [id], onDelete: Cascade)
childNodes InventorySkuNode[] @relation("InventorySkuNodeTree")
items InventoryItem[]
@@unique([familyId, path])
@@index([familyId, parentNodeId, sortOrder])
}
model Warehouse {
id String @id @default(cuid())
code String @unique
name String
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
locations WarehouseLocation[]
inventoryTransactions InventoryTransaction[]
purchaseReceipts PurchaseReceipt[]
workOrders WorkOrder[]
workOrderMaterialIssues WorkOrderMaterialIssue[]
reservations InventoryReservation[]
transferSources InventoryTransfer[] @relation("InventoryTransferFromWarehouse")
transferDestinations InventoryTransfer[] @relation("InventoryTransferToWarehouse")
}
model Customer {
id String @id @default(cuid())
name String
email String
phone String
addressLine1 String
addressLine2 String
city String
state String
postalCode String
country String
status String @default("ACTIVE")
lifecycleStage String @default("ACTIVE")
isReseller Boolean @default(false)
resellerDiscountPercent Float @default(0)
parentCustomerId String?
paymentTerms String?
currencyCode String? @default("USD")
taxExempt Boolean @default(false)
creditHold Boolean @default(false)
preferredAccount Boolean @default(false)
strategicAccount Boolean @default(false)
requiresApproval Boolean @default(false)
blockedAccount Boolean @default(false)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contactEntries CrmContactEntry[]
contacts CrmContact[]
parentCustomer Customer? @relation("CustomerHierarchy", fields: [parentCustomerId], references: [id], onDelete: SetNull)
childCustomers Customer[] @relation("CustomerHierarchy")
salesQuotes SalesQuote[]
salesOrders SalesOrder[]
projects Project[]
}
model InventoryBomLine {
id String @id @default(cuid())
parentItemId String
componentItemId String
quantity Float
unitOfMeasure String
notes String
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parentItem InventoryItem @relation("InventoryBomParent", fields: [parentItemId], references: [id], onDelete: Cascade)
componentItem InventoryItem @relation("InventoryBomComponent", fields: [componentItemId], references: [id], onDelete: Restrict)
@@index([parentItemId, position])
@@index([componentItemId])
}
model WarehouseLocation {
id String @id @default(cuid())
warehouseId String
code String
name String
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
warehouse Warehouse @relation(fields: [warehouseId], references: [id], onDelete: Cascade)
inventoryTransactions InventoryTransaction[]
purchaseReceipts PurchaseReceipt[]
workOrders WorkOrder[]
workOrderMaterialIssues WorkOrderMaterialIssue[]
reservations InventoryReservation[]
transferSourceLocations InventoryTransfer[] @relation("InventoryTransferFromLocation")
transferDestinationLocations InventoryTransfer[] @relation("InventoryTransferToLocation")
@@unique([warehouseId, code])
@@index([warehouseId])
}
model InventoryTransaction {
id String @id @default(cuid())
itemId String
warehouseId String
locationId String
transactionType String
quantity Int
reference String
notes String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
warehouse Warehouse @relation(fields: [warehouseId], references: [id], onDelete: Restrict)
location WarehouseLocation @relation(fields: [locationId], references: [id], onDelete: Restrict)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
@@index([itemId, createdAt])
@@index([warehouseId, createdAt])
@@index([locationId, createdAt])
}
model InventoryTransfer {
id String @id @default(cuid())
itemId String
fromWarehouseId String
fromLocationId String
toWarehouseId String
toLocationId String
quantity Int
notes String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
fromWarehouse Warehouse @relation("InventoryTransferFromWarehouse", fields: [fromWarehouseId], references: [id], onDelete: Restrict)
fromLocation WarehouseLocation @relation("InventoryTransferFromLocation", fields: [fromLocationId], references: [id], onDelete: Restrict)
toWarehouse Warehouse @relation("InventoryTransferToWarehouse", fields: [toWarehouseId], references: [id], onDelete: Restrict)
toLocation WarehouseLocation @relation("InventoryTransferToLocation", fields: [toLocationId], references: [id], onDelete: Restrict)
createdBy User? @relation("InventoryTransferCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([itemId, createdAt])
}
model InventoryReservation {
id String @id @default(cuid())
itemId String
warehouseId String?
locationId String?
workOrderId String?
sourceType String
sourceId String?
quantity Int
status String @default("ACTIVE")
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
warehouse Warehouse? @relation(fields: [warehouseId], references: [id], onDelete: SetNull)
location WarehouseLocation? @relation(fields: [locationId], references: [id], onDelete: SetNull)
workOrder WorkOrder? @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
@@index([itemId, status, createdAt])
@@index([warehouseId, locationId, status])
@@index([workOrderId, status])
}
model Vendor {
id String @id @default(cuid())
name String
email String
phone String
addressLine1 String
addressLine2 String
city String
state String
postalCode String
country String
status String @default("ACTIVE")
lifecycleStage String @default("ACTIVE")
paymentTerms String?
currencyCode String? @default("USD")
taxExempt Boolean @default(false)
creditHold Boolean @default(false)
preferredAccount Boolean @default(false)
strategicAccount Boolean @default(false)
requiresApproval Boolean @default(false)
blockedAccount Boolean @default(false)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contactEntries CrmContactEntry[]
contacts CrmContact[]
purchaseOrders PurchaseOrder[]
preferredSupplyItems InventoryItem[]
}
model CrmContactEntry {
id String @id @default(cuid())
type String @default("NOTE")
summary String
body String
contactAt DateTime
customerId String?
vendorId String?
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer? @relation(fields: [customerId], references: [id], onDelete: Cascade)
vendor Vendor? @relation(fields: [vendorId], references: [id], onDelete: Cascade)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
}
model CrmContact {
id String @id @default(cuid())
fullName String
role String @default("OTHER")
email String
phone String
isPrimary Boolean @default(false)
customerId String?
vendorId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer? @relation(fields: [customerId], references: [id], onDelete: Cascade)
vendor Vendor? @relation(fields: [vendorId], references: [id], onDelete: Cascade)
}
model SalesQuote {
id String @id @default(cuid())
documentNumber String @unique
customerId String
status String
issueDate DateTime
expiresAt DateTime?
approvedAt DateTime?
approvedById String?
discountPercent Float @default(0)
taxPercent Float @default(0)
freightAmount Float @default(0)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict)
approvedBy User? @relation("SalesQuoteApprovedBy", fields: [approvedById], references: [id], onDelete: SetNull)
lines SalesQuoteLine[]
projects Project[]
revisions SalesQuoteRevision[]
}
model SalesQuoteLine {
id String @id @default(cuid())
quoteId String
itemId String
description String
quantity Int
unitOfMeasure String
unitPrice Float
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
quote SalesQuote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
@@index([quoteId, position])
}
model SalesOrder {
id String @id @default(cuid())
documentNumber String @unique
customerId String
status String
issueDate DateTime
approvedAt DateTime?
approvedById String?
discountPercent Float @default(0)
taxPercent Float @default(0)
freightAmount Float @default(0)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict)
approvedBy User? @relation("SalesOrderApprovedBy", fields: [approvedById], references: [id], onDelete: SetNull)
lines SalesOrderLine[]
shipments Shipment[]
projects Project[]
revisions SalesOrderRevision[]
workOrders WorkOrder[]
purchaseOrderLines PurchaseOrderLine[]
}
model SalesOrderLine {
id String @id @default(cuid())
orderId String
itemId String
description String
quantity Int
unitOfMeasure String
unitPrice Float
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
order SalesOrder @relation(fields: [orderId], references: [id], onDelete: Cascade)
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
workOrders WorkOrder[]
purchaseOrderLines PurchaseOrderLine[]
@@index([orderId, position])
}
model SalesQuoteRevision {
id String @id @default(cuid())
quoteId String
revisionNumber Int
reason String
snapshot String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
quote SalesQuote @relation(fields: [quoteId], references: [id], onDelete: Cascade)
createdBy User? @relation("SalesQuoteRevisionCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@unique([quoteId, revisionNumber])
@@index([quoteId, createdAt])
}
model SalesOrderRevision {
id String @id @default(cuid())
orderId String
revisionNumber Int
reason String
snapshot String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
order SalesOrder @relation(fields: [orderId], references: [id], onDelete: Cascade)
createdBy User? @relation("SalesOrderRevisionCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@unique([orderId, revisionNumber])
@@index([orderId, createdAt])
}
model Shipment {
id String @id @default(cuid())
shipmentNumber String @unique
salesOrderId String
status String
shipDate DateTime?
carrier String
serviceLevel String
trackingNumber String
packageCount Int @default(1)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
salesOrder SalesOrder @relation(fields: [salesOrderId], references: [id], onDelete: Restrict)
projects Project[]
@@index([salesOrderId, createdAt])
}
model Project {
id String @id @default(cuid())
projectNumber String @unique
name String
status String
priority String
customerId String
salesQuoteId String?
salesOrderId String?
shipmentId String?
ownerId String?
dueDate DateTime?
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
customer Customer @relation(fields: [customerId], references: [id], onDelete: Restrict)
salesQuote SalesQuote? @relation(fields: [salesQuoteId], references: [id], onDelete: SetNull)
salesOrder SalesOrder? @relation(fields: [salesOrderId], references: [id], onDelete: SetNull)
shipment Shipment? @relation(fields: [shipmentId], references: [id], onDelete: SetNull)
owner User? @relation("ProjectOwner", fields: [ownerId], references: [id], onDelete: SetNull)
workOrders WorkOrder[]
@@index([customerId, createdAt])
@@index([ownerId, dueDate])
@@index([status, priority])
}
model WorkOrder {
id String @id @default(cuid())
workOrderNumber String @unique
itemId String
projectId String?
salesOrderId String?
salesOrderLineId String?
warehouseId String
locationId String
status String
quantity Int
completedQuantity Int @default(0)
dueDate DateTime?
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
salesOrder SalesOrder? @relation(fields: [salesOrderId], references: [id], onDelete: SetNull)
salesOrderLine SalesOrderLine? @relation(fields: [salesOrderLineId], references: [id], onDelete: SetNull)
warehouse Warehouse @relation(fields: [warehouseId], references: [id], onDelete: Restrict)
location WarehouseLocation @relation(fields: [locationId], references: [id], onDelete: Restrict)
operations WorkOrderOperation[]
materialIssues WorkOrderMaterialIssue[]
completions WorkOrderCompletion[]
reservations InventoryReservation[]
@@index([itemId, createdAt])
@@index([projectId, dueDate])
@@index([salesOrderId, dueDate])
@@index([salesOrderLineId, dueDate])
@@index([status, dueDate])
@@index([warehouseId, createdAt])
}
model ManufacturingStation {
id String @id @default(cuid())
code String @unique
name String
description String
queueDays Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
itemOperations InventoryItemOperation[]
workOrderOperations WorkOrderOperation[]
}
model InventoryItemOperation {
id String @id @default(cuid())
itemId String
stationId String
setupMinutes Int @default(0)
runMinutesPerUnit Int @default(0)
moveMinutes Int @default(0)
notes String
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
station ManufacturingStation @relation(fields: [stationId], references: [id], onDelete: Restrict)
@@index([itemId, position])
@@index([stationId])
}
model WorkOrderOperation {
id String @id @default(cuid())
workOrderId String
stationId String
sequence Int
setupMinutes Int @default(0)
runMinutesPerUnit Int @default(0)
moveMinutes Int @default(0)
plannedMinutes Int @default(0)
plannedStart DateTime
plannedEnd DateTime
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
workOrder WorkOrder @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
station ManufacturingStation @relation(fields: [stationId], references: [id], onDelete: Restrict)
@@index([workOrderId, sequence])
@@index([stationId, plannedStart])
}
model WorkOrderMaterialIssue {
id String @id @default(cuid())
workOrderId String
componentItemId String
warehouseId String
locationId String
quantity Int
notes String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
workOrder WorkOrder @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
componentItem InventoryItem @relation(fields: [componentItemId], references: [id], onDelete: Restrict)
warehouse Warehouse @relation(fields: [warehouseId], references: [id], onDelete: Restrict)
location WarehouseLocation @relation(fields: [locationId], references: [id], onDelete: Restrict)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
@@index([workOrderId, createdAt])
@@index([componentItemId, createdAt])
}
model WorkOrderCompletion {
id String @id @default(cuid())
workOrderId String
quantity Int
notes String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
workOrder WorkOrder @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
@@index([workOrderId, createdAt])
}
model PurchaseOrder {
id String @id @default(cuid())
documentNumber String @unique
vendorId String
status String
issueDate DateTime
taxPercent Float @default(0)
freightAmount Float @default(0)
notes String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
vendor Vendor @relation(fields: [vendorId], references: [id], onDelete: Restrict)
lines PurchaseOrderLine[]
receipts PurchaseReceipt[]
revisions PurchaseOrderRevision[]
}
model PurchaseOrderLine {
id String @id @default(cuid())
purchaseOrderId String
itemId String
salesOrderId String?
salesOrderLineId String?
description String
quantity Int
unitOfMeasure String
unitCost Float
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
item InventoryItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
salesOrder SalesOrder? @relation(fields: [salesOrderId], references: [id], onDelete: SetNull)
salesOrderLine SalesOrderLine? @relation(fields: [salesOrderLineId], references: [id], onDelete: SetNull)
receiptLines PurchaseReceiptLine[]
@@index([purchaseOrderId, position])
@@index([salesOrderId, position])
@@index([salesOrderLineId, position])
}
model PurchaseReceipt {
id String @id @default(cuid())
receiptNumber String @unique
purchaseOrderId String
warehouseId String
locationId String
receivedAt DateTime
notes String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
warehouse Warehouse @relation(fields: [warehouseId], references: [id], onDelete: Restrict)
location WarehouseLocation @relation(fields: [locationId], references: [id], onDelete: Restrict)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
lines PurchaseReceiptLine[]
@@index([purchaseOrderId, createdAt])
@@index([warehouseId, createdAt])
@@index([locationId, createdAt])
}
model PurchaseReceiptLine {
id String @id @default(cuid())
purchaseReceiptId String
purchaseOrderLineId String
quantity Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
purchaseReceipt PurchaseReceipt @relation(fields: [purchaseReceiptId], references: [id], onDelete: Cascade)
purchaseOrderLine PurchaseOrderLine @relation(fields: [purchaseOrderLineId], references: [id], onDelete: Restrict)
@@index([purchaseReceiptId])
@@index([purchaseOrderLineId])
}
model PurchaseOrderRevision {
id String @id @default(cuid())
purchaseOrderId String
revisionNumber Int
reason String
snapshot String
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
@@unique([purchaseOrderId, revisionNumber])
@@index([purchaseOrderId, createdAt])
}
model AuditEvent {
id String @id @default(cuid())
actorId String?
entityType String
entityId String?
action String
summary String
metadataJson String
createdAt DateTime @default(now())
actor User? @relation(fields: [actorId], references: [id], onDelete: SetNull)
@@index([createdAt])
@@index([entityType, entityId, createdAt])
@@index([actorId, createdAt])
}