delete and undo

This commit is contained in:
2026-10-10 10:43:24 +05:30
parent 575b00172d
commit ee71d4c24e
25 changed files with 3604 additions and 3469 deletions
@@ -1,34 +1,34 @@
-- CreateTable
CREATE TABLE "LoginRequest" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"secretHash" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"decidedById" TEXT,
"decidedAt" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "LoginRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "LoginRequest_decidedById_fkey" FOREIGN KEY ("decidedById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_User" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"role" TEXT NOT NULL,
"dealerId" TEXT,
"passwordHash" TEXT,
"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
);
INSERT INTO "new_User" ("createdAt", "dealerId", "id", "name", "phone", "role", "updatedAt") SELECT "createdAt", "dealerId", "id", "name", "phone", "role", "updatedAt" FROM "User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
-- CreateTable
CREATE TABLE "LoginRequest" (
"id" TEXT NOT NULL PRIMARY KEY,
"userId" TEXT NOT NULL,
"status" TEXT NOT NULL,
"secretHash" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"decidedById" TEXT,
"decidedAt" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "LoginRequest_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "LoginRequest_decidedById_fkey" FOREIGN KEY ("decidedById") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_User" (
"id" TEXT NOT NULL PRIMARY KEY,
"name" TEXT NOT NULL,
"phone" TEXT NOT NULL,
"role" TEXT NOT NULL,
"dealerId" TEXT,
"passwordHash" TEXT,
"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
);
INSERT INTO "new_User" ("createdAt", "dealerId", "id", "name", "phone", "role", "updatedAt") SELECT "createdAt", "dealerId", "id", "name", "phone", "role", "updatedAt" FROM "User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
@@ -1,2 +1,2 @@
-- AlterTable
ALTER TABLE "Stock" ADD COLUMN "plateNumber" TEXT;
-- AlterTable
ALTER TABLE "Stock" ADD COLUMN "plateNumber" TEXT;
+143 -143
View File
@@ -1,143 +1,143 @@
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])
passwordHash String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignments DealerAssignment[] @relation("SalesRepAssignments")
stageLogs StageLog[]
transfers StockTransfer[]
events Event[]
servicePoints ServicePoint[]
loginRequests LoginRequest[] @relation("DealerLoginRequests")
loginDecisions LoginRequest[] @relation("LoginDecisions")
}
model LoginRequest {
id String @id @default(cuid())
userId String
user User @relation("DealerLoginRequests", fields: [userId], references: [id], onDelete: Cascade)
status String
secretHash String
expiresAt DateTime
decidedById String?
decidedBy User? @relation("LoginDecisions", fields: [decidedById], references: [id])
decidedAt DateTime?
createdAt DateTime @default(now())
}
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?
plateNumber 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
}
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])
passwordHash String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignments DealerAssignment[] @relation("SalesRepAssignments")
stageLogs StageLog[]
transfers StockTransfer[]
events Event[]
servicePoints ServicePoint[]
loginRequests LoginRequest[] @relation("DealerLoginRequests")
loginDecisions LoginRequest[] @relation("LoginDecisions")
}
model LoginRequest {
id String @id @default(cuid())
userId String
user User @relation("DealerLoginRequests", fields: [userId], references: [id], onDelete: Cascade)
status String
secretHash String
expiresAt DateTime
decidedById String?
decidedBy User? @relation("LoginDecisions", fields: [decidedById], references: [id])
decidedAt DateTime?
createdAt DateTime @default(now())
}
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?
plateNumber 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
}
+41 -41
View File
@@ -1,41 +1,41 @@
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const prisma = require('../src/db');
const { isValidPhone, normalizePhone } = require('../src/lib/phone');
const { hashPassword } = require('../src/lib/passwords');
async function main() {
const name = String(process.env.SEED_ADMIN_NAME || 'Super Admin').trim();
const phone = normalizePhone(process.env.SEED_ADMIN_PHONE);
const password = String(process.env.SEED_ADMIN_PASSWORD || '');
if (!isValidPhone(phone)) {
throw new Error('SEED_ADMIN_PHONE must be a Sri Lankan mobile number');
}
if (password.length < 8) {
throw new Error('SEED_ADMIN_PASSWORD must be at least 8 characters');
}
const passwordHash = await hashPassword(password);
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, passwordHash },
})
: await prisma.user.upsert({
where: { phone },
update: { name, role: 'superAdmin', dealerId: null, passwordHash },
create: { name, phone, role: 'superAdmin', passwordHash },
});
console.log(`Seeded super admin ${admin.name} (${admin.phone})`);
}
main()
.catch((error) => {
console.error(error);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
const prisma = require('../src/db');
const { isValidPhone, normalizePhone } = require('../src/lib/phone');
const { hashPassword } = require('../src/lib/passwords');
async function main() {
const name = String(process.env.SEED_ADMIN_NAME || 'Super Admin').trim();
const phone = normalizePhone(process.env.SEED_ADMIN_PHONE);
const password = String(process.env.SEED_ADMIN_PASSWORD || '');
if (!isValidPhone(phone)) {
throw new Error('SEED_ADMIN_PHONE must be a Sri Lankan mobile number');
}
if (password.length < 8) {
throw new Error('SEED_ADMIN_PASSWORD must be at least 8 characters');
}
const passwordHash = await hashPassword(password);
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, passwordHash },
})
: await prisma.user.upsert({
where: { phone },
update: { name, role: 'superAdmin', dealerId: null, passwordHash },
create: { name, phone, role: 'superAdmin', passwordHash },
});
console.log(`Seeded super admin ${admin.name} (${admin.phone})`);
}
main()
.catch((error) => {
console.error(error);
process.exitCode = 1;
})
.finally(async () => {
await prisma.$disconnect();
});