carservice: initial commit

This commit is contained in:
Hermes
2026-07-20 21:17:12 +01:00
commit d315323191
69 changed files with 9255 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
username String @unique
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Car {
id Int @id @default(autoincrement())
regNumber String @unique
make String?
model String?
color String?
year Int?
ownerName String?
ownerPhone String?
ownerEmail String?
vin String?
engineNumber String?
mileage Int?
notes String? @default("")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
orders Order[]
parts Part[]
@@index([regNumber])
@@index([ownerName])
}
model Order {
id Int @id @default(autoincrement())
carId Int
car Car @relation(fields: [carId], references: [id], onDelete: Cascade)
status String @default("open") // open, closed
mileage Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tasks Task[]
total Float @default(0)
laborHours Float @default(0)
hourlyRate Float @default(50)
}
model Task {
id Int @id @default(autoincrement())
orderId Int
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
title String
status String @default("todo") // todo, finished
finishedAt DateTime?
laborHours Float @default(0)
hourlyRate Float @default(50)
partsCost Float @default(0)
laborCost Float @default(0)
price Float @default(0)
notes String? @default("")
orderIndex Int @default(0)
mileage Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parts TaskPart[]
@@index([status])
@@index([finishedAt])
}
model Part {
id Int @id @default(autoincrement())
name String
manufacturer String?
supplierLink String?
url String?
purchasePrice Float @default(0)
notes String? @default("")
carId Int?
car Car? @relation(fields: [carId], references: [id], onDelete: SetNull)
isGlobal Boolean @default(false)
orderId Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tasks TaskPart[]
@@index([name])
}
model TaskPart {
id Int @id @default(autoincrement())
taskId Int
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
partId Int
part Part @relation(fields: [partId], references: [id], onDelete: Cascade)
qty Int @default(1)
price Float @default(0)
@@unique([taskId, partId])
}
model QuickTask {
id Int @id @default(autoincrement())
title String @unique
useCount Int @default(0)
laborHours Float @default(0)
hourlyRate Float @default(50)
price Float? // manual override stored in cents/euros
createdAt DateTime @default(now())
parts QuickTaskPart[]
}
model QuickTaskPart {
id Int @id @default(autoincrement())
quickTaskId Int
quickTask QuickTask @relation(fields: [quickTaskId], references: [id], onDelete: Cascade)
name String
qty Int @default(1)
price Float @default(0)
isGlobal Boolean @default(false)
globalPartId Int?
}
+24
View File
@@ -0,0 +1,24 @@
const { PrismaClient } = require("@prisma/client");
const bcrypt = require("bcryptjs");
async function main() {
const prisma = new PrismaClient();
const existing = await prisma.user.findUnique({ where: { username: "admin" } });
if (!existing) {
const hash = await bcrypt.hash("password", 10);
await prisma.user.create({
data: { username: "admin", password: hash },
});
console.log("Created default user: admin / password");
} else {
console.log("User already exists");
}
await prisma.$disconnect();
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
+42
View File
@@ -0,0 +1,42 @@
const { PrismaClient } = require("@prisma/client");
const prisma = new PrismaClient();
const commonTasks = [
"Oil change",
"Oil filter replacement",
"Air filter replacement",
"Cabin filter replacement",
"Front brake pads replacement",
"Rear brake pads replacement",
"Brake fluid change",
"Tyre rotation",
"Wheel alignment",
"Battery test",
"Coolant change",
"Timing belt inspection",
"Spark plug replacement",
"Full diagnostic scan",
"Suspension check",
"Exhaust inspection",
"NCT pre-check",
];
async function main() {
for (const title of commonTasks) {
await prisma.quickTask.upsert({
where: { title },
update: {},
create: { title, useCount: 1 },
});
}
console.log("Seeded quick tasks");
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});