- Add mustChangePassword field to User model in schema.prisma - Add latitude/longitude fields to Client model (matching existing migration) - Remove @nestjs/serve-static import from app.module (not in dependencies) - Add @types/multer to devDependencies and type multer config explicitly - Create migration for mustChangePassword column Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
724 lines
23 KiB
Plaintext
724 lines
23 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ─── Multi-Tenant Foundation ────────────────────────────────────────
|
|
|
|
model Tenant {
|
|
id String @id @default(uuid())
|
|
name String
|
|
slug String @unique
|
|
isActive Boolean @default(true)
|
|
settings Json @default("{}")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
users User[]
|
|
tenantRoles TenantRole[]
|
|
areas Area[]
|
|
plans Plan[]
|
|
clients Client[]
|
|
subscriptions Subscription[]
|
|
invoices Invoice[]
|
|
payments Payment[]
|
|
tickets Ticket[]
|
|
comments TicketComment[]
|
|
notifications Notification[]
|
|
|
|
@@index([deletedAt])
|
|
@@map("tenants")
|
|
}
|
|
|
|
// ─── Auth & Users ───────────────────────────────────────────────────
|
|
|
|
model User {
|
|
id String @id @default(uuid())
|
|
tenantId String? // null for super_admin (platform-level user)
|
|
email String
|
|
password String
|
|
firstName String
|
|
lastName String
|
|
isActive Boolean @default(true)
|
|
mustChangePassword Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant? @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
roles UserRole[]
|
|
tenantRoles UserTenantRole[]
|
|
assignedTickets Ticket[] @relation("TicketAssignee")
|
|
createdTickets Ticket[] @relation("TicketCreator")
|
|
authoredComments TicketComment[] @relation("CommentAuthor")
|
|
payments Payment[]
|
|
remittances Remittance[] @relation("RemittanceCollector")
|
|
confirmedRemittances Remittance[] @relation("RemittanceConfirmer")
|
|
|
|
@@unique([tenantId, email])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("users")
|
|
}
|
|
|
|
model UserRole {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
role String // super_admin (platform-level only, legacy compat)
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, role])
|
|
@@map("user_roles")
|
|
}
|
|
|
|
// ─── Tenant-Scoped Role Management ─────────────────────────────────
|
|
|
|
model TenantRole {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
name String
|
|
slug String
|
|
description String?
|
|
isSystem Boolean @default(false) // system roles can't be deleted
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
permissions RolePermission[]
|
|
users UserTenantRole[]
|
|
|
|
@@unique([tenantId, slug])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("tenant_roles")
|
|
}
|
|
|
|
model RolePermission {
|
|
id String @id @default(uuid())
|
|
tenantRoleId String
|
|
module String // clients, subscriptions, invoices, payments, tickets, employees, expenses, assets, payroll, accounts, accounting, reports, settings, users, areas, plans, dashboard, fund_transfers
|
|
canView Boolean @default(false)
|
|
canCreate Boolean @default(false)
|
|
canUpdate Boolean @default(false)
|
|
canArchive Boolean @default(false)
|
|
canApprove Boolean @default(false)
|
|
canExport Boolean @default(false)
|
|
|
|
tenantRole TenantRole @relation(fields: [tenantRoleId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([tenantRoleId, module])
|
|
@@index([tenantRoleId])
|
|
@@map("role_permissions")
|
|
}
|
|
|
|
model UserTenantRole {
|
|
id String @id @default(uuid())
|
|
userId String
|
|
tenantRoleId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
tenantRole TenantRole @relation(fields: [tenantRoleId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, tenantRoleId])
|
|
@@index([userId])
|
|
@@index([tenantRoleId])
|
|
@@map("user_tenant_roles")
|
|
}
|
|
|
|
model RefreshToken {
|
|
id String @id @default(uuid())
|
|
token String @unique
|
|
userId String
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
@@index([expiresAt])
|
|
@@map("refresh_tokens")
|
|
}
|
|
|
|
// ─── Area & Zone Management ─────────────────────────────────────────
|
|
|
|
model Area {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
name String
|
|
description String?
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
clients Client[]
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("areas")
|
|
}
|
|
|
|
// ─── Plan / Package Management ──────────────────────────────────────
|
|
|
|
model Plan {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
name String
|
|
description String?
|
|
speedDown Int // Mbps download
|
|
speedUp Int // Mbps upload
|
|
price Decimal @db.Decimal(10, 2)
|
|
billingCycle Int @default(30) // days
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
subscriptions Subscription[]
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("plans")
|
|
}
|
|
|
|
// ─── Client Profiling ───────────────────────────────────────────────
|
|
|
|
model Client {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
accountNumber String
|
|
firstName String
|
|
lastName String
|
|
email String?
|
|
phone String?
|
|
address String
|
|
areaId String?
|
|
status String @default("active") // active, inactive, suspended
|
|
latitude Float?
|
|
longitude Float?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
area Area? @relation(fields: [areaId], references: [id])
|
|
subscriptions Subscription[]
|
|
invoices Invoice[]
|
|
payments Payment[]
|
|
tickets Ticket[]
|
|
|
|
@@unique([tenantId, accountNumber])
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([deletedAt])
|
|
@@map("clients")
|
|
}
|
|
|
|
// ─── Subscription Management ────────────────────────────────────────
|
|
|
|
model Subscription {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
clientId String
|
|
planId String
|
|
type String // prepaid, postpaid
|
|
status String @default("pending") // pending, active, suspended, cancelled, expired
|
|
startDate DateTime?
|
|
endDate DateTime?
|
|
installedAt DateTime?
|
|
activatedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
|
plan Plan @relation(fields: [planId], references: [id])
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([clientId])
|
|
@@index([deletedAt])
|
|
@@map("subscriptions")
|
|
}
|
|
|
|
// ─── Billing & Invoicing ────────────────────────────────────────────
|
|
|
|
model Invoice {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
clientId String
|
|
number String
|
|
amount Decimal @db.Decimal(10, 2)
|
|
balance Decimal @db.Decimal(10, 2) // remaining unpaid
|
|
status String @default("draft") // draft, sent, partial, paid, overdue, void
|
|
dueDate DateTime
|
|
paidAt DateTime?
|
|
periodStart DateTime?
|
|
periodEnd DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
|
payments Payment[]
|
|
|
|
@@unique([tenantId, number])
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([clientId])
|
|
@@index([deletedAt])
|
|
@@map("invoices")
|
|
}
|
|
|
|
// ─── Payment & Collection ───────────────────────────────────────────
|
|
|
|
model Payment {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
clientId String
|
|
invoiceId String?
|
|
collectedById String?
|
|
amount Decimal @db.Decimal(10, 2)
|
|
method String // gcash, maya, cash, bank_transfer
|
|
referenceNo String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
client Client @relation(fields: [clientId], references: [id], onDelete: Cascade)
|
|
invoice Invoice? @relation(fields: [invoiceId], references: [id])
|
|
collectedBy User? @relation(fields: [collectedById], references: [id])
|
|
|
|
@@index([tenantId])
|
|
@@index([clientId])
|
|
@@index([invoiceId])
|
|
@@index([deletedAt])
|
|
@@map("payments")
|
|
}
|
|
|
|
model Remittance {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
collectorId String
|
|
confirmedById String?
|
|
totalAmount Decimal @db.Decimal(10, 2)
|
|
status String @default("pending") // pending, confirmed, rejected
|
|
submittedAt DateTime @default(now())
|
|
confirmedAt DateTime?
|
|
notes String?
|
|
deletedAt DateTime?
|
|
|
|
collector User @relation("RemittanceCollector", fields: [collectorId], references: [id])
|
|
confirmedBy User? @relation("RemittanceConfirmer", fields: [confirmedById], references: [id])
|
|
payments RemittancePayment[]
|
|
|
|
@@index([tenantId])
|
|
@@index([collectorId])
|
|
@@index([deletedAt])
|
|
@@map("remittances")
|
|
}
|
|
|
|
model RemittancePayment {
|
|
id String @id @default(uuid())
|
|
remittanceId String
|
|
paymentId String
|
|
|
|
remittance Remittance @relation(fields: [remittanceId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([remittanceId, paymentId])
|
|
@@map("remittance_payments")
|
|
}
|
|
|
|
// ─── Tickets (Work Orders) ──────────────────────────────────────────
|
|
|
|
model Ticket {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
clientId String?
|
|
createdById String
|
|
assigneeId String?
|
|
type String // installation, activation, support, maintenance
|
|
status String @default("open") // open, in_progress, resolved, cancelled
|
|
title String
|
|
description String?
|
|
priority String @default("normal") // low, normal, high, urgent
|
|
latitude Float?
|
|
longitude Float?
|
|
resolvedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
client Client? @relation(fields: [clientId], references: [id])
|
|
createdBy User @relation("TicketCreator", fields: [createdById], references: [id])
|
|
assignee User? @relation("TicketAssignee", fields: [assigneeId], references: [id])
|
|
comments TicketComment[]
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, type, status])
|
|
@@index([clientId])
|
|
@@index([assigneeId])
|
|
@@index([deletedAt])
|
|
@@map("tickets")
|
|
}
|
|
|
|
// ─── Notifications ──────────────────────────────────────────────────
|
|
|
|
model Notification {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
userId String?
|
|
clientId String?
|
|
type String // sms, in_app
|
|
channel String // billing_reminder, payment_confirmation, ticket_update
|
|
title String
|
|
message String
|
|
isRead Boolean @default(false)
|
|
sentAt DateTime?
|
|
ticketId String?
|
|
createdAt DateTime @default(now())
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([tenantId])
|
|
@@index([userId, isRead])
|
|
@@map("notifications")
|
|
}
|
|
|
|
// ─── Ticket Comments ──────────────────────────────────────────────────
|
|
|
|
model TicketComment {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
ticketId String
|
|
userId String
|
|
content String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
|
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
|
author User @relation("CommentAuthor", fields: [userId], references: [id])
|
|
attachments TicketAttachment[]
|
|
|
|
@@index([ticketId])
|
|
@@index([tenantId])
|
|
@@map("ticket_comments")
|
|
}
|
|
|
|
model TicketAttachment {
|
|
id String @id @default(uuid())
|
|
commentId String
|
|
fileName String
|
|
filePath String
|
|
fileType String
|
|
fileSize Int
|
|
createdAt DateTime @default(now())
|
|
|
|
comment TicketComment @relation(fields: [commentId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("ticket_attachments")
|
|
}
|
|
|
|
// ─── Audit Log (append-only, no soft delete) ────────────────────────
|
|
|
|
model AuditLog {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
userId String
|
|
action String
|
|
entity String
|
|
entityId String
|
|
details Json @default("{}")
|
|
ipAddress String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, entity])
|
|
@@index([userId])
|
|
@@map("audit_logs")
|
|
}
|
|
|
|
// ─── Employee Management ────────────────────────────────────────────
|
|
|
|
model Employee {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
userId String? @unique // Linked user account (optional, 1:1)
|
|
firstName String
|
|
lastName String
|
|
email String?
|
|
phone String?
|
|
position String
|
|
department String?
|
|
employeeNo String
|
|
status String @default("active") // active, on_leave, terminated
|
|
hireDate DateTime @default(now())
|
|
terminatedAt DateTime?
|
|
salary Decimal? @db.Decimal(10, 2)
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
assets Asset[] @relation("AssetAssignee")
|
|
payslips Payslip[]
|
|
|
|
@@unique([tenantId, employeeNo])
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([deletedAt])
|
|
@@map("employees")
|
|
}
|
|
|
|
// ─── Payroll ────────────────────────────────────────────────────────
|
|
|
|
model PayrollRun {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
period String
|
|
status String @default("draft") // draft, processing, completed
|
|
totalAmount Decimal @default(0) @db.Decimal(12, 2)
|
|
processedBy String?
|
|
processedAt DateTime?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
payslips Payslip[]
|
|
|
|
@@unique([tenantId, period])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("payroll_runs")
|
|
}
|
|
|
|
model Payslip {
|
|
id String @id @default(uuid())
|
|
payrollRunId String
|
|
employeeId String
|
|
baseSalary Decimal @db.Decimal(10, 2)
|
|
deductions Decimal @default(0) @db.Decimal(10, 2)
|
|
bonuses Decimal @default(0) @db.Decimal(10, 2)
|
|
netPay Decimal @db.Decimal(10, 2)
|
|
status String @default("pending") // pending, paid
|
|
notes String?
|
|
|
|
payrollRun PayrollRun @relation(fields: [payrollRunId], references: [id], onDelete: Cascade)
|
|
employee Employee @relation(fields: [employeeId], references: [id])
|
|
|
|
@@unique([payrollRunId, employeeId])
|
|
@@index([payrollRunId])
|
|
@@index([employeeId])
|
|
@@map("payslips")
|
|
}
|
|
|
|
// ─── Recurring Expenses ─────────────────────────────────────────────
|
|
|
|
model RecurringExpense {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
category String
|
|
description String
|
|
amount Decimal @db.Decimal(10, 2)
|
|
frequency String @default("monthly") // monthly, quarterly, yearly
|
|
isActive Boolean @default(true)
|
|
nextRunDate DateTime
|
|
lastRunDate DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("recurring_expenses")
|
|
}
|
|
|
|
// ─── Expense Management ─────────────────────────────────────────────
|
|
|
|
model Expense {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
createdById String
|
|
approvedById String?
|
|
category String
|
|
description String
|
|
amount Decimal @db.Decimal(10, 2)
|
|
receiptUrl String?
|
|
status String @default("pending") // pending, approved, rejected
|
|
expenseDate DateTime @default(now())
|
|
approvedAt DateTime?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([tenantId, category])
|
|
@@index([deletedAt])
|
|
@@map("expenses")
|
|
}
|
|
|
|
// ─── Company Accounts & Fund Transfers ──────────────────────────────
|
|
|
|
model CompanyAccount {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
name String
|
|
type String // bank, e_wallet, cash
|
|
accountNo String?
|
|
balance Decimal @default(0) @db.Decimal(12, 2)
|
|
isActive Boolean @default(true)
|
|
isSystem Boolean @default(false)
|
|
chartOfAccountId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
outgoing FundTransfer[] @relation("TransferFrom")
|
|
incoming FundTransfer[] @relation("TransferTo")
|
|
|
|
@@unique([tenantId, name])
|
|
@@index([tenantId])
|
|
@@index([deletedAt])
|
|
@@map("company_accounts")
|
|
}
|
|
|
|
model FundTransfer {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
fromAccountId String
|
|
toAccountId String
|
|
amount Decimal @db.Decimal(12, 2)
|
|
description String?
|
|
transferredBy String
|
|
createdAt DateTime @default(now())
|
|
|
|
fromAccount CompanyAccount @relation("TransferFrom", fields: [fromAccountId], references: [id])
|
|
toAccount CompanyAccount @relation("TransferTo", fields: [toAccountId], references: [id])
|
|
|
|
@@index([tenantId])
|
|
@@map("fund_transfers")
|
|
}
|
|
|
|
// ─── Asset Management ───────────────────────────────────────────────
|
|
|
|
model Asset {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
name String
|
|
category String // router, olt, cable, tool, vehicle, computer, other
|
|
serialNumber String?
|
|
purchaseDate DateTime?
|
|
purchasePrice Decimal? @db.Decimal(10, 2)
|
|
assignedToId String?
|
|
status String @default("available") // available, in_use, maintenance, retired
|
|
location String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
assignedTo Employee? @relation("AssetAssignee", fields: [assignedToId], references: [id])
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, status])
|
|
@@index([tenantId, category])
|
|
@@index([deletedAt])
|
|
@@map("assets")
|
|
}
|
|
|
|
// ─── Billing Settings ───────────────────────────────────────────────
|
|
|
|
model BillingSetting {
|
|
id String @id @default(uuid())
|
|
tenantId String @unique
|
|
autoGenerate Boolean @default(true)
|
|
gracePeriodDays Int @default(7)
|
|
dueDateOffsetDays Int @default(15)
|
|
lateFeePercent Decimal @default(0) @db.Decimal(5, 2)
|
|
invoicePrefix String @default("INV")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("billing_settings")
|
|
}
|
|
|
|
// ─── Chart of Accounts ──────────────────────────────────────────────
|
|
|
|
model ChartOfAccount {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
code String
|
|
name String
|
|
type String // asset, liability, equity, revenue, expense
|
|
parentId String?
|
|
isActive Boolean @default(true)
|
|
isSystem Boolean @default(false)
|
|
balance Decimal @default(0) @db.Decimal(14, 2)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
deletedAt DateTime?
|
|
|
|
parent ChartOfAccount? @relation("AccountTree", fields: [parentId], references: [id])
|
|
children ChartOfAccount[] @relation("AccountTree")
|
|
journalLines JournalLine[]
|
|
|
|
@@unique([tenantId, code])
|
|
@@index([tenantId])
|
|
@@index([tenantId, type])
|
|
@@index([deletedAt])
|
|
@@map("chart_of_accounts")
|
|
}
|
|
|
|
// ─── Journal Entries (append-only, no soft delete) ──────────────────
|
|
|
|
model JournalEntry {
|
|
id String @id @default(uuid())
|
|
tenantId String
|
|
entryDate DateTime @default(now())
|
|
description String
|
|
reference String?
|
|
sourceType String?
|
|
sourceId String?
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
|
|
lines JournalLine[]
|
|
|
|
@@index([tenantId])
|
|
@@index([tenantId, sourceType, sourceId])
|
|
@@map("journal_entries")
|
|
}
|
|
|
|
model JournalLine {
|
|
id String @id @default(uuid())
|
|
journalEntryId String
|
|
accountId String
|
|
debit Decimal @default(0) @db.Decimal(14, 2)
|
|
credit Decimal @default(0) @db.Decimal(14, 2)
|
|
|
|
journalEntry JournalEntry @relation(fields: [journalEntryId], references: [id], onDelete: Cascade)
|
|
account ChartOfAccount @relation(fields: [accountId], references: [id])
|
|
|
|
@@index([journalEntryId])
|
|
@@index([accountId])
|
|
@@map("journal_lines")
|
|
}
|