This commit is contained in:
2026-10-01 11:52:17 +05:30
commit d303c576fd
26 changed files with 3229 additions and 0 deletions
@@ -0,0 +1,123 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"role" TEXT NOT NULL,
"dealerId" TEXT,
"currentOtp" TEXT,
"otpExpiresAt" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "User_dealerId_fkey" FOREIGN KEY ("dealerId") REFERENCES "Dealer" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Dealer" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"code" TEXT NOT NULL,
"district" TEXT,
"address" TEXT,
"phone" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "DealerAssignment" (
"salesRepId" TEXT NOT NULL,
"dealerId" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ("salesRepId", "dealerId"),
CONSTRAINT "DealerAssignment_salesRepId_fkey" FOREIGN KEY ("salesRepId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "DealerAssignment_dealerId_fkey" FOREIGN KEY ("dealerId") REFERENCES "Dealer" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Stock" (
"id" TEXT NOT NULL PRIMARY KEY,
"chassisNumber" TEXT NOT NULL,
"engineNumber" TEXT NOT NULL,
"model" TEXT NOT NULL,
"color" TEXT NOT NULL,
"currentDealerId" TEXT NOT NULL,
"dateReceived" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"currentStage" TEXT NOT NULL DEFAULT 'received',
"paymentType" TEXT,
"leaseProviderType" TEXT,
"financeCompanyName" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Stock_currentDealerId_fkey" FOREIGN KEY ("currentDealerId") REFERENCES "Dealer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "StageLog" (
"id" TEXT NOT NULL PRIMARY KEY,
"stockId" TEXT NOT NULL,
"stage" TEXT NOT NULL,
"loggedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"actorId" TEXT,
CONSTRAINT "StageLog_stockId_fkey" FOREIGN KEY ("stockId") REFERENCES "Stock" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "StageLog_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "StockTransfer" (
"id" TEXT NOT NULL PRIMARY KEY,
"stockId" TEXT NOT NULL,
"fromDealerId" TEXT NOT NULL,
"toDealerId" TEXT NOT NULL,
"actorId" TEXT NOT NULL,
"transferredAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "StockTransfer_stockId_fkey" FOREIGN KEY ("stockId") REFERENCES "Stock" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "StockTransfer_fromDealerId_fkey" FOREIGN KEY ("fromDealerId") REFERENCES "Dealer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "StockTransfer_toDealerId_fkey" FOREIGN KEY ("toDealerId") REFERENCES "Dealer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "StockTransfer_actorId_fkey" FOREIGN KEY ("actorId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Event" (
"id" TEXT NOT NULL PRIMARY KEY,
"dealerId" TEXT NOT NULL,
"planType" TEXT NOT NULL,
"month" INTEGER,
"year" INTEGER,
"title" TEXT NOT NULL,
"description" TEXT NOT NULL,
"expense" REAL NOT NULL,
"imageUrls" TEXT NOT NULL DEFAULT '[]',
"createdById" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Event_dealerId_fkey" FOREIGN KEY ("dealerId") REFERENCES "Dealer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "Event_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "ServicePoint" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"district" TEXT NOT NULL,
"address" TEXT,
"phone" TEXT,
"notes" TEXT,
"createdById" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "ServicePoint_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
-- CreateIndex
CREATE UNIQUE INDEX "Dealer_code_key" ON "Dealer"("code");
-- CreateIndex
CREATE UNIQUE INDEX "Stock_chassisNumber_key" ON "Stock"("chassisNumber");
-- CreateIndex
CREATE UNIQUE INDEX "Stock_engineNumber_key" ON "Stock"("engineNumber");
+3
View File
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"
+128
View File
@@ -0,0 +1,128 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
name String
phone String @unique
role String
dealerId String?
dealer Dealer? @relation("DealerStaff", fields: [dealerId], references: [id])
currentOtp String?
otpExpiresAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignments DealerAssignment[] @relation("SalesRepAssignments")
stageLogs StageLog[]
transfers StockTransfer[]
events Event[]
servicePoints ServicePoint[]
}
model Dealer {
id String @id @default(cuid())
name String
code String @unique
district String?
address String?
phone String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
staff User[] @relation("DealerStaff")
assignments DealerAssignment[]
stocks Stock[]
transfersFrom StockTransfer[] @relation("TransferFrom")
transfersTo StockTransfer[] @relation("TransferTo")
events Event[]
}
model DealerAssignment {
salesRepId String
dealerId String
createdAt DateTime @default(now())
salesRep User @relation("SalesRepAssignments", fields: [salesRepId], references: [id], onDelete: Cascade)
dealer Dealer @relation(fields: [dealerId], references: [id], onDelete: Cascade)
@@id([salesRepId, dealerId])
}
model Stock {
id String @id @default(cuid())
chassisNumber String @unique
engineNumber String @unique
model String
color String
currentDealerId String
currentDealer Dealer @relation(fields: [currentDealerId], references: [id])
dateReceived DateTime @default(now())
currentStage String @default("received")
paymentType String?
leaseProviderType String?
financeCompanyName String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
stageLogs StageLog[]
transfers StockTransfer[]
}
model StageLog {
id String @id @default(cuid())
stockId String
stock Stock @relation(fields: [stockId], references: [id], onDelete: Cascade)
stage String
loggedAt DateTime @default(now())
actorId String?
actor User? @relation(fields: [actorId], references: [id])
}
model StockTransfer {
id String @id @default(cuid())
stockId String
stock Stock @relation(fields: [stockId], references: [id], onDelete: Cascade)
fromDealerId String
fromDealer Dealer @relation("TransferFrom", fields: [fromDealerId], references: [id])
toDealerId String
toDealer Dealer @relation("TransferTo", fields: [toDealerId], references: [id])
actorId String
actor User @relation(fields: [actorId], references: [id])
transferredAt DateTime @default(now())
}
model Event {
id String @id @default(cuid())
dealerId String
dealer Dealer @relation(fields: [dealerId], references: [id])
planType String
month Int?
year Int?
title String
description String
expense Float
imageUrls String @default("[]")
createdById String
createdBy User @relation(fields: [createdById], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model ServicePoint {
id String @id @default(cuid())
name String
district String
address String?
phone String?
notes String?
createdById String
createdBy User @relation(fields: [createdById], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
+35
View File
@@ -0,0 +1,35 @@
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const prisma = require('../src/db');
const { isValidPhone, normalizePhone } = require('../src/lib/phone');
async function main() {
const name = String(process.env.SEED_ADMIN_NAME || 'Super Admin').trim();
const phone = normalizePhone(process.env.SEED_ADMIN_PHONE);
if (!isValidPhone(phone)) {
throw new Error('SEED_ADMIN_PHONE must be a Sri Lankan mobile number');
}
const existingAdmin = await prisma.user.findFirst({ where: { role: 'superAdmin' } });
const admin = existingAdmin
? await prisma.user.update({
where: { id: existingAdmin.id },
data: { name, phone, role: 'superAdmin', dealerId: null },
})
: await prisma.user.upsert({
where: { phone },
update: { name, role: 'superAdmin', dealerId: null },
create: { name, phone, role: 'superAdmin' },
});
console.log(`Seeded super admin ${admin.name} (${admin.phone})`);
}
main()
.catch((error) => {
console.error(error);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});