feat(db): reshape user and inventory schema
This commit is contained in:
@@ -1,66 +1,111 @@
|
|||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'MANAGER', 'STAFF', 'VIEWER');
|
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'MANAGER', 'STAFF', 'VIEWER');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "UserStatus" AS ENUM ('INVITED', 'ACTIVE', 'SUSPENDED', 'DISABLED');
|
||||||
|
|
||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "PersonDepartment" AS ENUM ('IT', 'ENGINEERING', 'LOGISTICS', 'TRAFFIC', 'DRIVER', 'ADMINISTRATION', 'SALES', 'OTHER');
|
CREATE TYPE "PersonDepartment" AS ENUM ('IT', 'ENGINEERING', 'LOGISTICS', 'TRAFFIC', 'DRIVER', 'ADMINISTRATION', 'SALES', 'OTHER');
|
||||||
|
|
||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "ItemStatus" AS ENUM ('AVAILABLE', 'ASSIGNED', 'RESERVED', 'IN_REPAIR', 'BROKEN', 'STOLEN', 'DISPOSED');
|
CREATE TYPE "ItemTrackingType" AS ENUM ('QUANTITY', 'SERIALIZED');
|
||||||
|
|
||||||
-- CreateEnum
|
-- CreateEnum
|
||||||
CREATE TYPE "MovementType" AS ENUM ('IN', 'OUT', 'ASSIGNMENT', 'RETURN', 'ADJUSTMENT', 'DELETED');
|
CREATE TYPE "ItemStatus" AS ENUM ('ACTIVE', 'DISCONTINUED', 'ARCHIVED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "AssetStatus" AS ENUM ('AVAILABLE', 'ASSIGNED', 'IN_REPAIR', 'BROKEN', 'LOST', 'STOLEN', 'DISPOSED', 'RETIRED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "AssignmentStatus" AS ENUM ('OPEN', 'PARTIALLY_RETURNED', 'RETURNED', 'CANCELLED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "InventoryMovementType" AS ENUM ('RECEIPT', 'ISSUE', 'ASSIGNMENT', 'RETURN', 'ADJUSTMENT', 'STATUS_CHANGE', 'DISPOSAL', 'INITIAL_LOAD');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "InventoryMovementReason" AS ENUM ('PURCHASE', 'MANUAL_ENTRY', 'EMPLOYEE_ASSIGNMENT', 'EMPLOYEE_RETURN', 'INVENTORY_CORRECTION', 'DAMAGE', 'REPAIR', 'REPAIR_RETURN', 'LOSS', 'THEFT', 'DISPOSAL', 'INITIAL_LOAD', 'OTHER');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "StockAlertStatus" AS ENUM ('OPEN', 'ACKNOWLEDGED', 'RESOLVED');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "StockAlertTrigger" AS ENUM ('BELOW_MINIMUM', 'OUT_OF_STOCK');
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "User" (
|
CREATE TABLE "User" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"name" TEXT NOT NULL,
|
"name" TEXT NOT NULL,
|
||||||
"email" TEXT NOT NULL,
|
"email" TEXT NOT NULL,
|
||||||
"password" TEXT NOT NULL,
|
"emailNormalized" TEXT NOT NULL,
|
||||||
|
"passwordHash" TEXT,
|
||||||
"role" "UserRole" NOT NULL DEFAULT 'STAFF',
|
"role" "UserRole" NOT NULL DEFAULT 'STAFF',
|
||||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
"status" "UserStatus" NOT NULL DEFAULT 'INVITED',
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
"invitedAt" TIMESTAMP(3),
|
||||||
|
"activatedAt" TIMESTAMP(3),
|
||||||
|
"passwordChangedAt" TIMESTAMP(3),
|
||||||
|
"lastLoginAt" TIMESTAMP(3),
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "UserInvitation" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"userId" UUID NOT NULL,
|
||||||
|
"tokenHash" TEXT NOT NULL,
|
||||||
|
"invitedById" UUID NOT NULL,
|
||||||
|
"email" TEXT NOT NULL,
|
||||||
|
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"acceptedAt" TIMESTAMP(3),
|
||||||
|
"revokedAt" TIMESTAMP(3),
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "UserInvitation_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Person" (
|
CREATE TABLE "Person" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"firstName" TEXT NOT NULL,
|
"firstName" TEXT NOT NULL,
|
||||||
"lastName" TEXT NOT NULL,
|
"lastName" TEXT NOT NULL,
|
||||||
"department" "PersonDepartment",
|
"department" "PersonDepartment",
|
||||||
"email" TEXT,
|
"email" TEXT,
|
||||||
"phone" TEXT,
|
"phone" TEXT,
|
||||||
"userId" TEXT,
|
"userId" UUID,
|
||||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
|
||||||
CONSTRAINT "Person_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "Person_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Category" (
|
CREATE TABLE "Category" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"name" TEXT NOT NULL,
|
"name" TEXT NOT NULL,
|
||||||
"description" TEXT,
|
"description" TEXT,
|
||||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
|
||||||
CONSTRAINT "Category_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "Category_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Item" (
|
CREATE TABLE "Item" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
|
"sku" TEXT NOT NULL,
|
||||||
"name" TEXT NOT NULL,
|
"name" TEXT NOT NULL,
|
||||||
"description" TEXT,
|
"description" TEXT,
|
||||||
"categoryId" TEXT NOT NULL,
|
"trackingType" "ItemTrackingType" NOT NULL,
|
||||||
|
"status" "ItemStatus" NOT NULL DEFAULT 'ACTIVE',
|
||||||
|
"categoryId" UUID NOT NULL,
|
||||||
"stock" INTEGER NOT NULL DEFAULT 0,
|
"stock" INTEGER NOT NULL DEFAULT 0,
|
||||||
"minStock" INTEGER,
|
"minStock" INTEGER,
|
||||||
"maxStock" INTEGER,
|
"targetStock" INTEGER,
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
"deletedAt" TIMESTAMP(3),
|
"deletedAt" TIMESTAMP(3),
|
||||||
@@ -70,29 +115,38 @@ CREATE TABLE "Item" (
|
|||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Asset" (
|
CREATE TABLE "Asset" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"itemId" TEXT,
|
"assetTag" TEXT,
|
||||||
"serialNumber" TEXT NOT NULL,
|
"serialNumber" TEXT NOT NULL,
|
||||||
|
"itemId" UUID NOT NULL,
|
||||||
|
"status" "AssetStatus" NOT NULL DEFAULT 'AVAILABLE',
|
||||||
|
"manufacturer" TEXT,
|
||||||
|
"model" TEXT,
|
||||||
"deliveryNote" TEXT,
|
"deliveryNote" TEXT,
|
||||||
"status" "ItemStatus" NOT NULL DEFAULT 'AVAILABLE',
|
"invoiceNumber" TEXT,
|
||||||
|
"purchaseDate" TIMESTAMP(3),
|
||||||
|
"purchasePrice" DECIMAL(12,2),
|
||||||
|
"warrantyEndsAt" TIMESTAMP(3),
|
||||||
"notes" TEXT,
|
"notes" TEXT,
|
||||||
|
"retiredAt" TIMESTAMP(3),
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
"deletedAt" TIMESTAMP(3),
|
||||||
|
|
||||||
CONSTRAINT "Asset_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "Asset_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Assignment" (
|
CREATE TABLE "Assignment" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"quantity" INTEGER,
|
"personId" UUID NOT NULL,
|
||||||
|
"status" "AssignmentStatus" NOT NULL DEFAULT 'OPEN',
|
||||||
|
"assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"dueAt" TIMESTAMP(3),
|
||||||
|
"closedAt" TIMESTAMP(3),
|
||||||
"notes" TEXT,
|
"notes" TEXT,
|
||||||
"itemId" TEXT,
|
"createdById" UUID NOT NULL,
|
||||||
"assetId" TEXT,
|
"closedById" UUID,
|
||||||
"personId" TEXT,
|
|
||||||
"assignmentDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"returnDate" TIMESTAMP(3),
|
|
||||||
"createdBy" TEXT NOT NULL,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
@@ -100,29 +154,135 @@ CREATE TABLE "Assignment" (
|
|||||||
);
|
);
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "Movement" (
|
CREATE TABLE "AssignmentStockLine" (
|
||||||
"id" TEXT NOT NULL,
|
"id" UUID NOT NULL,
|
||||||
"type" "MovementType" NOT NULL DEFAULT 'IN',
|
"assignmentId" UUID NOT NULL,
|
||||||
|
"itemId" UUID NOT NULL,
|
||||||
"quantity" INTEGER NOT NULL,
|
"quantity" INTEGER NOT NULL,
|
||||||
"details" TEXT,
|
"returnedQuantity" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"notes" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "AssignmentStockLine_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "AssignmentStockReturn" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"assignmentLineId" UUID NOT NULL,
|
||||||
|
"quantity" INTEGER NOT NULL,
|
||||||
|
"returnedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"receivedById" UUID NOT NULL,
|
||||||
"notes" TEXT,
|
"notes" TEXT,
|
||||||
"itemId" TEXT,
|
|
||||||
"assetId" TEXT,
|
|
||||||
"previousStock" INTEGER,
|
|
||||||
"newStock" INTEGER,
|
|
||||||
"personId" TEXT,
|
|
||||||
"assignmentId" TEXT,
|
|
||||||
"userId" TEXT NOT NULL,
|
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
CONSTRAINT "Movement_pkey" PRIMARY KEY ("id")
|
CONSTRAINT "AssignmentStockReturn_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "AssignmentAssetLine" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"assignmentId" UUID NOT NULL,
|
||||||
|
"assetId" UUID NOT NULL,
|
||||||
|
"assignedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"returnedAt" TIMESTAMP(3),
|
||||||
|
"returnedById" UUID,
|
||||||
|
"returnStatus" "AssetStatus",
|
||||||
|
"notes" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "AssignmentAssetLine_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "InventoryMovement" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"type" "InventoryMovementType" NOT NULL,
|
||||||
|
"reason" "InventoryMovementReason" NOT NULL,
|
||||||
|
"assignmentId" UUID,
|
||||||
|
"reference" TEXT,
|
||||||
|
"details" TEXT,
|
||||||
|
"notes" TEXT,
|
||||||
|
"performedById" UUID NOT NULL,
|
||||||
|
"occurredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "InventoryMovement_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "StockMovementLine" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"movementId" UUID NOT NULL,
|
||||||
|
"itemId" UUID NOT NULL,
|
||||||
|
"stockDelta" INTEGER NOT NULL,
|
||||||
|
"previousStock" INTEGER NOT NULL,
|
||||||
|
"newStock" INTEGER NOT NULL,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "StockMovementLine_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "AssetMovementLine" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"movementId" UUID NOT NULL,
|
||||||
|
"assetId" UUID NOT NULL,
|
||||||
|
"previousStatus" "AssetStatus",
|
||||||
|
"newStatus" "AssetStatus" NOT NULL,
|
||||||
|
"notes" TEXT,
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "AssetMovementLine_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "StockAlert" (
|
||||||
|
"id" UUID NOT NULL,
|
||||||
|
"itemId" UUID NOT NULL,
|
||||||
|
"trigger" "StockAlertTrigger" NOT NULL,
|
||||||
|
"status" "StockAlertStatus" NOT NULL DEFAULT 'OPEN',
|
||||||
|
"availableStock" INTEGER NOT NULL,
|
||||||
|
"minimumStock" INTEGER NOT NULL,
|
||||||
|
"suggestedPurchase" INTEGER,
|
||||||
|
"triggeredAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"acknowledgedAt" TIMESTAMP(3),
|
||||||
|
"acknowledgedById" UUID,
|
||||||
|
"resolvedAt" TIMESTAMP(3),
|
||||||
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "StockAlert_pkey" PRIMARY KEY ("id")
|
||||||
);
|
);
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
CREATE UNIQUE INDEX "User_emailNormalized_key" ON "User"("emailNormalized");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Person_email_key" ON "Person"("email");
|
CREATE INDEX "User_status_idx" ON "User"("status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "User_deletedAt_idx" ON "User"("deletedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "User_createdAt_idx" ON "User"("createdAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "UserInvitation_tokenHash_key" ON "UserInvitation"("tokenHash");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "UserInvitation_userId_idx" ON "UserInvitation"("userId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "UserInvitation_expiresAt_idx" ON "UserInvitation"("expiresAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "UserInvitation_acceptedAt_idx" ON "UserInvitation"("acceptedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "UserInvitation_revokedAt_idx" ON "UserInvitation"("revokedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Person_userId_key" ON "Person"("userId");
|
CREATE UNIQUE INDEX "Person_userId_key" ON "Person"("userId");
|
||||||
@@ -131,61 +291,127 @@ CREATE UNIQUE INDEX "Person_userId_key" ON "Person"("userId");
|
|||||||
CREATE INDEX "Person_lastName_firstName_idx" ON "Person"("lastName", "firstName");
|
CREATE INDEX "Person_lastName_firstName_idx" ON "Person"("lastName", "firstName");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Person_department_idx" ON "Person"("department");
|
CREATE INDEX "Person_department_deletedAt_idx" ON "Person"("department", "deletedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Person_deletedAt_idx" ON "Person"("deletedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Category_name_key" ON "Category"("name");
|
CREATE UNIQUE INDEX "Category_name_key" ON "Category"("name");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Category_name_idx" ON "Category"("name");
|
CREATE INDEX "Category_deletedAt_idx" ON "Category"("deletedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Item_name_key" ON "Item"("name");
|
CREATE UNIQUE INDEX "Item_sku_key" ON "Item"("sku");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Item_categoryId_idx" ON "Item"("categoryId");
|
CREATE INDEX "Item_categoryId_status_idx" ON "Item"("categoryId", "status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Item_trackingType_status_idx" ON "Item"("trackingType", "status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Item_name_idx" ON "Item"("name");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "Item_deletedAt_idx" ON "Item"("deletedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "Asset_assetTag_key" ON "Asset"("assetTag");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Asset_serialNumber_key" ON "Asset"("serialNumber");
|
CREATE UNIQUE INDEX "Asset_serialNumber_key" ON "Asset"("serialNumber");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Asset_serialNumber_idx" ON "Asset"("serialNumber");
|
CREATE INDEX "Asset_itemId_status_idx" ON "Asset"("itemId", "status");
|
||||||
|
|
||||||
-- CreateIndex
|
|
||||||
CREATE INDEX "Asset_itemId_idx" ON "Asset"("itemId");
|
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Asset_status_idx" ON "Asset"("status");
|
CREATE INDEX "Asset_status_idx" ON "Asset"("status");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE UNIQUE INDEX "Assignment_assetId_key" ON "Assignment"("assetId");
|
CREATE INDEX "Asset_createdAt_idx" ON "Asset"("createdAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Assignment_itemId_idx" ON "Assignment"("itemId");
|
CREATE INDEX "Asset_deletedAt_idx" ON "Asset"("deletedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Assignment_assetId_idx" ON "Assignment"("assetId");
|
CREATE INDEX "Assignment_personId_status_idx" ON "Assignment"("personId", "status");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Assignment_personId_idx" ON "Assignment"("personId");
|
CREATE INDEX "Assignment_personId_assignedAt_idx" ON "Assignment"("personId", "assignedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Assignment_createdBy_idx" ON "Assignment"("createdBy");
|
CREATE INDEX "Assignment_status_assignedAt_idx" ON "Assignment"("status", "assignedAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Movement_itemId_idx" ON "Movement"("itemId");
|
CREATE INDEX "Assignment_dueAt_idx" ON "Assignment"("dueAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Movement_assetId_idx" ON "Movement"("assetId");
|
CREATE INDEX "Assignment_createdById_createdAt_idx" ON "Assignment"("createdById", "createdAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Movement_personId_idx" ON "Movement"("personId");
|
CREATE INDEX "AssignmentStockLine_assignmentId_idx" ON "AssignmentStockLine"("assignmentId");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Movement_type_idx" ON "Movement"("type");
|
CREATE INDEX "AssignmentStockLine_itemId_createdAt_idx" ON "AssignmentStockLine"("itemId", "createdAt");
|
||||||
|
|
||||||
-- CreateIndex
|
-- CreateIndex
|
||||||
CREATE INDEX "Movement_userId_idx" ON "Movement"("userId");
|
CREATE INDEX "AssignmentStockReturn_assignmentLineId_returnedAt_idx" ON "AssignmentStockReturn"("assignmentLineId", "returnedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "AssignmentStockReturn_receivedById_returnedAt_idx" ON "AssignmentStockReturn"("receivedById", "returnedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "AssignmentAssetLine_assignmentId_idx" ON "AssignmentAssetLine"("assignmentId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "AssignmentAssetLine_assetId_assignedAt_idx" ON "AssignmentAssetLine"("assetId", "assignedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "AssignmentAssetLine_returnedAt_idx" ON "AssignmentAssetLine"("returnedAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "InventoryMovement_type_occurredAt_idx" ON "InventoryMovement"("type", "occurredAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "InventoryMovement_reason_occurredAt_idx" ON "InventoryMovement"("reason", "occurredAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "InventoryMovement_assignmentId_idx" ON "InventoryMovement"("assignmentId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "InventoryMovement_performedById_occurredAt_idx" ON "InventoryMovement"("performedById", "occurredAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "InventoryMovement_occurredAt_idx" ON "InventoryMovement"("occurredAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "StockMovementLine_movementId_idx" ON "StockMovementLine"("movementId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "StockMovementLine_itemId_createdAt_idx" ON "StockMovementLine"("itemId", "createdAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "AssetMovementLine_assetId_createdAt_idx" ON "AssetMovementLine"("assetId", "createdAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "AssetMovementLine_movementId_assetId_key" ON "AssetMovementLine"("movementId", "assetId");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "StockAlert_itemId_status_idx" ON "StockAlert"("itemId", "status");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "StockAlert_status_triggeredAt_idx" ON "StockAlert"("status", "triggeredAt");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "StockAlert_trigger_triggeredAt_idx" ON "StockAlert"("trigger", "triggeredAt");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "UserInvitation" ADD CONSTRAINT "UserInvitation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "UserInvitation" ADD CONSTRAINT "UserInvitation_invitedById_fkey" FOREIGN KEY ("invitedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Person" ADD CONSTRAINT "Person_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "Person" ADD CONSTRAINT "Person_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
@@ -194,31 +420,335 @@ ALTER TABLE "Person" ADD CONSTRAINT "Person_userId_fkey" FOREIGN KEY ("userId")
|
|||||||
ALTER TABLE "Item" ADD CONSTRAINT "Item_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "Item" ADD CONSTRAINT "Item_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Asset" ADD CONSTRAINT "Asset_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "Asset" ADD CONSTRAINT "Asset_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "Asset"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_closedById_fkey" FOREIGN KEY ("closedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Assignment" ADD CONSTRAINT "Assignment_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentStockLine" ADD CONSTRAINT "AssignmentStockLine_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Movement" ADD CONSTRAINT "Movement_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentStockLine" ADD CONSTRAINT "AssignmentStockLine_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Movement" ADD CONSTRAINT "Movement_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "Asset"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentStockReturn" ADD CONSTRAINT "AssignmentStockReturn_assignmentLineId_fkey" FOREIGN KEY ("assignmentLineId") REFERENCES "AssignmentStockLine"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Movement" ADD CONSTRAINT "Movement_personId_fkey" FOREIGN KEY ("personId") REFERENCES "Person"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentStockReturn" ADD CONSTRAINT "AssignmentStockReturn_receivedById_fkey" FOREIGN KEY ("receivedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Movement" ADD CONSTRAINT "Movement_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentAssetLine" ADD CONSTRAINT "AssignmentAssetLine_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "Movement" ADD CONSTRAINT "Movement_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "AssignmentAssetLine" ADD CONSTRAINT "AssignmentAssetLine_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "Asset"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "AssignmentAssetLine" ADD CONSTRAINT "AssignmentAssetLine_returnedById_fkey" FOREIGN KEY ("returnedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "InventoryMovement" ADD CONSTRAINT "InventoryMovement_assignmentId_fkey" FOREIGN KEY ("assignmentId") REFERENCES "Assignment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "InventoryMovement" ADD CONSTRAINT "InventoryMovement_performedById_fkey" FOREIGN KEY ("performedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "StockMovementLine" ADD CONSTRAINT "StockMovementLine_movementId_fkey" FOREIGN KEY ("movementId") REFERENCES "InventoryMovement"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "StockMovementLine" ADD CONSTRAINT "StockMovementLine_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "AssetMovementLine" ADD CONSTRAINT "AssetMovementLine_movementId_fkey" FOREIGN KEY ("movementId") REFERENCES "InventoryMovement"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "AssetMovementLine" ADD CONSTRAINT "AssetMovementLine_assetId_fkey" FOREIGN KEY ("assetId") REFERENCES "Asset"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "StockAlert" ADD CONSTRAINT "StockAlert_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "Item"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "StockAlert" ADD CONSTRAINT "StockAlert_acknowledgedById_fkey" FOREIGN KEY ("acknowledgedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- USER INVITATION / ACTIVATION
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "User"
|
||||||
|
ADD CONSTRAINT "User_invited_without_password"
|
||||||
|
CHECK (
|
||||||
|
"status" <> 'INVITED'
|
||||||
|
OR "passwordHash" IS NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "User"
|
||||||
|
ADD CONSTRAINT "User_active_requires_password"
|
||||||
|
CHECK (
|
||||||
|
"status" <> 'ACTIVE'
|
||||||
|
OR "passwordHash" IS NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "User"
|
||||||
|
ADD CONSTRAINT "User_active_requires_activation_date"
|
||||||
|
CHECK (
|
||||||
|
"status" <> 'ACTIVE'
|
||||||
|
OR "activatedAt" IS NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "User"
|
||||||
|
ADD CONSTRAINT "User_activation_date_after_invitation"
|
||||||
|
CHECK (
|
||||||
|
"activatedAt" IS NULL
|
||||||
|
OR "invitedAt" IS NULL
|
||||||
|
OR "activatedAt" >= "invitedAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "User"
|
||||||
|
ADD CONSTRAINT "User_password_changed_after_invitation"
|
||||||
|
CHECK (
|
||||||
|
"passwordChangedAt" IS NULL
|
||||||
|
OR "invitedAt" IS NULL
|
||||||
|
OR "passwordChangedAt" >= "invitedAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "UserInvitation"
|
||||||
|
ADD CONSTRAINT "UserInvitation_expiry_after_creation"
|
||||||
|
CHECK ("expiresAt" > "createdAt");
|
||||||
|
|
||||||
|
ALTER TABLE "UserInvitation"
|
||||||
|
ADD CONSTRAINT "UserInvitation_accepted_or_revoked"
|
||||||
|
CHECK (
|
||||||
|
"acceptedAt" IS NULL
|
||||||
|
OR "revokedAt" IS NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "UserInvitation"
|
||||||
|
ADD CONSTRAINT "UserInvitation_accepted_after_creation"
|
||||||
|
CHECK (
|
||||||
|
"acceptedAt" IS NULL
|
||||||
|
OR "acceptedAt" >= "createdAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "UserInvitation"
|
||||||
|
ADD CONSTRAINT "UserInvitation_revoked_after_creation"
|
||||||
|
CHECK (
|
||||||
|
"revokedAt" IS NULL
|
||||||
|
OR "revokedAt" >= "createdAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "UserInvitation_active_user_key"
|
||||||
|
ON "UserInvitation" ("userId")
|
||||||
|
WHERE "acceptedAt" IS NULL
|
||||||
|
AND "revokedAt" IS NULL;
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- ITEM STOCK
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "Item"
|
||||||
|
ADD CONSTRAINT "Item_stock_non_negative"
|
||||||
|
CHECK ("stock" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "Item"
|
||||||
|
ADD CONSTRAINT "Item_min_stock_non_negative"
|
||||||
|
CHECK (
|
||||||
|
"minStock" IS NULL
|
||||||
|
OR "minStock" >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Item"
|
||||||
|
ADD CONSTRAINT "Item_target_stock_non_negative"
|
||||||
|
CHECK (
|
||||||
|
"targetStock" IS NULL
|
||||||
|
OR "targetStock" >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Item"
|
||||||
|
ADD CONSTRAINT "Item_target_not_below_minimum"
|
||||||
|
CHECK (
|
||||||
|
"minStock" IS NULL
|
||||||
|
OR "targetStock" IS NULL
|
||||||
|
OR "targetStock" >= "minStock"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Item"
|
||||||
|
ADD CONSTRAINT "Item_serialized_stock_zero"
|
||||||
|
CHECK (
|
||||||
|
"trackingType" <> 'SERIALIZED'
|
||||||
|
OR "stock" = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- ASSET DATA
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "Asset"
|
||||||
|
ADD CONSTRAINT "Asset_purchase_price_non_negative"
|
||||||
|
CHECK (
|
||||||
|
"purchasePrice" IS NULL
|
||||||
|
OR "purchasePrice" >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Asset"
|
||||||
|
ADD CONSTRAINT "Asset_warranty_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"warrantyEndsAt" IS NULL
|
||||||
|
OR "purchaseDate" IS NULL
|
||||||
|
OR "warrantyEndsAt" >= "purchaseDate"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Asset"
|
||||||
|
ADD CONSTRAINT "Asset_retired_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"retiredAt" IS NULL
|
||||||
|
OR "retiredAt" >= "createdAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- ASSIGNMENTS
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "Assignment"
|
||||||
|
ADD CONSTRAINT "Assignment_due_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"dueAt" IS NULL
|
||||||
|
OR "dueAt" >= "assignedAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "Assignment"
|
||||||
|
ADD CONSTRAINT "Assignment_closed_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"closedAt" IS NULL
|
||||||
|
OR "closedAt" >= "assignedAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- QUANTITY ASSIGNMENTS
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentStockLine"
|
||||||
|
ADD CONSTRAINT "AssignmentStockLine_quantity_positive"
|
||||||
|
CHECK ("quantity" > 0);
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentStockLine"
|
||||||
|
ADD CONSTRAINT "AssignmentStockLine_returned_non_negative"
|
||||||
|
CHECK ("returnedQuantity" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentStockLine"
|
||||||
|
ADD CONSTRAINT "AssignmentStockLine_returned_not_greater"
|
||||||
|
CHECK ("returnedQuantity" <= "quantity");
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentStockReturn"
|
||||||
|
ADD CONSTRAINT "AssignmentStockReturn_quantity_positive"
|
||||||
|
CHECK ("quantity" > 0);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- SERIALIZED ASSET ASSIGNMENTS
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentAssetLine"
|
||||||
|
ADD CONSTRAINT "AssignmentAssetLine_return_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"returnedAt" IS NULL
|
||||||
|
OR "returnedAt" >= "assignedAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "AssignmentAssetLine"
|
||||||
|
ADD CONSTRAINT "AssignmentAssetLine_return_data_consistent"
|
||||||
|
CHECK (
|
||||||
|
(
|
||||||
|
"returnedAt" IS NULL
|
||||||
|
AND "returnedById" IS NULL
|
||||||
|
AND "returnStatus" IS NULL
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
"returnedAt" IS NOT NULL
|
||||||
|
AND "returnedById" IS NOT NULL
|
||||||
|
AND "returnStatus" IS NOT NULL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "AssignmentAssetLine_active_asset_key"
|
||||||
|
ON "AssignmentAssetLine" ("assetId")
|
||||||
|
WHERE "returnedAt" IS NULL;
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- STOCK MOVEMENTS
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "StockMovementLine"
|
||||||
|
ADD CONSTRAINT "StockMovementLine_stock_consistency"
|
||||||
|
CHECK (
|
||||||
|
"newStock" = "previousStock" + "stockDelta"
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "StockMovementLine"
|
||||||
|
ADD CONSTRAINT "StockMovementLine_previous_stock_non_negative"
|
||||||
|
CHECK ("previousStock" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "StockMovementLine"
|
||||||
|
ADD CONSTRAINT "StockMovementLine_new_stock_non_negative"
|
||||||
|
CHECK ("newStock" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "StockMovementLine"
|
||||||
|
ADD CONSTRAINT "StockMovementLine_delta_not_zero"
|
||||||
|
CHECK ("stockDelta" <> 0);
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- STOCK ALERTS
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
ALTER TABLE "StockAlert"
|
||||||
|
ADD CONSTRAINT "StockAlert_available_stock_non_negative"
|
||||||
|
CHECK ("availableStock" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "StockAlert"
|
||||||
|
ADD CONSTRAINT "StockAlert_minimum_stock_non_negative"
|
||||||
|
CHECK ("minimumStock" >= 0);
|
||||||
|
|
||||||
|
ALTER TABLE "StockAlert"
|
||||||
|
ADD CONSTRAINT "StockAlert_suggested_purchase_non_negative"
|
||||||
|
CHECK (
|
||||||
|
"suggestedPurchase" IS NULL
|
||||||
|
OR "suggestedPurchase" >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "StockAlert"
|
||||||
|
ADD CONSTRAINT "StockAlert_acknowledgement_consistent"
|
||||||
|
CHECK (
|
||||||
|
(
|
||||||
|
"acknowledgedAt" IS NULL
|
||||||
|
AND "acknowledgedById" IS NULL
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
"acknowledgedAt" IS NOT NULL
|
||||||
|
AND "acknowledgedById" IS NOT NULL
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE "StockAlert"
|
||||||
|
ADD CONSTRAINT "StockAlert_resolution_date_valid"
|
||||||
|
CHECK (
|
||||||
|
"resolvedAt" IS NULL
|
||||||
|
OR "resolvedAt" >= "triggeredAt"
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX "StockAlert_active_item_trigger_key"
|
||||||
|
ON "StockAlert" ("itemId", "trigger")
|
||||||
|
WHERE "status" IN ('OPEN', 'ACKNOWLEDGED');
|
||||||
+495
-101
@@ -14,6 +14,10 @@ datasource db {
|
|||||||
provider = "postgresql"
|
provider = "postgresql"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// USERS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
enum UserRole {
|
enum UserRole {
|
||||||
ADMIN
|
ADMIN
|
||||||
MANAGER
|
MANAGER
|
||||||
@@ -21,20 +25,91 @@ enum UserRole {
|
|||||||
VIEWER
|
VIEWER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum UserStatus {
|
||||||
|
INVITED
|
||||||
|
ACTIVE
|
||||||
|
SUSPENDED
|
||||||
|
DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
model User {
|
model User {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
name String
|
name String
|
||||||
email String @unique
|
email String
|
||||||
password String
|
emailNormalized String @unique
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nulo mientras el usuario no haya aceptado la invitación.
|
||||||
|
*/
|
||||||
|
passwordHash String?
|
||||||
|
|
||||||
role UserRole @default(STAFF)
|
role UserRole @default(STAFF)
|
||||||
isActive Boolean @default(true)
|
status UserStatus @default(INVITED)
|
||||||
|
|
||||||
|
deletedAt DateTime?
|
||||||
|
|
||||||
|
invitedAt DateTime?
|
||||||
|
activatedAt DateTime?
|
||||||
|
passwordChangedAt DateTime?
|
||||||
|
lastLoginAt DateTime?
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
movements Movement[]
|
|
||||||
assignments Assignment[]
|
|
||||||
person Person?
|
person Person?
|
||||||
|
|
||||||
|
createdAssignments Assignment[] @relation("AssignmentCreatedBy")
|
||||||
|
closedAssignments Assignment[] @relation("AssignmentClosedBy")
|
||||||
|
|
||||||
|
receivedStockReturns AssignmentStockReturn[]
|
||||||
|
receivedAssetReturns AssignmentAssetLine[] @relation("AssetReturnedBy")
|
||||||
|
|
||||||
|
movements InventoryMovement[]
|
||||||
|
|
||||||
|
acknowledgedStockAlerts StockAlert[] @relation("StockAlertAcknowledgedBy")
|
||||||
|
|
||||||
|
sentInvitations UserInvitation[] @relation("UserInvitationInvitedBy")
|
||||||
|
invitations UserInvitation[]
|
||||||
|
|
||||||
|
@@index([status])
|
||||||
|
@@index([deletedAt])
|
||||||
|
@@index([createdAt])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model UserInvitation {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
userId String @db.Uuid
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash del token de invitación.
|
||||||
|
* Nunca guardar el token plano.
|
||||||
|
*/
|
||||||
|
tokenHash String @unique
|
||||||
|
|
||||||
|
invitedById String @db.Uuid
|
||||||
|
invitedBy User @relation("UserInvitationInvitedBy", fields: [invitedById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
email String
|
||||||
|
|
||||||
|
expiresAt DateTime
|
||||||
|
acceptedAt DateTime?
|
||||||
|
revokedAt DateTime?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@index([userId])
|
||||||
|
@@index([expiresAt])
|
||||||
|
@@index([acceptedAt])
|
||||||
|
@@index([revokedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// PEOPLE
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
enum PersonDepartment {
|
enum PersonDepartment {
|
||||||
IT
|
IT
|
||||||
ENGINEERING
|
ENGINEERING
|
||||||
@@ -47,139 +122,458 @@ enum PersonDepartment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Person {
|
model Person {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
firstName String
|
firstName String
|
||||||
lastName String
|
lastName String
|
||||||
department PersonDepartment?
|
department PersonDepartment?
|
||||||
email String? @unique
|
|
||||||
|
email String?
|
||||||
phone String?
|
phone String?
|
||||||
userId String? @unique
|
|
||||||
|
userId String? @unique @db.Uuid
|
||||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
||||||
isActive Boolean @default(true)
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
assignments Assignment[]
|
|
||||||
movements Movement[]
|
|
||||||
|
|
||||||
@@index([lastName, firstName])
|
|
||||||
@@index([department])
|
|
||||||
}
|
|
||||||
|
|
||||||
model Category {
|
|
||||||
id String @id @default(uuid())
|
|
||||||
name String @unique
|
|
||||||
description String?
|
|
||||||
isActive Boolean @default(true)
|
|
||||||
items Item[]
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
|
|
||||||
@@index([name])
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ItemStatus {
|
|
||||||
AVAILABLE
|
|
||||||
ASSIGNED
|
|
||||||
RESERVED
|
|
||||||
IN_REPAIR
|
|
||||||
BROKEN
|
|
||||||
STOLEN
|
|
||||||
DISPOSED
|
|
||||||
}
|
|
||||||
|
|
||||||
model Item {
|
|
||||||
id String @id @default(uuid())
|
|
||||||
name String @unique
|
|
||||||
description String?
|
|
||||||
categoryId String
|
|
||||||
category Category @relation(fields: [categoryId], references: [id])
|
|
||||||
stock Int @default(0)
|
|
||||||
minStock Int?
|
|
||||||
maxStock Int?
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
deletedAt DateTime?
|
deletedAt DateTime?
|
||||||
movements Movement[]
|
|
||||||
assignments Assignment[]
|
assignments Assignment[]
|
||||||
|
|
||||||
|
@@index([lastName, firstName])
|
||||||
|
@@index([department, deletedAt])
|
||||||
|
@@index([deletedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// CATALOG
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
enum ItemTrackingType {
|
||||||
|
QUANTITY
|
||||||
|
SERIALIZED
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ItemStatus {
|
||||||
|
ACTIVE
|
||||||
|
DISCONTINUED
|
||||||
|
ARCHIVED
|
||||||
|
}
|
||||||
|
|
||||||
|
model Category {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
name String @unique
|
||||||
|
description String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
deletedAt DateTime?
|
||||||
|
|
||||||
|
items Item[]
|
||||||
|
|
||||||
|
@@index([deletedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
model Item {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
sku String @unique
|
||||||
|
name String
|
||||||
|
description String?
|
||||||
|
|
||||||
|
trackingType ItemTrackingType
|
||||||
|
status ItemStatus @default(ACTIVE)
|
||||||
|
|
||||||
|
categoryId String @db.Uuid
|
||||||
|
category Category @relation(fields: [categoryId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Solo se utiliza para artículos QUANTITY.
|
||||||
|
* Para artículos SERIALIZED, las existencias se obtienen
|
||||||
|
* contando los activos AVAILABLE.
|
||||||
|
*/
|
||||||
|
stock Int @default(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Umbral de alerta.
|
||||||
|
* QUANTITY:
|
||||||
|
* Se compara contra Item.stock.
|
||||||
|
* SERIALIZED:
|
||||||
|
* Se compara contra número de Asset AVAILABLE.
|
||||||
|
*/
|
||||||
|
minStock Int?
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nivel deseado tras reposición.
|
||||||
|
* Compra sugerida:
|
||||||
|
* targetStock - stock disponible.
|
||||||
|
*/
|
||||||
|
targetStock Int?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
deletedAt DateTime?
|
||||||
|
|
||||||
assets Asset[]
|
assets Asset[]
|
||||||
|
|
||||||
@@index([categoryId])
|
assignmentStockLines AssignmentStockLine[]
|
||||||
|
stockMovementLines StockMovementLine[]
|
||||||
|
|
||||||
|
stockAlerts StockAlert[]
|
||||||
|
|
||||||
|
@@index([categoryId, status])
|
||||||
|
@@index([trackingType, status])
|
||||||
|
@@index([name])
|
||||||
|
@@index([deletedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// SERIALIZED ASSETS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
enum AssetStatus {
|
||||||
|
AVAILABLE
|
||||||
|
ASSIGNED
|
||||||
|
IN_REPAIR
|
||||||
|
BROKEN
|
||||||
|
LOST
|
||||||
|
STOLEN
|
||||||
|
DISPOSED
|
||||||
|
RETIRED
|
||||||
}
|
}
|
||||||
|
|
||||||
model Asset {
|
model Asset {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
itemId String?
|
|
||||||
item Item? @relation(fields: [itemId], references: [id])
|
/**
|
||||||
|
* Identificador interno visible.
|
||||||
|
* Ejemplos:
|
||||||
|
* IT-000001
|
||||||
|
* LAP-000042
|
||||||
|
* MON-000117
|
||||||
|
*/
|
||||||
|
assetTag String? @unique
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Número de serie del fabricante.
|
||||||
|
* Puede ser nulo.
|
||||||
|
*/
|
||||||
serialNumber String @unique
|
serialNumber String @unique
|
||||||
|
|
||||||
|
itemId String @db.Uuid
|
||||||
|
item Item @relation(fields: [itemId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
status AssetStatus @default(AVAILABLE)
|
||||||
|
|
||||||
|
manufacturer String?
|
||||||
|
model String?
|
||||||
|
|
||||||
deliveryNote String?
|
deliveryNote String?
|
||||||
status ItemStatus @default(AVAILABLE)
|
invoiceNumber String?
|
||||||
|
|
||||||
|
purchaseDate DateTime?
|
||||||
|
purchasePrice Decimal? @db.Decimal(12, 2)
|
||||||
|
|
||||||
|
warrantyEndsAt DateTime?
|
||||||
|
|
||||||
notes String?
|
notes String?
|
||||||
|
|
||||||
|
retiredAt DateTime?
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
movements Movement[]
|
|
||||||
assignment Assignment?
|
|
||||||
|
|
||||||
@@index([serialNumber])
|
deletedAt DateTime?
|
||||||
@@index([itemId])
|
|
||||||
|
assignmentLines AssignmentAssetLine[]
|
||||||
|
movementLines AssetMovementLine[]
|
||||||
|
|
||||||
|
@@index([itemId, status])
|
||||||
@@index([status])
|
@@index([status])
|
||||||
|
@@index([createdAt])
|
||||||
|
@@index([deletedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// ASSIGNMENTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
enum AssignmentStatus {
|
||||||
|
OPEN
|
||||||
|
PARTIALLY_RETURNED
|
||||||
|
RETURNED
|
||||||
|
CANCELLED
|
||||||
}
|
}
|
||||||
|
|
||||||
model Assignment {
|
model Assignment {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
quantity Int?
|
|
||||||
|
personId String @db.Uuid
|
||||||
|
person Person @relation(fields: [personId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
status AssignmentStatus @default(OPEN)
|
||||||
|
|
||||||
|
assignedAt DateTime @default(now())
|
||||||
|
dueAt DateTime?
|
||||||
|
closedAt DateTime?
|
||||||
|
|
||||||
notes String?
|
notes String?
|
||||||
itemId String?
|
|
||||||
item Item? @relation(fields: [itemId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
createdById String @db.Uuid
|
||||||
assetId String? @unique
|
createdBy User @relation("AssignmentCreatedBy", fields: [createdById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
asset Asset? @relation(fields: [assetId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
||||||
personId String?
|
closedById String? @db.Uuid
|
||||||
person Person? @relation(fields: [personId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
closedBy User? @relation("AssignmentClosedBy", fields: [closedById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
assignmentDate DateTime @default(now())
|
|
||||||
returnDate DateTime?
|
|
||||||
createdBy String
|
|
||||||
createdUser User @relation(fields: [createdBy], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
movement Movement[]
|
|
||||||
|
|
||||||
@@index([itemId])
|
stockLines AssignmentStockLine[]
|
||||||
@@index([assetId])
|
assetLines AssignmentAssetLine[]
|
||||||
@@index([personId])
|
movements InventoryMovement[]
|
||||||
@@index([createdBy])
|
|
||||||
|
@@index([personId, status])
|
||||||
|
@@index([personId, assignedAt])
|
||||||
|
@@index([status, assignedAt])
|
||||||
|
@@index([dueAt])
|
||||||
|
@@index([createdById, createdAt])
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MovementType {
|
// ======================================================
|
||||||
IN
|
// QUANTITY ASSIGNMENTS
|
||||||
OUT
|
// ======================================================
|
||||||
|
|
||||||
|
model AssignmentStockLine {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
assignmentId String @db.Uuid
|
||||||
|
assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
itemId String @db.Uuid
|
||||||
|
item Item @relation(fields: [itemId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
quantity Int
|
||||||
|
returnedQuantity Int @default(0)
|
||||||
|
|
||||||
|
notes String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
returns AssignmentStockReturn[]
|
||||||
|
|
||||||
|
@@index([assignmentId])
|
||||||
|
@@index([itemId, createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
model AssignmentStockReturn {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
assignmentLineId String @db.Uuid
|
||||||
|
assignmentLine AssignmentStockLine @relation(fields: [assignmentLineId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
quantity Int
|
||||||
|
|
||||||
|
returnedAt DateTime @default(now())
|
||||||
|
|
||||||
|
receivedById String @db.Uuid
|
||||||
|
receivedBy User @relation(fields: [receivedById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
notes String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@index([assignmentLineId, returnedAt])
|
||||||
|
@@index([receivedById, returnedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// SERIALIZED ASSET ASSIGNMENTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
model AssignmentAssetLine {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
assignmentId String @db.Uuid
|
||||||
|
assignment Assignment @relation(fields: [assignmentId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
assetId String @db.Uuid
|
||||||
|
asset Asset @relation(fields: [assetId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
assignedAt DateTime @default(now())
|
||||||
|
returnedAt DateTime?
|
||||||
|
|
||||||
|
returnedById String? @db.Uuid
|
||||||
|
returnedBy User? @relation("AssetReturnedBy", fields: [returnedById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
returnStatus AssetStatus?
|
||||||
|
|
||||||
|
notes String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* La unicidad de asignación activa se protege
|
||||||
|
* mediante índice único parcial en PostgreSQL.
|
||||||
|
*/
|
||||||
|
@@index([assignmentId])
|
||||||
|
@@index([assetId, assignedAt])
|
||||||
|
@@index([returnedAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// INVENTORY MOVEMENTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
enum InventoryMovementType {
|
||||||
|
RECEIPT
|
||||||
|
ISSUE
|
||||||
ASSIGNMENT
|
ASSIGNMENT
|
||||||
RETURN
|
RETURN
|
||||||
ADJUSTMENT
|
ADJUSTMENT
|
||||||
DELETED
|
STATUS_CHANGE
|
||||||
|
DISPOSAL
|
||||||
|
INITIAL_LOAD
|
||||||
}
|
}
|
||||||
|
|
||||||
model Movement {
|
enum InventoryMovementReason {
|
||||||
id String @id @default(uuid())
|
PURCHASE
|
||||||
type MovementType @default(IN)
|
MANUAL_ENTRY
|
||||||
quantity Int
|
EMPLOYEE_ASSIGNMENT
|
||||||
|
EMPLOYEE_RETURN
|
||||||
|
INVENTORY_CORRECTION
|
||||||
|
DAMAGE
|
||||||
|
REPAIR
|
||||||
|
REPAIR_RETURN
|
||||||
|
LOSS
|
||||||
|
THEFT
|
||||||
|
DISPOSAL
|
||||||
|
INITIAL_LOAD
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
||||||
|
model InventoryMovement {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
type InventoryMovementType
|
||||||
|
reason InventoryMovementReason
|
||||||
|
|
||||||
|
assignmentId String? @db.Uuid
|
||||||
|
assignment Assignment? @relation(fields: [assignmentId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
reference String?
|
||||||
|
|
||||||
details String?
|
details String?
|
||||||
notes String?
|
notes String?
|
||||||
itemId String?
|
|
||||||
item Item? @relation(fields: [itemId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
performedById String @db.Uuid
|
||||||
assetId String?
|
performedBy User @relation(fields: [performedById], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
asset Asset? @relation(fields: [assetId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
||||||
previousStock Int?
|
occurredAt DateTime @default(now())
|
||||||
newStock Int?
|
|
||||||
personId String?
|
|
||||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
||||||
assignmentId String?
|
|
||||||
assignment Assignment? @relation(fields: [assignmentId], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
|
||||||
userId String
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
@@index([itemId])
|
stockLines StockMovementLine[]
|
||||||
@@index([assetId])
|
assetLines AssetMovementLine[]
|
||||||
@@index([personId])
|
|
||||||
@@index([type])
|
@@index([type, occurredAt])
|
||||||
@@index([userId])
|
@@index([reason, occurredAt])
|
||||||
|
@@index([assignmentId])
|
||||||
|
@@index([performedById, occurredAt])
|
||||||
|
@@index([occurredAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// QUANTITY MOVEMENTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
model StockMovementLine {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
movementId String @db.Uuid
|
||||||
|
movement InventoryMovement @relation(fields: [movementId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||||
|
|
||||||
|
itemId String @db.Uuid
|
||||||
|
item Item @relation(fields: [itemId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Positivo: entrada/devolución/ajuste positivo.
|
||||||
|
* Negativo: salida/asignación/ajuste negativo.
|
||||||
|
*/
|
||||||
|
stockDelta Int
|
||||||
|
|
||||||
|
previousStock Int
|
||||||
|
newStock Int
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@index([movementId])
|
||||||
|
@@index([itemId, createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// SERIALIZED ASSET MOVEMENTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
model AssetMovementLine {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
movementId String @db.Uuid
|
||||||
|
movement InventoryMovement @relation(fields: [movementId], references: [id], onDelete: Cascade, onUpdate: Cascade)
|
||||||
|
|
||||||
|
assetId String @db.Uuid
|
||||||
|
asset Asset @relation(fields: [assetId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
previousStatus AssetStatus?
|
||||||
|
newStatus AssetStatus
|
||||||
|
|
||||||
|
notes String?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
|
@@unique([movementId, assetId])
|
||||||
|
@@index([assetId, createdAt])
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// STOCK ALERTS
|
||||||
|
// ======================================================
|
||||||
|
|
||||||
|
enum StockAlertStatus {
|
||||||
|
OPEN
|
||||||
|
ACKNOWLEDGED
|
||||||
|
RESOLVED
|
||||||
|
}
|
||||||
|
|
||||||
|
enum StockAlertTrigger {
|
||||||
|
BELOW_MINIMUM
|
||||||
|
OUT_OF_STOCK
|
||||||
|
}
|
||||||
|
|
||||||
|
model StockAlert {
|
||||||
|
id String @id @default(uuid(7)) @db.Uuid
|
||||||
|
|
||||||
|
itemId String @db.Uuid
|
||||||
|
item Item @relation(fields: [itemId], references: [id], onDelete: Restrict, onUpdate: Cascade)
|
||||||
|
|
||||||
|
trigger StockAlertTrigger
|
||||||
|
status StockAlertStatus @default(OPEN)
|
||||||
|
|
||||||
|
availableStock Int
|
||||||
|
minimumStock Int
|
||||||
|
suggestedPurchase Int?
|
||||||
|
|
||||||
|
triggeredAt DateTime @default(now())
|
||||||
|
|
||||||
|
acknowledgedAt DateTime?
|
||||||
|
|
||||||
|
acknowledgedById String? @db.Uuid
|
||||||
|
acknowledgedBy User? @relation("StockAlertAcknowledgedBy", fields: [acknowledgedById], references: [id], onDelete: SetNull, onUpdate: Cascade)
|
||||||
|
|
||||||
|
resolvedAt DateTime?
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([itemId, status])
|
||||||
|
@@index([status, triggeredAt])
|
||||||
|
@@index([trigger, triggeredAt])
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user