627 lines
20 KiB
Plaintext
627 lines
20 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
// ─── Auth / Users ────────────────────────────────────────────────────────────
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
name String?
|
|
email String @unique
|
|
emailVerified DateTime?
|
|
image String?
|
|
password String?
|
|
role UserRole @default(ARTIST)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
accounts Account[]
|
|
sessions Session[]
|
|
jobs Job[] @relation("JobCreator")
|
|
comments Comment[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Account {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
type String
|
|
provider String
|
|
providerAccountId String
|
|
refresh_token String?
|
|
access_token String?
|
|
expires_at Int?
|
|
token_type String?
|
|
scope String?
|
|
id_token String?
|
|
session_state String?
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([provider, providerAccountId])
|
|
@@map("accounts")
|
|
}
|
|
|
|
model Session {
|
|
id String @id @default(cuid())
|
|
sessionToken String @unique
|
|
userId String
|
|
expires DateTime
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("sessions")
|
|
}
|
|
|
|
model VerificationToken {
|
|
identifier String
|
|
token String @unique
|
|
expires DateTime
|
|
|
|
@@unique([identifier, token])
|
|
@@map("verification_tokens")
|
|
}
|
|
|
|
enum UserRole {
|
|
ADMIN
|
|
PRODUCER
|
|
SUPERVISOR
|
|
ARTIST
|
|
}
|
|
|
|
// ─── Clients ─────────────────────────────────────────────────────────────────
|
|
|
|
model Client {
|
|
id String @id @default(cuid())
|
|
companyName String
|
|
contactPerson String?
|
|
email String?
|
|
phone String?
|
|
vatNumber String?
|
|
companyRegNumber String?
|
|
billingAddress String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
jobs Job[]
|
|
invoices Invoice[]
|
|
|
|
@@map("clients")
|
|
}
|
|
|
|
// ─── Jobs / Quotes ────────────────────────────────────────────────────────────
|
|
|
|
model Job {
|
|
id String @id @default(cuid())
|
|
projectTitle String
|
|
projectCode String @unique
|
|
showId String @default("")
|
|
jobType JobType @default(STANDARD)
|
|
clientId String
|
|
createdById String?
|
|
issueDate DateTime @default(now())
|
|
expiryDate DateTime?
|
|
currency String @default("ZAR")
|
|
status JobStatus @default(DRAFT)
|
|
description String?
|
|
internalNotes String?
|
|
markupPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
taxPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
discountPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
productionFeePercent Decimal @default(0) @db.Decimal(10, 4)
|
|
pullManagementFeePercent Decimal @default(0) @db.Decimal(10, 4)
|
|
customHeaderHtml String?
|
|
customFooterHtml String?
|
|
termsAndConditions String?
|
|
startDate DateTime?
|
|
estimatedCompletionDate DateTime?
|
|
version Int @default(1)
|
|
parentJobId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
client Client @relation(fields: [clientId], references: [id])
|
|
createdBy User? @relation("JobCreator", fields: [createdById], references: [id])
|
|
parentJob Job? @relation("JobVersions", fields: [parentJobId], references: [id], onDelete: SetNull)
|
|
versions Job[] @relation("JobVersions")
|
|
shots Shot[]
|
|
assets Asset[]
|
|
supervisions Supervision[]
|
|
previses Previs[]
|
|
comments Comment[]
|
|
history JobHistory[]
|
|
paymentSchedule PaymentSchedule?
|
|
invoices Invoice[]
|
|
|
|
@@map("jobs")
|
|
}
|
|
|
|
enum JobStatus {
|
|
DRAFT
|
|
SENT
|
|
APPROVED
|
|
REJECTED
|
|
ARCHIVED
|
|
}
|
|
|
|
enum JobType {
|
|
STANDARD
|
|
EPISODIC
|
|
}
|
|
|
|
model JobHistory {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
field String
|
|
oldValue String?
|
|
newValue String?
|
|
changedAt DateTime @default(now())
|
|
changedBy String?
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("job_history")
|
|
}
|
|
|
|
model Comment {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
userId String?
|
|
body String
|
|
createdAt DateTime @default(now())
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
@@map("comments")
|
|
}
|
|
|
|
// ─── Rate Cards ───────────────────────────────────────────────────────────────
|
|
|
|
model RateCard {
|
|
id String @id @default(cuid())
|
|
name String
|
|
department String?
|
|
defaultDailyRate Decimal @default(0) @db.Decimal(10, 4)
|
|
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
|
|
currency String @default("ZAR")
|
|
notes String?
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lineItems LineItem[]
|
|
|
|
@@map("rate_cards")
|
|
}
|
|
|
|
// ─── Shot Templates ───────────────────────────────────────────────────────────
|
|
|
|
model ShotTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lineItemTemplates ShotLineItemTemplate[]
|
|
|
|
@@map("shot_templates")
|
|
}
|
|
|
|
model ShotLineItemTemplate {
|
|
id String @id @default(cuid())
|
|
templateId String
|
|
taskName String
|
|
artistRole String?
|
|
defaultHours Decimal @default(0) @db.Decimal(10, 4)
|
|
rateCardId String?
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
|
|
template ShotTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("shot_line_item_templates")
|
|
}
|
|
|
|
// ─── Asset Templates ──────────────────────────────────────────────────────────
|
|
|
|
model AssetTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lineItemTemplates AssetLineItemTemplate[]
|
|
|
|
@@map("asset_templates")
|
|
}
|
|
|
|
model AssetLineItemTemplate {
|
|
id String @id @default(cuid())
|
|
templateId String
|
|
taskName String
|
|
artistRole String?
|
|
defaultHours Decimal @default(0) @db.Decimal(10, 4)
|
|
rateCardId String?
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
|
|
template AssetTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("asset_line_item_templates")
|
|
}
|
|
|
|
// ─── Shots ────────────────────────────────────────────────────────────────────
|
|
|
|
model Shot {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
shotCode String
|
|
shotNumber Int @default(0)
|
|
scene String @default("")
|
|
episode String?
|
|
shotGroup String?
|
|
description String?
|
|
durationSeconds Int?
|
|
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
lineItems LineItem[]
|
|
|
|
@@map("shots")
|
|
}
|
|
|
|
// ─── Assets ───────────────────────────────────────────────────────────────────
|
|
|
|
model Asset {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
assetName String
|
|
assetType String?
|
|
description String?
|
|
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
lineItems LineItem[]
|
|
|
|
@@map("assets")
|
|
}
|
|
|
|
// ─── Supervision ─────────────────────────────────────────────────────────────
|
|
|
|
model Supervision {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
supervisionTitle String
|
|
shootName String?
|
|
location String?
|
|
shootDates String?
|
|
numShootDays Int @default(0)
|
|
travelDays Int @default(0)
|
|
prepDays Int @default(0)
|
|
wrapDays Int @default(0)
|
|
description String?
|
|
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
lineItems LineItem[]
|
|
|
|
@@map("supervisions")
|
|
}
|
|
|
|
model SupervisionTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lineItemTemplates SupervisionLineItemTemplate[]
|
|
|
|
@@map("supervision_templates")
|
|
}
|
|
|
|
model SupervisionLineItemTemplate {
|
|
id String @id @default(cuid())
|
|
templateId String
|
|
taskName String
|
|
artistRole String?
|
|
defaultHours Decimal @default(0) @db.Decimal(10, 4)
|
|
rateCardId String?
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
|
|
template SupervisionTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("supervision_line_item_templates")
|
|
}
|
|
|
|
// ─── Previs ───────────────────────────────────────────────────────────────────
|
|
|
|
model Previs {
|
|
id String @id @default(cuid())
|
|
jobId String
|
|
sequenceName String
|
|
previsCode String?
|
|
sequenceType String @default("Previs")
|
|
description String?
|
|
duration String?
|
|
frameRange String?
|
|
revisionCount Int @default(0)
|
|
deliveryStage String @default("Blocking")
|
|
complexityMultiplier Decimal @default(1) @db.Decimal(5, 4)
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
lineItems LineItem[]
|
|
|
|
@@map("previses")
|
|
}
|
|
|
|
model PrevisTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
description String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
lineItemTemplates PrevisLineItemTemplate[]
|
|
|
|
@@map("previs_templates")
|
|
}
|
|
|
|
model PrevisLineItemTemplate {
|
|
id String @id @default(cuid())
|
|
templateId String
|
|
taskName String
|
|
artistRole String?
|
|
defaultHours Decimal @default(0) @db.Decimal(10, 4)
|
|
rateCardId String?
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
|
|
template PrevisTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("previs_line_item_templates")
|
|
}
|
|
|
|
// ─── Line Items ───────────────────────────────────────────────────────────────
|
|
|
|
model LineItem {
|
|
id String @id @default(cuid())
|
|
shotId String?
|
|
assetId String?
|
|
supervisionId String?
|
|
previsId String?
|
|
rateCardId String?
|
|
taskName String
|
|
artistRole String?
|
|
// Inputs
|
|
quantityHours Decimal @default(0) @db.Decimal(10, 4)
|
|
dailyRate Decimal @default(0) @db.Decimal(10, 4)
|
|
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
|
|
numArtists Decimal @default(1) @db.Decimal(5, 2)
|
|
numDays Decimal @default(0) @db.Decimal(10, 4)
|
|
// Overrides
|
|
manualHourlyRate Decimal? @db.Decimal(10, 4)
|
|
manualSubtotal Decimal? @db.Decimal(14, 4)
|
|
// Adjustments
|
|
markupPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
discountPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
taxPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
// Stored computed totals (recalculated server-side before PDF)
|
|
hourlyRate Decimal @default(0) @db.Decimal(10, 4)
|
|
subtotal Decimal @default(0) @db.Decimal(14, 4)
|
|
markupAmount Decimal @default(0) @db.Decimal(14, 4)
|
|
discountAmount Decimal @default(0) @db.Decimal(14, 4)
|
|
taxAmount Decimal @default(0) @db.Decimal(14, 4)
|
|
total Decimal @default(0) @db.Decimal(14, 4)
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
shot Shot? @relation(fields: [shotId], references: [id], onDelete: Cascade)
|
|
asset Asset? @relation(fields: [assetId], references: [id], onDelete: Cascade)
|
|
supervision Supervision? @relation(fields: [supervisionId], references: [id], onDelete: Cascade)
|
|
previs Previs? @relation(fields: [previsId], references: [id], onDelete: Cascade)
|
|
rateCard RateCard? @relation(fields: [rateCardId], references: [id])
|
|
|
|
@@map("line_items")
|
|
}
|
|
|
|
// ─── Task Templates ───────────────────────────────────────────────────────────
|
|
|
|
model TaskTemplate {
|
|
id String @id @default(cuid())
|
|
name String
|
|
taskName String
|
|
artistRole String?
|
|
rateCardId String?
|
|
quantityHours Decimal @default(0) @db.Decimal(10, 4)
|
|
dailyRate Decimal @default(0) @db.Decimal(10, 4)
|
|
hoursPerDay Decimal @default(8) @db.Decimal(5, 2)
|
|
numArtists Decimal @default(1) @db.Decimal(5, 2)
|
|
numDays Decimal @default(0) @db.Decimal(10, 4)
|
|
manualHourlyRate Decimal? @db.Decimal(10, 4)
|
|
manualSubtotal Decimal? @db.Decimal(14, 4)
|
|
markupPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
discountPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
taxPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("task_templates")
|
|
}
|
|
|
|
// ─── Studio Settings ──────────────────────────────────────────────────────────
|
|
|
|
model StudioSettings {
|
|
id String @id @default("default")
|
|
studioName String @default("My VFX Studio")
|
|
studioEmail String?
|
|
studioPhone String?
|
|
studioAddress String?
|
|
logoUrl String?
|
|
vatNumber String?
|
|
companyRegNumber String?
|
|
invoiceHeader String?
|
|
invoiceFooter String?
|
|
defaultTermsAndConditions String?
|
|
defaultCurrency String @default("ZAR")
|
|
defaultMarkupPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
defaultDiscountPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
defaultTaxPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("studio_settings")
|
|
}
|
|
|
|
// ─── Payment Schedule ─────────────────────────────────────────────────────────
|
|
|
|
enum ScheduleTemplate {
|
|
STANDARD_FILM
|
|
SMALL_COMMERCIAL
|
|
EPISODIC
|
|
CUSTOM
|
|
}
|
|
|
|
enum MilestoneStatus {
|
|
DRAFT
|
|
PENDING
|
|
INVOICED
|
|
PARTIALLY_PAID
|
|
PAID
|
|
OVERDUE
|
|
CANCELLED
|
|
}
|
|
|
|
model PaymentSchedule {
|
|
id String @id @default(cuid())
|
|
jobId String @unique
|
|
template ScheduleTemplate @default(CUSTOM)
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
milestones PaymentMilestone[]
|
|
|
|
@@map("payment_schedules")
|
|
}
|
|
|
|
model PaymentMilestone {
|
|
id String @id @default(cuid())
|
|
scheduleId String
|
|
title String
|
|
description String?
|
|
dueDate DateTime?
|
|
percentOfTotal Decimal @default(0) @db.Decimal(10, 4)
|
|
fixedAmount Decimal? @db.Decimal(14, 4)
|
|
status MilestoneStatus @default(PENDING)
|
|
paymentReceivedDate DateTime?
|
|
notes String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
schedule PaymentSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)
|
|
invoice Invoice?
|
|
|
|
@@map("payment_milestones")
|
|
}
|
|
|
|
// ─── Invoices ─────────────────────────────────────────────────────────────────
|
|
|
|
enum InvoiceStatus {
|
|
DRAFT
|
|
SENT
|
|
VIEWED
|
|
PARTIALLY_PAID
|
|
PAID
|
|
OVERDUE
|
|
CANCELLED
|
|
}
|
|
|
|
enum PaymentMethod {
|
|
EFT
|
|
CASH
|
|
CREDIT_CARD
|
|
BANK_TRANSFER
|
|
CRYPTO
|
|
OTHER
|
|
}
|
|
|
|
model Invoice {
|
|
id String @id @default(cuid())
|
|
invoiceNumber String @unique
|
|
clientId String
|
|
jobId String
|
|
milestoneId String? @unique
|
|
status InvoiceStatus @default(DRAFT)
|
|
issueDate DateTime @default(now())
|
|
dueDate DateTime?
|
|
paymentTerms String?
|
|
currency String @default("ZAR")
|
|
subtotal Decimal @default(0) @db.Decimal(14, 4)
|
|
taxPercent Decimal @default(0) @db.Decimal(10, 4)
|
|
taxAmount Decimal @default(0) @db.Decimal(14, 4)
|
|
totalAmount Decimal @default(0) @db.Decimal(14, 4)
|
|
amountPaid Decimal @default(0) @db.Decimal(14, 4)
|
|
amountDue Decimal @default(0) @db.Decimal(14, 4)
|
|
notes String?
|
|
internalNotes String?
|
|
bankingDetails String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
client Client @relation(fields: [clientId], references: [id])
|
|
job Job @relation(fields: [jobId], references: [id], onDelete: Cascade)
|
|
milestone PaymentMilestone? @relation(fields: [milestoneId], references: [id])
|
|
payments InvoicePayment[]
|
|
|
|
@@map("invoices")
|
|
}
|
|
|
|
model InvoicePayment {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
amount Decimal @db.Decimal(14, 4)
|
|
paymentDate DateTime
|
|
paymentMethod PaymentMethod @default(EFT)
|
|
reference String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
|
|
invoice Invoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("invoice_payments")
|
|
}
|