Initialize the API and add managed app banners.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,469 @@
|
||||
-- CreateSchema
|
||||
CREATE SCHEMA IF NOT EXISTS "public";
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SettlementType" AS ENUM ('cash', 'check');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CheckRegistrationMode" AS ENUM ('full', 'brief');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "OrderStatus" AS ENUM ('cart', 'awaiting_settlement', 'cash_in_progress', 'check_in_progress', 'submitted', 'awaiting_review', 'pricing', 'needs_correction', 'awaiting_settlement_fix', 'cash_invoice_issued', 'awaiting_cash_payment', 'cash_payment_submitted', 'awaiting_cash_confirmation', 'cash_confirmed', 'awaiting_check_review', 'check_needs_fix', 'check_rejected', 'checks_approved', 'final_approved', 'preparing', 'ready_to_ship', 'shipped', 'delivered', 'cancelled', 'rejected', 'expired');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CheckStatus" AS ENUM ('pending_review', 'approved', 'rejected');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CashPaymentStatus" AS ENUM ('pending_review', 'approved', 'rejected', 'expired');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ShipmentStatus" AS ENUM ('preparing', 'ready', 'shipped', 'delivered');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CustomerType" AS ENUM ('wholesale', 'retail');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AdminRole" AS ENUM ('admin', 'sales', 'finance', 'warehouse');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "NotificationTone" AS ENUM ('info', 'warning', 'success', 'danger');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Company" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"logoUrl" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"displayOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"maxMeteragePerInvoice" INTEGER NOT NULL DEFAULT 5000,
|
||||
"cashInvoiceValidityHours" INTEGER NOT NULL DEFAULT 8,
|
||||
"cashInvoiceValidUntilHour" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Company_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BankAccount" (
|
||||
"id" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"bankName" TEXT NOT NULL,
|
||||
"accountHolder" TEXT NOT NULL,
|
||||
"accountNumber" TEXT NOT NULL,
|
||||
"cardNumber" TEXT NOT NULL,
|
||||
"iban" TEXT NOT NULL,
|
||||
"notes" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"displayOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "BankAccount_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Catalog" (
|
||||
"id" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"displayOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Catalog_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Product" (
|
||||
"id" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"catalogId" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"color" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"minMeterage" DOUBLE PRECISION NOT NULL DEFAULT 30,
|
||||
"orderMultiplier" DOUBLE PRECISION NOT NULL DEFAULT 10,
|
||||
"basePrice" DOUBLE PRECISION,
|
||||
"stock" DOUBLE PRECISION,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Product_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Customer" (
|
||||
"id" TEXT NOT NULL,
|
||||
"firstName" TEXT NOT NULL,
|
||||
"lastName" TEXT NOT NULL,
|
||||
"phone" TEXT NOT NULL,
|
||||
"nationalId" TEXT,
|
||||
"customerType" "CustomerType" NOT NULL DEFAULT 'wholesale',
|
||||
"companyId" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Customer_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AdminUser" (
|
||||
"id" TEXT NOT NULL,
|
||||
"fullName" TEXT NOT NULL,
|
||||
"phone" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"passwordHash" TEXT NOT NULL,
|
||||
"role" "AdminRole" NOT NULL DEFAULT 'admin',
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"lastLoginAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "AdminUser_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OtpChallenge" (
|
||||
"id" TEXT NOT NULL,
|
||||
"phone" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"firstName" TEXT,
|
||||
"lastName" TEXT,
|
||||
"isRegister" BOOLEAN NOT NULL DEFAULT false,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "OtpChallenge_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Cart" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"companyId" TEXT,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Cart_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CartItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"cartId" TEXT NOT NULL,
|
||||
"productId" TEXT NOT NULL,
|
||||
"catalogCode" TEXT NOT NULL,
|
||||
"productName" TEXT NOT NULL,
|
||||
"productCode" TEXT NOT NULL,
|
||||
"color" TEXT NOT NULL,
|
||||
"meterage" DOUBLE PRECISION NOT NULL,
|
||||
"unitPrice" DOUBLE PRECISION,
|
||||
"notes" TEXT,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"companyName" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "CartItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Order" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderNumber" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"companyId" TEXT NOT NULL,
|
||||
"companyName" TEXT NOT NULL,
|
||||
"settlementType" "SettlementType" NOT NULL,
|
||||
"checkMode" "CheckRegistrationMode",
|
||||
"status" "OrderStatus" NOT NULL DEFAULT 'awaiting_review',
|
||||
"totalMeterage" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"totalAmount" DOUBLE PRECISION,
|
||||
"shippingCost" DOUBLE PRECISION,
|
||||
"totalDiscount" DOUBLE PRECISION,
|
||||
"finalAmount" DOUBLE PRECISION,
|
||||
"notes" TEXT,
|
||||
"checkRassDays" INTEGER,
|
||||
"checkRassDate" TIMESTAMP(3),
|
||||
"cashInvoiceExpiresAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Order_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OrderItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"productId" TEXT,
|
||||
"catalogCode" TEXT NOT NULL,
|
||||
"productName" TEXT NOT NULL,
|
||||
"productCode" TEXT,
|
||||
"color" TEXT NOT NULL,
|
||||
"requestedMeterage" DOUBLE PRECISION NOT NULL,
|
||||
"confirmedMeterage" DOUBLE PRECISION,
|
||||
"unitPrice" DOUBLE PRECISION,
|
||||
"unitDiscount" DOUBLE PRECISION DEFAULT 0,
|
||||
"lineTotal" DOUBLE PRECISION,
|
||||
"notes" TEXT,
|
||||
|
||||
CONSTRAINT "OrderItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "OrderStatusHistory" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"fromStatus" "OrderStatus",
|
||||
"toStatus" "OrderStatus" NOT NULL,
|
||||
"changedBy" TEXT NOT NULL,
|
||||
"note" TEXT,
|
||||
"reason" TEXT,
|
||||
"changedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "OrderStatusHistory_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Check" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"row" INTEGER NOT NULL,
|
||||
"amount" DOUBLE PRECISION NOT NULL,
|
||||
"dueDate" TIMESTAMP(3) NOT NULL,
|
||||
"sayadId" TEXT,
|
||||
"checkNumber" TEXT,
|
||||
"ownerNationalId" TEXT,
|
||||
"ownerFirstName" TEXT,
|
||||
"ownerLastName" TEXT,
|
||||
"bankName" TEXT,
|
||||
"branchName" TEXT,
|
||||
"frontImage" TEXT,
|
||||
"backImage" TEXT,
|
||||
"notes" TEXT,
|
||||
"mode" "CheckRegistrationMode" NOT NULL DEFAULT 'full',
|
||||
"status" "CheckStatus" NOT NULL DEFAULT 'pending_review',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Check_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "CashPaymentReceipt" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"amount" DOUBLE PRECISION NOT NULL,
|
||||
"paidAmount" DOUBLE PRECISION,
|
||||
"transferDate" TIMESTAMP(3),
|
||||
"transferTime" TEXT,
|
||||
"trackingNumber" TEXT,
|
||||
"destinationAccountId" TEXT,
|
||||
"receiptImage" TEXT,
|
||||
"notes" TEXT,
|
||||
"expiresAt" TIMESTAMP(3),
|
||||
"status" "CashPaymentStatus" NOT NULL DEFAULT 'pending_review',
|
||||
"submittedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "CashPaymentReceipt_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Shipment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"orderId" TEXT NOT NULL,
|
||||
"carrier" TEXT NOT NULL,
|
||||
"trackingNumber" TEXT,
|
||||
"meterage" DOUBLE PRECISION NOT NULL,
|
||||
"status" "ShipmentStatus" NOT NULL DEFAULT 'preparing',
|
||||
"shippedAt" TIMESTAMP(3),
|
||||
"deliveredAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Shipment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SystemSettings" (
|
||||
"id" TEXT NOT NULL DEFAULT 'default',
|
||||
"maxMeteragePerInvoice" INTEGER NOT NULL DEFAULT 5000,
|
||||
"cashInvoiceValidityHours" INTEGER NOT NULL DEFAULT 8,
|
||||
"defaultSettlementCheck" BOOLEAN NOT NULL DEFAULT true,
|
||||
"defaultSettlementCash" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smsOrderRegistered" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smsPaymentReminder" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smsCheckReview" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smsShippingUpdate" BOOLEAN NOT NULL DEFAULT true,
|
||||
"supportPhone" TEXT,
|
||||
"supportEmail" TEXT,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SystemSettings_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AdminNotification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"tone" "NotificationTone" DEFAULT 'info',
|
||||
"link" TEXT,
|
||||
"isRead" BOOLEAN NOT NULL DEFAULT false,
|
||||
"sentAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "AdminNotification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InternalMessage" (
|
||||
"id" TEXT NOT NULL,
|
||||
"senderName" TEXT NOT NULL,
|
||||
"subject" TEXT NOT NULL,
|
||||
"preview" TEXT NOT NULL,
|
||||
"isRead" BOOLEAN NOT NULL DEFAULT false,
|
||||
"sentAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "InternalMessage_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Company_slug_key" ON "Company"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BankAccount_companyId_idx" ON "BankAccount"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Catalog_companyId_idx" ON "Catalog"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Catalog_companyId_code_key" ON "Catalog"("companyId", "code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Product_catalogId_idx" ON "Product"("catalogId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Product_companyId_idx" ON "Product"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Product_companyId_code_key" ON "Product"("companyId", "code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Customer_phone_key" ON "Customer"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Customer_companyId_idx" ON "Customer"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "AdminUser_phone_key" ON "AdminUser"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "AdminUser_email_key" ON "AdminUser"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "OtpChallenge_phone_idx" ON "OtpChallenge"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Cart_userId_idx" ON "Cart"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "CartItem_cartId_idx" ON "CartItem"("cartId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CartItem_cartId_productId_key" ON "CartItem"("cartId", "productId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Order_orderNumber_key" ON "Order"("orderNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Order_userId_idx" ON "Order"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Order_companyId_idx" ON "Order"("companyId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Order_status_idx" ON "Order"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Order_createdAt_idx" ON "Order"("createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "OrderItem_orderId_idx" ON "OrderItem"("orderId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "OrderStatusHistory_orderId_idx" ON "OrderStatusHistory"("orderId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Check_orderId_idx" ON "Check"("orderId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Check_dueDate_idx" ON "Check"("dueDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "CashPaymentReceipt_orderId_key" ON "CashPaymentReceipt"("orderId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Shipment_orderId_key" ON "Shipment"("orderId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "BankAccount" ADD CONSTRAINT "BankAccount_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Catalog" ADD CONSTRAINT "Catalog_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Product" ADD CONSTRAINT "Product_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Product" ADD CONSTRAINT "Product_catalogId_fkey" FOREIGN KEY ("catalogId") REFERENCES "Catalog"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Customer" ADD CONSTRAINT "Customer_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Cart" ADD CONSTRAINT "Cart_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CartItem" ADD CONSTRAINT "CartItem_cartId_fkey" FOREIGN KEY ("cartId") REFERENCES "Cart"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CartItem" ADD CONSTRAINT "CartItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Order" ADD CONSTRAINT "Order_userId_fkey" FOREIGN KEY ("userId") REFERENCES "Customer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Order" ADD CONSTRAINT "Order_companyId_fkey" FOREIGN KEY ("companyId") REFERENCES "Company"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OrderItem" ADD CONSTRAINT "OrderItem_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OrderItem" ADD CONSTRAINT "OrderItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "OrderStatusHistory" ADD CONSTRAINT "OrderStatusHistory_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Check" ADD CONSTRAINT "Check_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CashPaymentReceipt" ADD CONSTRAINT "CashPaymentReceipt_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "CashPaymentReceipt" ADD CONSTRAINT "CashPaymentReceipt_destinationAccountId_fkey" FOREIGN KEY ("destinationAccountId") REFERENCES "BankAccount"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Shipment" ADD CONSTRAINT "Shipment_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- شمارنده تلاش ناموفق برای جلوگیری از حدسزدن کد ۴ رقمی
|
||||
ALTER TABLE "OtpChallenge" ADD COLUMN "attempts" INTEGER NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- روش تسویه دیگر در لحظه ثبت سفارش گرفته نمیشود؛ مشتری بعد از قیمتگذاری انتخاب میکند.
|
||||
ALTER TABLE "Order" ALTER COLUMN "settlementType" DROP NOT NULL;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- اعلان درونبرنامهای مشتری بههمراه سوئیچ پیامک «فاکتور آماده شد»
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN "smsPricingReady" BOOLEAN NOT NULL DEFAULT true;
|
||||
|
||||
CREATE TABLE "CustomerNotification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"orderId" TEXT,
|
||||
"event" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"body" TEXT NOT NULL,
|
||||
"tone" "NotificationTone" DEFAULT 'info',
|
||||
"link" TEXT,
|
||||
"isRead" BOOLEAN NOT NULL DEFAULT false,
|
||||
"smsSent" BOOLEAN NOT NULL DEFAULT false,
|
||||
"sentAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "CustomerNotification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "CustomerNotification_customerId_isRead_idx" ON "CustomerNotification"("customerId", "isRead");
|
||||
CREATE INDEX "CustomerNotification_sentAt_idx" ON "CustomerNotification"("sentAt");
|
||||
|
||||
ALTER TABLE "CustomerNotification" ADD CONSTRAINT "CustomerNotification_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CustomerNotification" ADD CONSTRAINT "CustomerNotification_orderId_fkey" FOREIGN KEY ("orderId") REFERENCES "Order"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- سقف متراژ شرکت اختیاری میشود؛ خالی یعنی از SystemSettings ارث میبرد.
|
||||
ALTER TABLE "Company" ALTER COLUMN "maxMeteragePerInvoice" DROP NOT NULL;
|
||||
ALTER TABLE "Company" ALTER COLUMN "maxMeteragePerInvoice" DROP DEFAULT;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- یادآوری پایان مهلت پرداخت فقط یکبار برای هر فاکتور ارسال میشود.
|
||||
ALTER TABLE "Order" ADD COLUMN "cashReminderSentAt" TIMESTAMP(3);
|
||||
|
||||
CREATE INDEX "Order_status_cashInvoiceExpiresAt_idx" ON "Order"("status", "cashInvoiceExpiresAt");
|
||||
@@ -0,0 +1,15 @@
|
||||
-- اقلام سفارش شرکت خود را نگه میدارند تا یک فاکتور چندشرکتی ممکن شود.
|
||||
ALTER TABLE "OrderItem" ADD COLUMN "companyId" TEXT;
|
||||
ALTER TABLE "OrderItem" ADD COLUMN "companyName" TEXT;
|
||||
|
||||
UPDATE "OrderItem" AS oi
|
||||
SET
|
||||
"companyId" = o."companyId",
|
||||
"companyName" = o."companyName"
|
||||
FROM "Order" AS o
|
||||
WHERE oi."orderId" = o."id";
|
||||
|
||||
ALTER TABLE "OrderItem" ALTER COLUMN "companyId" SET NOT NULL;
|
||||
ALTER TABLE "OrderItem" ALTER COLUMN "companyName" SET NOT NULL;
|
||||
|
||||
CREATE INDEX "OrderItem_companyId_idx" ON "OrderItem"("companyId");
|
||||
@@ -0,0 +1,122 @@
|
||||
-- AlterEnum
|
||||
CREATE TYPE "AppUserRole" AS ENUM ('customer', 'agent');
|
||||
CREATE TYPE "InteractionType" AS ENUM ('in_person', 'call', 'message', 'note');
|
||||
CREATE TYPE "ProductSeason" AS ENUM ('summer', 'winter', 'all_season');
|
||||
CREATE TYPE "ProductUsageCategory" AS ENUM ('trousers', 'suit', 'shirt', 'other');
|
||||
|
||||
-- AlterTable Product
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "usageCategory" "ProductUsageCategory" NOT NULL DEFAULT 'other';
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "season" "ProductSeason" NOT NULL DEFAULT 'all_season';
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "widthCm" DOUBLE PRECISION;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "composition" TEXT;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "weightGrams" DOUBLE PRECISION;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "weaveType" TEXT;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "colorsJson" JSONB;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "tagsJson" JSONB;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "imageUrlsJson" JSONB;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "subtitle" TEXT;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "rollMeters" DOUBLE PRECISION NOT NULL DEFAULT 50;
|
||||
ALTER TABLE "Product" ADD COLUMN IF NOT EXISTS "isNew" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Product_usageCategory_idx" ON "Product"("usageCategory");
|
||||
CREATE INDEX IF NOT EXISTS "Product_season_idx" ON "Product"("season");
|
||||
|
||||
-- AlterTable Customer
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "appRole" "AppUserRole" NOT NULL DEFAULT 'customer';
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "agentCode" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "businessName" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "levelLabel" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "nextLevelLabel" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "pointsToNext" INTEGER;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "levelProgress" INTEGER DEFAULT 0;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "assignedAgentId" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "avatarLetter" TEXT;
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "avatarColor" TEXT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Customer_appRole_idx" ON "Customer"("appRole");
|
||||
CREATE INDEX IF NOT EXISTS "Customer_assignedAgentId_idx" ON "Customer"("assignedAgentId");
|
||||
CREATE INDEX IF NOT EXISTS "Customer_agentCode_idx" ON "Customer"("agentCode");
|
||||
|
||||
ALTER TABLE "Customer"
|
||||
ADD CONSTRAINT "Customer_assignedAgentId_fkey"
|
||||
FOREIGN KEY ("assignedAgentId") REFERENCES "Customer"("id")
|
||||
ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- MeetingInteraction
|
||||
CREATE TABLE IF NOT EXISTS "MeetingInteraction" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"agentId" TEXT NOT NULL,
|
||||
"type" "InteractionType" NOT NULL DEFAULT 'in_person',
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"subject" TEXT,
|
||||
"content" TEXT,
|
||||
"date" TEXT NOT NULL,
|
||||
"time" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "MeetingInteraction_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "MeetingInteraction_customerId_idx" ON "MeetingInteraction"("customerId");
|
||||
CREATE INDEX IF NOT EXISTS "MeetingInteraction_agentId_idx" ON "MeetingInteraction"("agentId");
|
||||
CREATE INDEX IF NOT EXISTS "MeetingInteraction_date_idx" ON "MeetingInteraction"("date");
|
||||
|
||||
ALTER TABLE "MeetingInteraction"
|
||||
ADD CONSTRAINT "MeetingInteraction_customerId_fkey"
|
||||
FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "MeetingInteraction"
|
||||
ADD CONSTRAINT "MeetingInteraction_agentId_fkey"
|
||||
FOREIGN KEY ("agentId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- Reminder
|
||||
CREATE TABLE IF NOT EXISTS "Reminder" (
|
||||
"id" TEXT NOT NULL,
|
||||
"ownerId" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"note" TEXT,
|
||||
"date" TEXT NOT NULL,
|
||||
"time" TEXT NOT NULL,
|
||||
"interactionType" "InteractionType" NOT NULL DEFAULT 'note',
|
||||
"completed" BOOLEAN NOT NULL DEFAULT false,
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "Reminder_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Reminder_ownerId_completed_idx" ON "Reminder"("ownerId", "completed");
|
||||
CREATE INDEX IF NOT EXISTS "Reminder_customerId_idx" ON "Reminder"("customerId");
|
||||
CREATE INDEX IF NOT EXISTS "Reminder_date_idx" ON "Reminder"("date");
|
||||
|
||||
ALTER TABLE "Reminder"
|
||||
ADD CONSTRAINT "Reminder_ownerId_fkey"
|
||||
FOREIGN KEY ("ownerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "Reminder"
|
||||
ADD CONSTRAINT "Reminder_customerId_fkey"
|
||||
FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- ProductFavorite
|
||||
CREATE TABLE IF NOT EXISTS "ProductFavorite" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"productId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "ProductFavorite_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS "ProductFavorite_customerId_productId_key" ON "ProductFavorite"("customerId", "productId");
|
||||
CREATE INDEX IF NOT EXISTS "ProductFavorite_customerId_idx" ON "ProductFavorite"("customerId");
|
||||
|
||||
ALTER TABLE "ProductFavorite"
|
||||
ADD CONSTRAINT "ProductFavorite_customerId_fkey"
|
||||
FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE "ProductFavorite"
|
||||
ADD CONSTRAINT "ProductFavorite_productId_fkey"
|
||||
FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,149 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CatalogRequestStatus" AS ENUM ('new', 'approved', 'ready_to_ship', 'delivered', 'returned', 'cancelled');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "CatalogItemHolderType" AS ENUM ('warehouse', 'customer', 'agent');
|
||||
|
||||
-- AlterTable SystemSettings
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN IF NOT EXISTS "minOrderRollsPerProduct" INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN IF NOT EXISTS "showCatalogPublicPrice" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- CreateTable Brand
|
||||
CREATE TABLE "Brand" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT,
|
||||
"description" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"displayOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "Brand_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "Brand_slug_key" ON "Brand"("slug");
|
||||
|
||||
-- CreateTable CustomerLevelDef
|
||||
CREATE TABLE "CustomerLevelDef" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"label" TEXT NOT NULL,
|
||||
"sortOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"criteriaJson" JSONB,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "CustomerLevelDef_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "CustomerLevelDef_code_key" ON "CustomerLevelDef"("code");
|
||||
|
||||
-- CreateTable LevelBenefit
|
||||
CREATE TABLE "LevelBenefit" (
|
||||
"id" TEXT NOT NULL,
|
||||
"levelId" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
CONSTRAINT "LevelBenefit_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "LevelBenefit_levelId_idx" ON "LevelBenefit"("levelId");
|
||||
|
||||
-- AlterTable Customer
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "levelDefId" TEXT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Customer_levelDefId_idx" ON "Customer"("levelDefId");
|
||||
|
||||
-- CreateTable CustomerBrand
|
||||
CREATE TABLE "CustomerBrand" (
|
||||
"customerId" TEXT NOT NULL,
|
||||
"brandId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "CustomerBrand_pkey" PRIMARY KEY ("customerId","brandId")
|
||||
);
|
||||
|
||||
CREATE INDEX "CustomerBrand_brandId_idx" ON "CustomerBrand"("brandId");
|
||||
|
||||
-- CreateTable CatalogRequest
|
||||
CREATE TABLE "CatalogRequest" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"status" "CatalogRequestStatus" NOT NULL DEFAULT 'new',
|
||||
"note" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
CONSTRAINT "CatalogRequest_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "CatalogRequest_customerId_idx" ON "CatalogRequest"("customerId");
|
||||
CREATE INDEX "CatalogRequest_status_idx" ON "CatalogRequest"("status");
|
||||
|
||||
-- CreateTable CatalogRequestItem
|
||||
CREATE TABLE "CatalogRequestItem" (
|
||||
"id" TEXT NOT NULL,
|
||||
"requestId" TEXT NOT NULL,
|
||||
"productId" TEXT NOT NULL,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"holderType" "CatalogItemHolderType" NOT NULL DEFAULT 'warehouse',
|
||||
"holderCustomerId" TEXT,
|
||||
CONSTRAINT "CatalogRequestItem_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "CatalogRequestItem_requestId_idx" ON "CatalogRequestItem"("requestId");
|
||||
CREATE INDEX "CatalogRequestItem_productId_idx" ON "CatalogRequestItem"("productId");
|
||||
|
||||
-- CreateTable CatalogItemMovement
|
||||
CREATE TABLE "CatalogItemMovement" (
|
||||
"id" TEXT NOT NULL,
|
||||
"itemId" TEXT NOT NULL,
|
||||
"fromHolder" TEXT NOT NULL,
|
||||
"toHolder" TEXT NOT NULL,
|
||||
"note" TEXT,
|
||||
"movedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "CatalogItemMovement_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "CatalogItemMovement_itemId_idx" ON "CatalogItemMovement"("itemId");
|
||||
|
||||
-- CreateTable StockNotifyRequest
|
||||
CREATE TABLE "StockNotifyRequest" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"productId" TEXT NOT NULL,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"notifiedAt" TIMESTAMP(3),
|
||||
CONSTRAINT "StockNotifyRequest_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX "StockNotifyRequest_customerId_productId_key" ON "StockNotifyRequest"("customerId", "productId");
|
||||
CREATE INDEX "StockNotifyRequest_productId_active_idx" ON "StockNotifyRequest"("productId", "active");
|
||||
|
||||
-- CreateTable ProductSuggestion
|
||||
CREATE TABLE "ProductSuggestion" (
|
||||
"id" TEXT NOT NULL,
|
||||
"customerId" TEXT NOT NULL,
|
||||
"productId" TEXT NOT NULL,
|
||||
"note" TEXT,
|
||||
"createdByAdminId" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "ProductSuggestion_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX "ProductSuggestion_customerId_isActive_idx" ON "ProductSuggestion"("customerId", "isActive");
|
||||
CREATE INDEX "ProductSuggestion_productId_idx" ON "ProductSuggestion"("productId");
|
||||
|
||||
-- FKs
|
||||
ALTER TABLE "Customer" ADD CONSTRAINT "Customer_levelDefId_fkey" FOREIGN KEY ("levelDefId") REFERENCES "CustomerLevelDef"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
ALTER TABLE "LevelBenefit" ADD CONSTRAINT "LevelBenefit_levelId_fkey" FOREIGN KEY ("levelId") REFERENCES "CustomerLevelDef"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CustomerBrand" ADD CONSTRAINT "CustomerBrand_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CustomerBrand" ADD CONSTRAINT "CustomerBrand_brandId_fkey" FOREIGN KEY ("brandId") REFERENCES "Brand"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CatalogRequest" ADD CONSTRAINT "CatalogRequest_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CatalogRequestItem" ADD CONSTRAINT "CatalogRequestItem_requestId_fkey" FOREIGN KEY ("requestId") REFERENCES "CatalogRequest"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "CatalogRequestItem" ADD CONSTRAINT "CatalogRequestItem_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE "CatalogItemMovement" ADD CONSTRAINT "CatalogItemMovement_itemId_fkey" FOREIGN KEY ("itemId") REFERENCES "CatalogRequestItem"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "StockNotifyRequest" ADD CONSTRAINT "StockNotifyRequest_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "StockNotifyRequest" ADD CONSTRAINT "StockNotifyRequest_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ProductSuggestion" ADD CONSTRAINT "ProductSuggestion_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
ALTER TABLE "ProductSuggestion" ADD CONSTRAINT "ProductSuggestion_productId_fkey" FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN IF NOT EXISTS "allowAgentPricing" BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN IF NOT EXISTS "agentMinUnitPrice" INTEGER;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE "Customer" ADD COLUMN IF NOT EXISTS "avatarUrl" TEXT;
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE "SystemSettings" ADD COLUMN IF NOT EXISTS "categoryImagesJson" JSONB;
|
||||
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE IF NOT EXISTS "AppBanner" (
|
||||
"id" TEXT NOT NULL,
|
||||
"slot" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"subtitle" TEXT,
|
||||
"ctaLabel" TEXT,
|
||||
"ctaLink" TEXT,
|
||||
"imageUrl" TEXT,
|
||||
"displayOrder" INTEGER NOT NULL DEFAULT 0,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "AppBanner_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "AppBanner_slot_isActive_displayOrder_idx"
|
||||
ON "AppBanner"("slot", "isActive", "displayOrder");
|
||||
|
||||
INSERT INTO "AppBanner" ("id", "slot", "title", "subtitle", "ctaLabel", "ctaLink", "displayOrder", "isActive", "createdAt", "updatedAt")
|
||||
SELECT 'home-hero-default', 'home_hero', 'کالکشن پاییز و زمستان', 'جدیدترین پارچهها', 'مشاهده کالکشن', '/categories', 0, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
|
||||
WHERE NOT EXISTS (SELECT 1 FROM "AppBanner" WHERE "id" = 'home-hero-default');
|
||||
@@ -0,0 +1 @@
|
||||
provider = "postgresql"
|
||||
@@ -0,0 +1,751 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = ["native", "debian-openssl-3.0.x"]
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum SettlementType {
|
||||
cash
|
||||
check
|
||||
}
|
||||
|
||||
enum CheckRegistrationMode {
|
||||
full
|
||||
brief
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
cart
|
||||
awaiting_settlement
|
||||
cash_in_progress
|
||||
check_in_progress
|
||||
submitted
|
||||
awaiting_review
|
||||
pricing
|
||||
needs_correction
|
||||
awaiting_settlement_fix
|
||||
cash_invoice_issued
|
||||
awaiting_cash_payment
|
||||
cash_payment_submitted
|
||||
awaiting_cash_confirmation
|
||||
cash_confirmed
|
||||
awaiting_check_review
|
||||
check_needs_fix
|
||||
check_rejected
|
||||
checks_approved
|
||||
final_approved
|
||||
preparing
|
||||
ready_to_ship
|
||||
shipped
|
||||
delivered
|
||||
cancelled
|
||||
rejected
|
||||
expired
|
||||
}
|
||||
|
||||
enum CheckStatus {
|
||||
pending_review
|
||||
approved
|
||||
rejected
|
||||
}
|
||||
|
||||
enum CashPaymentStatus {
|
||||
pending_review
|
||||
approved
|
||||
rejected
|
||||
expired
|
||||
}
|
||||
|
||||
enum ShipmentStatus {
|
||||
preparing
|
||||
ready
|
||||
shipped
|
||||
delivered
|
||||
}
|
||||
|
||||
enum CustomerType {
|
||||
wholesale
|
||||
retail
|
||||
}
|
||||
|
||||
enum AppUserRole {
|
||||
customer
|
||||
agent
|
||||
}
|
||||
|
||||
enum InteractionType {
|
||||
in_person
|
||||
call
|
||||
message
|
||||
note
|
||||
}
|
||||
|
||||
enum ProductSeason {
|
||||
summer
|
||||
winter
|
||||
all_season
|
||||
}
|
||||
|
||||
enum ProductUsageCategory {
|
||||
trousers
|
||||
suit
|
||||
shirt
|
||||
other
|
||||
}
|
||||
|
||||
enum AdminRole {
|
||||
admin
|
||||
sales
|
||||
finance
|
||||
warehouse
|
||||
}
|
||||
|
||||
enum NotificationTone {
|
||||
info
|
||||
warning
|
||||
success
|
||||
danger
|
||||
}
|
||||
|
||||
/// گردش کالیته فیزیکی (§۷ سند)
|
||||
enum CatalogRequestStatus {
|
||||
new
|
||||
approved
|
||||
ready_to_ship
|
||||
delivered
|
||||
returned
|
||||
cancelled
|
||||
}
|
||||
|
||||
enum CatalogItemHolderType {
|
||||
warehouse
|
||||
customer
|
||||
agent
|
||||
}
|
||||
|
||||
model Company {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String @unique
|
||||
description String?
|
||||
logoUrl String?
|
||||
isActive Boolean @default(true)
|
||||
displayOrder Int @default(0)
|
||||
/// خالی یعنی از تنظیمات سیستم ارث میبرد
|
||||
maxMeteragePerInvoice Int?
|
||||
cashInvoiceValidityHours Int @default(8)
|
||||
cashInvoiceValidUntilHour Int?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
bankAccounts BankAccount[]
|
||||
catalogs Catalog[]
|
||||
products Product[]
|
||||
orders Order[]
|
||||
customers Customer[]
|
||||
}
|
||||
|
||||
model BankAccount {
|
||||
id String @id @default(cuid())
|
||||
companyId String
|
||||
bankName String
|
||||
accountHolder String
|
||||
accountNumber String
|
||||
cardNumber String
|
||||
iban String
|
||||
notes String?
|
||||
isActive Boolean @default(true)
|
||||
displayOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
cashReceipts CashPaymentReceipt[]
|
||||
|
||||
@@index([companyId])
|
||||
}
|
||||
|
||||
model Catalog {
|
||||
id String @id @default(cuid())
|
||||
companyId String
|
||||
name String
|
||||
code String
|
||||
description String?
|
||||
displayOrder Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
products Product[]
|
||||
|
||||
@@unique([companyId, code])
|
||||
@@index([companyId])
|
||||
}
|
||||
|
||||
model Product {
|
||||
id String @id @default(cuid())
|
||||
companyId String
|
||||
catalogId String
|
||||
name String
|
||||
code String
|
||||
color String
|
||||
description String?
|
||||
minMeterage Float @default(30)
|
||||
orderMultiplier Float @default(10)
|
||||
basePrice Float?
|
||||
stock Float?
|
||||
isActive Boolean @default(true)
|
||||
/// فیلدهای نمایش کاتالوگ موکاپ (اپ کاربر)
|
||||
usageCategory ProductUsageCategory @default(other)
|
||||
season ProductSeason @default(all_season)
|
||||
widthCm Float?
|
||||
composition String?
|
||||
weightGrams Float?
|
||||
weaveType String?
|
||||
colorsJson Json?
|
||||
tagsJson Json?
|
||||
imageUrlsJson Json?
|
||||
subtitle String?
|
||||
rollMeters Float @default(50)
|
||||
isNew Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
||||
catalog Catalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
|
||||
cartItems CartItem[]
|
||||
orderItems OrderItem[]
|
||||
favorites ProductFavorite[]
|
||||
catalogRequestItems CatalogRequestItem[]
|
||||
stockNotifyRequests StockNotifyRequest[]
|
||||
productSuggestions ProductSuggestion[]
|
||||
|
||||
@@unique([companyId, code])
|
||||
@@index([catalogId])
|
||||
@@index([companyId])
|
||||
@@index([usageCategory])
|
||||
@@index([season])
|
||||
}
|
||||
|
||||
model Customer {
|
||||
id String @id @default(cuid())
|
||||
firstName String
|
||||
lastName String
|
||||
phone String @unique
|
||||
nationalId String?
|
||||
customerType CustomerType @default(wholesale)
|
||||
/// نقش در اپ کاربر: مشتری عادی یا واسطه
|
||||
appRole AppUserRole @default(customer)
|
||||
agentCode String?
|
||||
businessName String?
|
||||
levelLabel String?
|
||||
nextLevelLabel String?
|
||||
pointsToNext Int?
|
||||
levelProgress Int? @default(0)
|
||||
assignedAgentId String?
|
||||
avatarLetter String?
|
||||
avatarColor String?
|
||||
avatarUrl String?
|
||||
companyId String?
|
||||
levelDefId String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
||||
levelDef CustomerLevelDef? @relation(fields: [levelDefId], references: [id], onDelete: SetNull)
|
||||
assignedAgent Customer? @relation("AgentCustomers", fields: [assignedAgentId], references: [id], onDelete: SetNull)
|
||||
agentCustomers Customer[] @relation("AgentCustomers")
|
||||
carts Cart[]
|
||||
orders Order[]
|
||||
notifications CustomerNotification[]
|
||||
meetings MeetingInteraction[] @relation("MeetingCustomer")
|
||||
meetingsAsAgent MeetingInteraction[] @relation("MeetingAgent")
|
||||
reminders Reminder[] @relation("ReminderOwner")
|
||||
remindersAbout Reminder[] @relation("ReminderCustomer")
|
||||
favorites ProductFavorite[]
|
||||
catalogRequests CatalogRequest[]
|
||||
stockNotifyRequests StockNotifyRequest[]
|
||||
productSuggestions ProductSuggestion[]
|
||||
customerBrands CustomerBrand[]
|
||||
|
||||
@@index([companyId])
|
||||
@@index([appRole])
|
||||
@@index([assignedAgentId])
|
||||
@@index([agentCode])
|
||||
@@index([levelDefId])
|
||||
}
|
||||
|
||||
model AdminUser {
|
||||
id String @id @default(cuid())
|
||||
fullName String
|
||||
phone String @unique
|
||||
email String @unique
|
||||
passwordHash String
|
||||
role AdminRole @default(admin)
|
||||
isActive Boolean @default(true)
|
||||
lastLoginAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model OtpChallenge {
|
||||
id String @id @default(cuid())
|
||||
phone String
|
||||
code String
|
||||
firstName String?
|
||||
lastName String?
|
||||
isRegister Boolean @default(false)
|
||||
attempts Int @default(0)
|
||||
expiresAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([phone])
|
||||
}
|
||||
|
||||
model Cart {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
companyId String?
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user Customer @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
items CartItem[]
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model CartItem {
|
||||
id String @id @default(cuid())
|
||||
cartId String
|
||||
productId String
|
||||
catalogCode String
|
||||
productName String
|
||||
productCode String
|
||||
color String
|
||||
meterage Float
|
||||
unitPrice Float?
|
||||
notes String?
|
||||
companyId String
|
||||
companyName String
|
||||
|
||||
cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Restrict)
|
||||
|
||||
@@unique([cartId, productId])
|
||||
@@index([cartId])
|
||||
}
|
||||
|
||||
model Order {
|
||||
id String @id @default(cuid())
|
||||
orderNumber String @unique
|
||||
userId String
|
||||
companyId String
|
||||
companyName String
|
||||
// روش تسویه بعد از قیمتگذاری ادمین توسط مشتری انتخاب میشود
|
||||
settlementType SettlementType?
|
||||
checkMode CheckRegistrationMode?
|
||||
status OrderStatus @default(awaiting_review)
|
||||
totalMeterage Float @default(0)
|
||||
totalAmount Float?
|
||||
shippingCost Float?
|
||||
totalDiscount Float?
|
||||
finalAmount Float?
|
||||
notes String?
|
||||
checkRassDays Int?
|
||||
checkRassDate DateTime?
|
||||
cashInvoiceExpiresAt DateTime?
|
||||
/// زمان ارسال یادآوری پایان مهلت پرداخت تا دوباره ارسال نشود
|
||||
cashReminderSentAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user Customer @relation(fields: [userId], references: [id], onDelete: Restrict)
|
||||
company Company @relation(fields: [companyId], references: [id], onDelete: Restrict)
|
||||
items OrderItem[]
|
||||
checks Check[]
|
||||
cashReceipt CashPaymentReceipt?
|
||||
shipment Shipment?
|
||||
statusHistory OrderStatusHistory[]
|
||||
notifications CustomerNotification[]
|
||||
|
||||
@@index([userId])
|
||||
@@index([companyId])
|
||||
@@index([status])
|
||||
@@index([createdAt])
|
||||
@@index([status, cashInvoiceExpiresAt])
|
||||
}
|
||||
|
||||
model OrderItem {
|
||||
id String @id @default(cuid())
|
||||
orderId String
|
||||
productId String?
|
||||
catalogCode String
|
||||
productName String
|
||||
productCode String?
|
||||
color String
|
||||
requestedMeterage Float
|
||||
confirmedMeterage Float?
|
||||
unitPrice Float?
|
||||
unitDiscount Float? @default(0)
|
||||
lineTotal Float?
|
||||
notes String?
|
||||
companyId String
|
||||
companyName String
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||||
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([orderId])
|
||||
@@index([companyId])
|
||||
}
|
||||
|
||||
model OrderStatusHistory {
|
||||
id String @id @default(cuid())
|
||||
orderId String
|
||||
fromStatus OrderStatus?
|
||||
toStatus OrderStatus
|
||||
changedBy String
|
||||
note String?
|
||||
reason String?
|
||||
changedAt DateTime @default(now())
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([orderId])
|
||||
}
|
||||
|
||||
model Check {
|
||||
id String @id @default(cuid())
|
||||
orderId String
|
||||
row Int
|
||||
amount Float
|
||||
dueDate DateTime
|
||||
sayadId String?
|
||||
checkNumber String?
|
||||
ownerNationalId String?
|
||||
ownerFirstName String?
|
||||
ownerLastName String?
|
||||
bankName String?
|
||||
branchName String?
|
||||
frontImage String?
|
||||
backImage String?
|
||||
notes String?
|
||||
mode CheckRegistrationMode @default(full)
|
||||
status CheckStatus @default(pending_review)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([orderId])
|
||||
@@index([dueDate])
|
||||
}
|
||||
|
||||
model CashPaymentReceipt {
|
||||
id String @id @default(cuid())
|
||||
orderId String @unique
|
||||
amount Float
|
||||
paidAmount Float?
|
||||
transferDate DateTime?
|
||||
transferTime String?
|
||||
trackingNumber String?
|
||||
destinationAccountId String?
|
||||
receiptImage String?
|
||||
notes String?
|
||||
expiresAt DateTime?
|
||||
status CashPaymentStatus @default(pending_review)
|
||||
submittedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||||
destinationAccount BankAccount? @relation(fields: [destinationAccountId], references: [id], onDelete: SetNull)
|
||||
}
|
||||
|
||||
model Shipment {
|
||||
id String @id @default(cuid())
|
||||
orderId String @unique
|
||||
carrier String
|
||||
trackingNumber String?
|
||||
meterage Float
|
||||
status ShipmentStatus @default(preparing)
|
||||
shippedAt DateTime?
|
||||
deliveredAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model SystemSettings {
|
||||
id String @id @default("default")
|
||||
maxMeteragePerInvoice Int @default(5000)
|
||||
cashInvoiceValidityHours Int @default(8)
|
||||
defaultSettlementCheck Boolean @default(true)
|
||||
defaultSettlementCash Boolean @default(true)
|
||||
/// حداقل سفارش: تعداد طاقه از هر محصول (§۱۹)
|
||||
minOrderRollsPerProduct Int @default(1)
|
||||
/// نمایش قیمت عمومی در کاتالوگ (پیشفرض خاموش)
|
||||
showCatalogPublicPrice Boolean @default(false)
|
||||
/// اجازه قیمتگذاری توسط واسطه (§۱۹)
|
||||
allowAgentPricing Boolean @default(false)
|
||||
/// کف قیمت واحد برای قیمتگذاری واسطه (ریال) — اختیاری
|
||||
agentMinUnitPrice Int?
|
||||
smsOrderRegistered Boolean @default(true)
|
||||
smsPricingReady Boolean @default(true)
|
||||
smsPaymentReminder Boolean @default(true)
|
||||
smsCheckReview Boolean @default(true)
|
||||
smsShippingUpdate Boolean @default(true)
|
||||
supportPhone String?
|
||||
supportEmail String?
|
||||
/// تصاویر دستههای کاربرد/فصل اپ کاربر: { trousers: dataUrl, summer: dataUrl, ... }
|
||||
categoryImagesJson Json?
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
/// بنرهای قابل مدیریت بخشهای اپ کاربر
|
||||
model AppBanner {
|
||||
id String @id @default(cuid())
|
||||
slot String
|
||||
title String
|
||||
subtitle String?
|
||||
ctaLabel String?
|
||||
ctaLink String?
|
||||
imageUrl String?
|
||||
displayOrder Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([slot, isActive, displayOrder])
|
||||
}
|
||||
|
||||
model AdminNotification {
|
||||
id String @id @default(cuid())
|
||||
title String
|
||||
body String
|
||||
tone NotificationTone? @default(info)
|
||||
link String?
|
||||
isRead Boolean @default(false)
|
||||
sentAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model CustomerNotification {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
orderId String?
|
||||
event String
|
||||
title String
|
||||
body String
|
||||
tone NotificationTone? @default(info)
|
||||
link String?
|
||||
isRead Boolean @default(false)
|
||||
smsSent Boolean @default(false)
|
||||
sentAt DateTime @default(now())
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
order Order? @relation(fields: [orderId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([customerId, isRead])
|
||||
@@index([sentAt])
|
||||
}
|
||||
|
||||
model InternalMessage {
|
||||
id String @id @default(cuid())
|
||||
senderName String
|
||||
subject String
|
||||
preview String
|
||||
isRead Boolean @default(false)
|
||||
sentAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model MeetingInteraction {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
agentId String
|
||||
type InteractionType @default(in_person)
|
||||
title String
|
||||
description String?
|
||||
subject String?
|
||||
content String?
|
||||
date String
|
||||
time String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
customer Customer @relation("MeetingCustomer", fields: [customerId], references: [id], onDelete: Cascade)
|
||||
agent Customer @relation("MeetingAgent", fields: [agentId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([customerId])
|
||||
@@index([agentId])
|
||||
@@index([date])
|
||||
}
|
||||
|
||||
model Reminder {
|
||||
id String @id @default(cuid())
|
||||
ownerId String
|
||||
customerId String
|
||||
title String
|
||||
description String?
|
||||
note String?
|
||||
date String
|
||||
time String
|
||||
interactionType InteractionType @default(note)
|
||||
completed Boolean @default(false)
|
||||
completedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
owner Customer @relation("ReminderOwner", fields: [ownerId], references: [id], onDelete: Cascade)
|
||||
customer Customer @relation("ReminderCustomer", fields: [customerId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([ownerId, completed])
|
||||
@@index([customerId])
|
||||
@@index([date])
|
||||
}
|
||||
|
||||
model ProductFavorite {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
productId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([customerId, productId])
|
||||
@@index([customerId])
|
||||
}
|
||||
|
||||
model Brand {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
slug String? @unique
|
||||
description String?
|
||||
isActive Boolean @default(true)
|
||||
displayOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
customers CustomerBrand[]
|
||||
}
|
||||
|
||||
model CustomerBrand {
|
||||
customerId String
|
||||
brandId String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
brand Brand @relation(fields: [brandId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@id([customerId, brandId])
|
||||
@@index([brandId])
|
||||
}
|
||||
|
||||
model CustomerLevelDef {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
label String
|
||||
sortOrder Int @default(0)
|
||||
criteriaJson Json?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
benefits LevelBenefit[]
|
||||
customers Customer[]
|
||||
}
|
||||
|
||||
model LevelBenefit {
|
||||
id String @id @default(cuid())
|
||||
levelId String
|
||||
title String
|
||||
description String?
|
||||
|
||||
level CustomerLevelDef @relation(fields: [levelId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([levelId])
|
||||
}
|
||||
|
||||
model CatalogRequest {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
status CatalogRequestStatus @default(new)
|
||||
note String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
items CatalogRequestItem[]
|
||||
|
||||
@@index([customerId])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model CatalogRequestItem {
|
||||
id String @id @default(cuid())
|
||||
requestId String
|
||||
productId String
|
||||
quantity Int @default(1)
|
||||
holderType CatalogItemHolderType @default(warehouse)
|
||||
holderCustomerId String?
|
||||
|
||||
request CatalogRequest @relation(fields: [requestId], references: [id], onDelete: Cascade)
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Restrict)
|
||||
movements CatalogItemMovement[]
|
||||
|
||||
@@index([requestId])
|
||||
@@index([productId])
|
||||
}
|
||||
|
||||
model CatalogItemMovement {
|
||||
id String @id @default(cuid())
|
||||
itemId String
|
||||
fromHolder String
|
||||
toHolder String
|
||||
note String?
|
||||
movedAt DateTime @default(now())
|
||||
|
||||
item CatalogRequestItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([itemId])
|
||||
}
|
||||
|
||||
model StockNotifyRequest {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
productId String
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
notifiedAt DateTime?
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([customerId, productId])
|
||||
@@index([productId, active])
|
||||
}
|
||||
|
||||
model ProductSuggestion {
|
||||
id String @id @default(cuid())
|
||||
customerId String
|
||||
productId String
|
||||
note String?
|
||||
createdByAdminId String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade)
|
||||
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([customerId, isActive])
|
||||
@@index([productId])
|
||||
}
|
||||
+882
@@ -0,0 +1,882 @@
|
||||
import {
|
||||
PrismaClient,
|
||||
AdminRole,
|
||||
AppUserRole,
|
||||
CustomerType,
|
||||
OrderStatus,
|
||||
SettlementType,
|
||||
CheckRegistrationMode,
|
||||
CheckStatus,
|
||||
CashPaymentStatus,
|
||||
ShipmentStatus,
|
||||
InteractionType,
|
||||
ProductSeason,
|
||||
ProductUsageCategory,
|
||||
} from '@prisma/client';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('Seeding fabric_trade database...');
|
||||
|
||||
await prisma.productFavorite.deleteMany();
|
||||
await prisma.reminder.deleteMany();
|
||||
await prisma.meetingInteraction.deleteMany();
|
||||
await prisma.orderStatusHistory.deleteMany();
|
||||
await prisma.cashPaymentReceipt.deleteMany();
|
||||
await prisma.check.deleteMany();
|
||||
await prisma.shipment.deleteMany();
|
||||
await prisma.orderItem.deleteMany();
|
||||
await prisma.order.deleteMany();
|
||||
await prisma.cartItem.deleteMany();
|
||||
await prisma.cart.deleteMany();
|
||||
await prisma.otpChallenge.deleteMany();
|
||||
await prisma.customerNotification.deleteMany();
|
||||
await prisma.product.deleteMany();
|
||||
await prisma.catalog.deleteMany();
|
||||
await prisma.bankAccount.deleteMany();
|
||||
await prisma.customer.deleteMany();
|
||||
await prisma.company.deleteMany();
|
||||
await prisma.adminUser.deleteMany();
|
||||
await prisma.adminNotification.deleteMany();
|
||||
await prisma.internalMessage.deleteMany();
|
||||
await prisma.systemSettings.deleteMany();
|
||||
|
||||
const passwordHash = await bcrypt.hash('123456', 10);
|
||||
|
||||
await prisma.adminUser.create({
|
||||
data: {
|
||||
id: 'usr-1',
|
||||
fullName: 'مدیر سیستم',
|
||||
phone: '09128081392',
|
||||
email: 'admin@parche.ir',
|
||||
passwordHash,
|
||||
role: AdminRole.admin,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.company.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'company-par',
|
||||
name: 'شرکت پَر',
|
||||
slug: 'par',
|
||||
description: 'تولیدکننده پارچههای باکیفیت',
|
||||
isActive: true,
|
||||
displayOrder: 1,
|
||||
maxMeteragePerInvoice: null,
|
||||
cashInvoiceValidityHours: 8,
|
||||
cashInvoiceValidUntilHour: 17,
|
||||
},
|
||||
{
|
||||
id: 'company-fam-baft',
|
||||
name: 'فامبافت',
|
||||
slug: 'fam-baft',
|
||||
description: 'عرضه پارچههای تخصصی',
|
||||
isActive: true,
|
||||
displayOrder: 2,
|
||||
maxMeteragePerInvoice: null,
|
||||
cashInvoiceValidityHours: 8,
|
||||
cashInvoiceValidUntilHour: 17,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.bankAccount.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'ba-par-1',
|
||||
companyId: 'company-par',
|
||||
bankName: 'بانک ملی',
|
||||
accountHolder: 'شرکت پَر',
|
||||
accountNumber: '0123456789',
|
||||
cardNumber: '6037-9912-3456-7890',
|
||||
iban: 'IR120170000000012345678901',
|
||||
isActive: true,
|
||||
displayOrder: 1,
|
||||
},
|
||||
{
|
||||
id: 'ba-par-2',
|
||||
companyId: 'company-par',
|
||||
bankName: 'بانک صادرات',
|
||||
accountHolder: 'شرکت پَر',
|
||||
accountNumber: '9876543210',
|
||||
cardNumber: '6037-6912-3456-7891',
|
||||
iban: 'IR620190000000098765432101',
|
||||
isActive: true,
|
||||
displayOrder: 2,
|
||||
},
|
||||
{
|
||||
id: 'ba-fam-1',
|
||||
companyId: 'company-fam-baft',
|
||||
bankName: 'بانک ملت',
|
||||
accountHolder: 'فامبافت',
|
||||
accountNumber: '1122334455',
|
||||
cardNumber: '6104-3378-9012-3456',
|
||||
iban: 'IR450120000000011223344556',
|
||||
isActive: true,
|
||||
displayOrder: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.catalog.createMany({
|
||||
data: [
|
||||
{ id: 'cat-377', companyId: 'company-par', name: 'کالیته ۳۷۷', code: '377', displayOrder: 1, isActive: true },
|
||||
{ id: 'cat-378', companyId: 'company-par', name: 'کالیته ۳۷۸', code: '378', displayOrder: 2, isActive: true },
|
||||
{ id: 'cat-379', companyId: 'company-par', name: 'کالیته ۳۷۹', code: '379', displayOrder: 3, isActive: true },
|
||||
{ id: 'cat-380', companyId: 'company-par', name: 'کالیته ۳۸۰', code: '380', displayOrder: 4, isActive: true },
|
||||
{ id: 'cat-381', companyId: 'company-par', name: 'کالیته ۳۸۱', code: '381', displayOrder: 5, isActive: true },
|
||||
{ id: 'cat-fam-401', companyId: 'company-fam-baft', name: 'کالیته ۴۰۱', code: '401', displayOrder: 1, isActive: true },
|
||||
{ id: 'cat-fam-402', companyId: 'company-fam-baft', name: 'کالیته ۴۰۲', code: '402', displayOrder: 2, isActive: true },
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.product.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'prod-377-blue',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-377',
|
||||
name: 'فاستونی ایتالیایی',
|
||||
code: '377-BL',
|
||||
color: 'آبی',
|
||||
minMeterage: 30,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 185000,
|
||||
stock: 10000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.suit,
|
||||
season: ProductSeason.winter,
|
||||
widthCm: 150,
|
||||
composition: '۸۰٪ پشم، ۲۰٪ پلیاستر',
|
||||
weightGrams: 280,
|
||||
weaveType: 'تویل',
|
||||
colorsJson: ['#1e3a8a', '#111827', '#6b7280', '#92400e'],
|
||||
tagsJson: ['کتشلواری', 'زمستانه', 'رسمی'],
|
||||
subtitle: 'مناسب کت و شلوار رسمی',
|
||||
rollMeters: 50,
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
id: 'prod-377-black',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-377',
|
||||
name: 'پارچه مشکی رسمی',
|
||||
code: '377-BK',
|
||||
color: 'مشکی',
|
||||
minMeterage: 30,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 192000,
|
||||
stock: 8000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.trousers,
|
||||
season: ProductSeason.all_season,
|
||||
widthCm: 150,
|
||||
composition: '۷۰٪ پشم، ۳۰٪ پلیاستر',
|
||||
weightGrams: 260,
|
||||
weaveType: 'ساده',
|
||||
colorsJson: ['#111827', '#374151'],
|
||||
tagsJson: ['شلواری', 'چهارفصل'],
|
||||
subtitle: 'شلوار رسمی روزانه',
|
||||
rollMeters: 50,
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
id: 'prod-378-blue',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-378',
|
||||
name: 'پیراهنی نخی آبی',
|
||||
code: '378-BL',
|
||||
color: 'آبی',
|
||||
minMeterage: 50,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 200000,
|
||||
stock: 5000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.shirt,
|
||||
season: ProductSeason.summer,
|
||||
widthCm: 145,
|
||||
composition: '۱۰۰٪ پنبه',
|
||||
weightGrams: 120,
|
||||
weaveType: 'پاپلین',
|
||||
colorsJson: ['#3b82f6', '#93c5fd', '#ffffff'],
|
||||
tagsJson: ['پیراهنی', 'تابستانه'],
|
||||
subtitle: 'خنک و سبک',
|
||||
rollMeters: 40,
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
id: 'prod-378-black',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-378',
|
||||
name: 'پیراهنی مشکی',
|
||||
code: '378-BK',
|
||||
color: 'مشکی',
|
||||
minMeterage: 50,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 205000,
|
||||
stock: 5000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.shirt,
|
||||
season: ProductSeason.all_season,
|
||||
widthCm: 145,
|
||||
composition: '۹۵٪ پنبه، ۵٪ الاستان',
|
||||
weightGrams: 130,
|
||||
colorsJson: ['#111827', '#4b5563'],
|
||||
tagsJson: ['پیراهنی'],
|
||||
subtitle: 'پیراهن اداری',
|
||||
rollMeters: 40,
|
||||
isNew: false,
|
||||
},
|
||||
{
|
||||
id: 'prod-378-blue-white',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-378',
|
||||
name: 'آبی پشت سفید',
|
||||
code: '378-BLW',
|
||||
color: 'آبی پشت سفید',
|
||||
minMeterage: 50,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 210000,
|
||||
stock: 3000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.suit,
|
||||
season: ProductSeason.summer,
|
||||
widthCm: 150,
|
||||
composition: '۵۵٪ پشم، ۴۵٪ پلیاستر',
|
||||
weightGrams: 220,
|
||||
colorsJson: ['#60a5fa', '#f8fafc'],
|
||||
tagsJson: ['کتشلواری', 'تابستانه'],
|
||||
subtitle: 'سبک تابستانه',
|
||||
rollMeters: 50,
|
||||
isNew: false,
|
||||
},
|
||||
{
|
||||
id: 'prod-378-black-white',
|
||||
companyId: 'company-par',
|
||||
catalogId: 'cat-378',
|
||||
name: 'مشکی پشت سفید',
|
||||
code: '378-BKW',
|
||||
color: 'مشکی پشت سفید',
|
||||
minMeterage: 50,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 215000,
|
||||
stock: 3000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.trousers,
|
||||
season: ProductSeason.winter,
|
||||
widthCm: 150,
|
||||
composition: '۶۰٪ پشم، ۴۰٪ پلیاستر',
|
||||
weightGrams: 300,
|
||||
colorsJson: ['#111827', '#f8fafc'],
|
||||
tagsJson: ['شلواری', 'زمستانه'],
|
||||
subtitle: 'گرم زمستانه',
|
||||
rollMeters: 50,
|
||||
isNew: false,
|
||||
},
|
||||
{
|
||||
id: 'prod-fam-401-1',
|
||||
companyId: 'company-fam-baft',
|
||||
catalogId: 'cat-fam-401',
|
||||
name: 'پارچه مخمل',
|
||||
code: '401-MV',
|
||||
color: 'سرمهای',
|
||||
minMeterage: 40,
|
||||
orderMultiplier: 10,
|
||||
basePrice: 250000,
|
||||
stock: 6000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.suit,
|
||||
season: ProductSeason.winter,
|
||||
widthCm: 140,
|
||||
composition: 'مخمل پلیاستر',
|
||||
weightGrams: 320,
|
||||
colorsJson: ['#1e3a5f', '#7c2d12', '#365314'],
|
||||
tagsJson: ['کتشلواری', 'زمستانه'],
|
||||
subtitle: 'مخمل لوکس',
|
||||
rollMeters: 45,
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
id: 'prod-fam-401-2',
|
||||
companyId: 'company-fam-baft',
|
||||
catalogId: 'cat-fam-401',
|
||||
name: 'پارچه کجراه',
|
||||
code: '401-KJ',
|
||||
color: 'کرم',
|
||||
minMeterage: 40,
|
||||
orderMultiplier: 10,
|
||||
basePrice: null,
|
||||
stock: 4000,
|
||||
isActive: true,
|
||||
usageCategory: ProductUsageCategory.trousers,
|
||||
season: ProductSeason.all_season,
|
||||
widthCm: 150,
|
||||
composition: 'کجراه پنبهای',
|
||||
weightGrams: 240,
|
||||
colorsJson: ['#d6c3a8', '#8b7355'],
|
||||
tagsJson: ['شلواری', 'چهارفصل'],
|
||||
subtitle: 'روزمره',
|
||||
rollMeters: 50,
|
||||
isNew: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.customer.create({
|
||||
data: {
|
||||
id: 'agent-1',
|
||||
firstName: 'علی',
|
||||
lastName: 'رضایی',
|
||||
phone: '09121112233',
|
||||
nationalId: '0011111111',
|
||||
customerType: CustomerType.wholesale,
|
||||
appRole: AppUserRole.agent,
|
||||
agentCode: 'W-1247',
|
||||
levelLabel: 'طلایی',
|
||||
nextLevelLabel: 'VIP',
|
||||
pointsToNext: 550_000_000,
|
||||
levelProgress: 72,
|
||||
companyId: 'company-par',
|
||||
isActive: true,
|
||||
avatarLetter: 'ع',
|
||||
avatarColor: '#0B3D33',
|
||||
createdAt: new Date('2024-01-10T10:00:00'),
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.customer.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'cust-1',
|
||||
firstName: 'سارا',
|
||||
lastName: 'محمدی',
|
||||
phone: '09121234567',
|
||||
nationalId: '0012345678',
|
||||
customerType: CustomerType.wholesale,
|
||||
companyId: 'company-par',
|
||||
businessName: 'بوتیک رز',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'نقرهای',
|
||||
avatarLetter: 'پ',
|
||||
avatarColor: '#f9a8d4',
|
||||
isActive: true,
|
||||
createdAt: new Date('2024-03-12T10:00:00'),
|
||||
},
|
||||
{
|
||||
id: 'cust-2',
|
||||
firstName: 'نرگس',
|
||||
lastName: 'احمدی',
|
||||
phone: '09135551234',
|
||||
nationalId: '1030567890',
|
||||
customerType: CustomerType.wholesale,
|
||||
companyId: 'company-fam-baft',
|
||||
businessName: 'مزون الوان',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'برنزی',
|
||||
avatarLetter: 'م',
|
||||
avatarColor: '#c4b5fd',
|
||||
isActive: true,
|
||||
createdAt: new Date('2024-05-20T14:30:00'),
|
||||
},
|
||||
{
|
||||
id: 'cust-3',
|
||||
firstName: 'فروشگاه',
|
||||
lastName: 'پارچه مهر',
|
||||
phone: '09128877665',
|
||||
nationalId: '0012345679',
|
||||
customerType: CustomerType.retail,
|
||||
companyId: 'company-par',
|
||||
businessName: 'پارچه مهر',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'برنزی',
|
||||
avatarLetter: 'م',
|
||||
avatarColor: '#93c5fd',
|
||||
isActive: true,
|
||||
createdAt: new Date('2024-07-08T09:15:00'),
|
||||
},
|
||||
{
|
||||
id: 'cust-4',
|
||||
firstName: 'پوشاک',
|
||||
lastName: 'سپهر',
|
||||
phone: '09369876543',
|
||||
nationalId: '1050987654',
|
||||
customerType: CustomerType.wholesale,
|
||||
companyId: 'company-par',
|
||||
businessName: 'پوشاک سپهر',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'برنزی',
|
||||
avatarLetter: 'س',
|
||||
avatarColor: '#fcd34d',
|
||||
isActive: false,
|
||||
createdAt: new Date('2024-08-01T11:00:00'),
|
||||
},
|
||||
{
|
||||
id: 'cust-5',
|
||||
firstName: 'بافت',
|
||||
lastName: 'آسان',
|
||||
phone: '09121110000',
|
||||
nationalId: '0065432109',
|
||||
customerType: CustomerType.wholesale,
|
||||
companyId: 'company-fam-baft',
|
||||
businessName: 'بافت آسان',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'نقرهای',
|
||||
avatarLetter: 'ب',
|
||||
avatarColor: '#6ee7b7',
|
||||
isActive: true,
|
||||
createdAt: new Date('2024-06-01T10:00:00'),
|
||||
},
|
||||
{
|
||||
id: 'cust-6',
|
||||
firstName: 'مینا',
|
||||
lastName: 'کریمی',
|
||||
phone: '09129990001',
|
||||
nationalId: '0077007700',
|
||||
customerType: CustomerType.retail,
|
||||
companyId: 'company-par',
|
||||
businessName: 'مزون مینا',
|
||||
assignedAgentId: 'agent-1',
|
||||
levelLabel: 'برنزی',
|
||||
avatarLetter: 'ن',
|
||||
avatarColor: '#fda4af',
|
||||
isActive: true,
|
||||
createdAt: new Date('2024-09-01T10:00:00'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const order1 = await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-1',
|
||||
orderNumber: 'ORD-1403-1256',
|
||||
userId: 'cust-1',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.check,
|
||||
checkMode: CheckRegistrationMode.full,
|
||||
status: OrderStatus.awaiting_review,
|
||||
totalMeterage: 4250,
|
||||
totalAmount: 2_450_000_000,
|
||||
createdAt: new Date('2024-10-25T10:30:00'),
|
||||
items: {
|
||||
create: [
|
||||
{
|
||||
id: 'oi-1',
|
||||
productId: 'prod-377-blue',
|
||||
catalogCode: '377',
|
||||
productName: 'پارچه آبی',
|
||||
productCode: '377-BL',
|
||||
color: 'آبی',
|
||||
requestedMeterage: 2000,
|
||||
confirmedMeterage: 2000,
|
||||
},
|
||||
{
|
||||
id: 'oi-2',
|
||||
productId: 'prod-377-black',
|
||||
catalogCode: '377',
|
||||
productName: 'پارچه مشکی',
|
||||
productCode: '377-BK',
|
||||
color: 'مشکی',
|
||||
requestedMeterage: 1500,
|
||||
confirmedMeterage: 1000,
|
||||
},
|
||||
{
|
||||
id: 'oi-3',
|
||||
productId: 'prod-378-blue-white',
|
||||
catalogCode: '378',
|
||||
productName: 'آبی پشت سفید',
|
||||
productCode: '378-BLW',
|
||||
color: 'آبی پشت سفید',
|
||||
requestedMeterage: 750,
|
||||
confirmedMeterage: 750,
|
||||
},
|
||||
],
|
||||
},
|
||||
checks: {
|
||||
create: [
|
||||
{
|
||||
id: 'chk-1',
|
||||
row: 1,
|
||||
amount: 1_000_000_000,
|
||||
bankName: 'ملت',
|
||||
sayadId: '1234567890123456',
|
||||
dueDate: new Date('2024-10-21'),
|
||||
status: CheckStatus.pending_review,
|
||||
mode: CheckRegistrationMode.full,
|
||||
},
|
||||
{
|
||||
id: 'chk-2',
|
||||
row: 2,
|
||||
amount: 800_000_000,
|
||||
bankName: 'ملی',
|
||||
sayadId: '2345678901234567',
|
||||
dueDate: new Date('2024-10-26'),
|
||||
status: CheckStatus.pending_review,
|
||||
mode: CheckRegistrationMode.full,
|
||||
},
|
||||
{
|
||||
id: 'chk-3',
|
||||
row: 3,
|
||||
amount: 650_000_000,
|
||||
bankName: 'ملت',
|
||||
sayadId: '3456789012345678',
|
||||
dueDate: new Date('2024-10-31'),
|
||||
status: CheckStatus.pending_review,
|
||||
mode: CheckRegistrationMode.full,
|
||||
},
|
||||
],
|
||||
},
|
||||
statusHistory: {
|
||||
create: [
|
||||
{ fromStatus: null, toStatus: OrderStatus.submitted, changedBy: 'customer', changedAt: new Date('2024-10-25T10:30:00') },
|
||||
{ fromStatus: OrderStatus.submitted, toStatus: OrderStatus.awaiting_review, changedBy: 'system', changedAt: new Date('2024-10-25T10:30:01') },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-2',
|
||||
orderNumber: 'ORD-1403-1255',
|
||||
userId: 'cust-2',
|
||||
companyId: 'company-fam-baft',
|
||||
companyName: 'فامبافت',
|
||||
settlementType: SettlementType.check,
|
||||
checkMode: CheckRegistrationMode.brief,
|
||||
status: OrderStatus.awaiting_check_review,
|
||||
totalMeterage: 3200,
|
||||
totalAmount: 1_850_000_000,
|
||||
createdAt: new Date('2024-10-24T14:15:00'),
|
||||
items: {
|
||||
create: [
|
||||
{
|
||||
productId: 'prod-fam-401-1',
|
||||
catalogCode: '401',
|
||||
productName: 'پارچه مخمل',
|
||||
productCode: '401-MV',
|
||||
color: 'سرمهای',
|
||||
requestedMeterage: 3200,
|
||||
confirmedMeterage: 3200,
|
||||
unitPrice: 250000,
|
||||
lineTotal: 800_000_000,
|
||||
},
|
||||
],
|
||||
},
|
||||
cashReceipt: {
|
||||
create: {
|
||||
id: 'cp-1',
|
||||
amount: 1_850_000_000,
|
||||
paidAmount: 1_850_000_000,
|
||||
transferDate: new Date('2024-10-25T08:30:00'),
|
||||
trackingNumber: '9876543210',
|
||||
expiresAt: new Date('2024-10-25T17:00:00'),
|
||||
status: CashPaymentStatus.pending_review,
|
||||
submittedAt: new Date('2024-10-25T08:30:00'),
|
||||
},
|
||||
},
|
||||
statusHistory: {
|
||||
create: [
|
||||
{ fromStatus: null, toStatus: OrderStatus.submitted, changedBy: 'customer' },
|
||||
{ fromStatus: OrderStatus.submitted, toStatus: OrderStatus.awaiting_check_review, changedBy: 'admin' },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-3',
|
||||
orderNumber: 'ORD-1403-1254',
|
||||
userId: 'cust-1',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.cash,
|
||||
status: OrderStatus.final_approved,
|
||||
totalMeterage: 1800,
|
||||
totalAmount: 980_000_000,
|
||||
finalAmount: 980_000_000,
|
||||
createdAt: new Date('2024-10-23T09:00:00'),
|
||||
cashReceipt: {
|
||||
create: {
|
||||
id: 'cp-2',
|
||||
amount: 980_000_000,
|
||||
paidAmount: 980_000_000,
|
||||
transferDate: new Date('2024-10-24T15:20:00'),
|
||||
trackingNumber: '1234567890',
|
||||
destinationAccountId: 'ba-par-1',
|
||||
expiresAt: new Date('2024-10-24T17:00:00'),
|
||||
status: CashPaymentStatus.approved,
|
||||
submittedAt: new Date('2024-10-24T15:20:00'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-4',
|
||||
orderNumber: 'ORD-1403-1253',
|
||||
userId: 'cust-5',
|
||||
companyId: 'company-fam-baft',
|
||||
companyName: 'فامبافت',
|
||||
settlementType: SettlementType.check,
|
||||
status: OrderStatus.check_needs_fix,
|
||||
totalMeterage: 5100,
|
||||
totalAmount: 3_200_000_000,
|
||||
createdAt: new Date('2024-10-22T16:45:00'),
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-5',
|
||||
orderNumber: 'ORD-1403-1252',
|
||||
userId: 'cust-1',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.cash,
|
||||
status: OrderStatus.delivered,
|
||||
totalMeterage: 1200,
|
||||
totalAmount: 750_000_000,
|
||||
finalAmount: 750_000_000,
|
||||
createdAt: new Date('2024-10-21T11:20:00'),
|
||||
shipment: {
|
||||
create: {
|
||||
id: 'shp-delivered-5',
|
||||
carrier: 'باربری تهران',
|
||||
trackingNumber: 'BR-1403-88001',
|
||||
meterage: 1200,
|
||||
status: ShipmentStatus.delivered,
|
||||
shippedAt: new Date('2024-10-19T09:00:00'),
|
||||
deliveredAt: new Date('2024-10-21T11:00:00'),
|
||||
},
|
||||
},
|
||||
cashReceipt: {
|
||||
create: {
|
||||
id: 'cp-3',
|
||||
amount: 750_000_000,
|
||||
paidAmount: 750_000_000,
|
||||
transferDate: new Date('2024-10-18T11:00:00'),
|
||||
trackingNumber: '5555123456',
|
||||
destinationAccountId: 'ba-par-2',
|
||||
expiresAt: new Date('2024-10-18T17:00:00'),
|
||||
status: CashPaymentStatus.approved,
|
||||
submittedAt: new Date('2024-10-18T11:00:00'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-6',
|
||||
orderNumber: 'ORD-1403-1251',
|
||||
userId: 'cust-1',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.check,
|
||||
status: OrderStatus.shipped,
|
||||
totalMeterage: 2900,
|
||||
totalAmount: 1_600_000_000,
|
||||
createdAt: new Date('2024-10-20T08:30:00'),
|
||||
shipment: {
|
||||
create: {
|
||||
id: 'shp-1',
|
||||
carrier: 'باربری تهران-اصفهان',
|
||||
trackingNumber: 'BR-1403-88901',
|
||||
meterage: 2900,
|
||||
status: ShipmentStatus.shipped,
|
||||
shippedAt: new Date('2024-10-24T09:00:00'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-7',
|
||||
orderNumber: 'ORD-1403-1250',
|
||||
userId: 'cust-5',
|
||||
companyId: 'company-fam-baft',
|
||||
companyName: 'فامبافت',
|
||||
settlementType: SettlementType.check,
|
||||
status: OrderStatus.awaiting_check_review,
|
||||
totalMeterage: 3800,
|
||||
totalAmount: 2_100_000_000,
|
||||
createdAt: new Date('2024-10-19T13:00:00'),
|
||||
shipment: {
|
||||
create: {
|
||||
id: 'shp-2',
|
||||
carrier: 'باربری سریع',
|
||||
trackingNumber: 'BR-1403-88902',
|
||||
meterage: 3800,
|
||||
status: ShipmentStatus.ready,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-8',
|
||||
orderNumber: 'ORD-1403-1208',
|
||||
userId: 'cust-3',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.cash,
|
||||
status: OrderStatus.preparing,
|
||||
totalMeterage: 950,
|
||||
totalAmount: 450_000_000,
|
||||
createdAt: new Date('2024-10-18T10:00:00'),
|
||||
shipment: {
|
||||
create: {
|
||||
id: 'shp-3',
|
||||
carrier: 'پیک داخلی',
|
||||
trackingNumber: 'PK-1403-0045',
|
||||
meterage: 950,
|
||||
status: ShipmentStatus.preparing,
|
||||
},
|
||||
},
|
||||
cashReceipt: {
|
||||
create: {
|
||||
id: 'cp-4',
|
||||
amount: 450_000_000,
|
||||
paidAmount: null,
|
||||
transferDate: null,
|
||||
trackingNumber: null,
|
||||
expiresAt: new Date('2024-10-22T17:00:00'),
|
||||
status: CashPaymentStatus.expired,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.order.create({
|
||||
data: {
|
||||
id: 'ord-9',
|
||||
orderNumber: 'ORD-1403-1199',
|
||||
userId: 'cust-1',
|
||||
companyId: 'company-par',
|
||||
companyName: 'شرکت پَر',
|
||||
settlementType: SettlementType.check,
|
||||
status: OrderStatus.delivered,
|
||||
totalMeterage: 4100,
|
||||
totalAmount: 2_200_000_000,
|
||||
createdAt: new Date('2024-10-15T10:00:00'),
|
||||
shipment: {
|
||||
create: {
|
||||
id: 'shp-4',
|
||||
carrier: 'باربری تهران-مشهد',
|
||||
trackingNumber: 'BR-1403-88750',
|
||||
meterage: 4100,
|
||||
status: ShipmentStatus.delivered,
|
||||
shippedAt: new Date('2024-10-18T10:00:00'),
|
||||
deliveredAt: new Date('2024-10-20T16:30:00'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.systemSettings.create({
|
||||
data: {
|
||||
id: 'default',
|
||||
maxMeteragePerInvoice: 5000,
|
||||
cashInvoiceValidityHours: 8,
|
||||
defaultSettlementCheck: true,
|
||||
defaultSettlementCash: true,
|
||||
smsOrderRegistered: true,
|
||||
smsPaymentReminder: true,
|
||||
smsCheckReview: true,
|
||||
smsShippingUpdate: true,
|
||||
supportPhone: '02191000000',
|
||||
supportEmail: 'support@fabrictrade.ir',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.meetingInteraction.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'meet-1',
|
||||
agentId: 'agent-1',
|
||||
customerId: 'cust-1',
|
||||
type: InteractionType.in_person,
|
||||
title: 'بازدید از بوتیک رز',
|
||||
description: 'نیاز به پارچههای طوسی و سرمهای اعلام شد.',
|
||||
subject: 'بازدید حضوری',
|
||||
content: 'نیاز به پارچههای طوسی، سرمهای و ذغالی با عرض مناسب.',
|
||||
date: '1403/03/20',
|
||||
time: '11:30',
|
||||
},
|
||||
{
|
||||
id: 'meet-2',
|
||||
agentId: 'agent-1',
|
||||
customerId: 'cust-2',
|
||||
type: InteractionType.call,
|
||||
title: 'پیگیری موجودی',
|
||||
description: 'تماس برای اعلام موجودی فاستونی.',
|
||||
date: '1403/03/18',
|
||||
time: '10:00',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
await prisma.reminder.createMany({
|
||||
data: [
|
||||
{
|
||||
id: 'rem-1',
|
||||
ownerId: 'agent-1',
|
||||
customerId: 'cust-1',
|
||||
title: 'پیگیری موجودی پارچه فاستونی طوسی',
|
||||
description: 'اعلام موجودی و ارسال نمونه',
|
||||
note: 'تماس برای اعلام موجودی و ارسال نمونه',
|
||||
date: '1403/03/23',
|
||||
time: '10:00',
|
||||
interactionType: InteractionType.call,
|
||||
completed: false,
|
||||
},
|
||||
{
|
||||
id: 'rem-2',
|
||||
ownerId: 'agent-1',
|
||||
customerId: 'cust-2',
|
||||
title: 'ارسال کالیته جدید',
|
||||
description: 'ارسال کالیته زمستانه برای مزون الوان',
|
||||
date: '1403/03/24',
|
||||
time: '14:00',
|
||||
interactionType: InteractionType.in_person,
|
||||
completed: false,
|
||||
},
|
||||
{
|
||||
id: 'rem-3',
|
||||
ownerId: 'agent-1',
|
||||
customerId: 'cust-3',
|
||||
title: 'پیگیری سفارش قبلی',
|
||||
description: 'بررسی وضعیت سفارش و تسویه',
|
||||
date: '1403/03/10',
|
||||
time: '09:00',
|
||||
interactionType: InteractionType.note,
|
||||
completed: true,
|
||||
completedAt: new Date('2024-10-20T09:30:00'),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
void order1;
|
||||
console.log('Seed completed successfully.');
|
||||
console.log('Admin login: 09128081392 / 123456');
|
||||
console.log('Agent OTP login: 09121112233');
|
||||
console.log('Customer OTP login: 09121234567');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user