feat: add internal finance ledger for accounts, claims, and payroll
Keep booked income and expense separate from cash balances, with installments, recurring items, and reports. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -203,6 +203,14 @@ model Organization {
|
||||
webhookEndpoints WebhookEndpoint[]
|
||||
smsCampaigns SmsCampaign[]
|
||||
outboundSmsLogs OutboundSmsLog[]
|
||||
financialAccounts FinancialAccount[]
|
||||
financialCategories FinancialCategory[]
|
||||
financialDocuments FinancialDocument[]
|
||||
financialMovements FinancialMovement[]
|
||||
financialReceivables FinancialReceivable[]
|
||||
financialPayrolls FinancialPayroll[]
|
||||
financialRecurringItems FinancialRecurringItem[]
|
||||
financialReconciliations FinancialReconciliation[]
|
||||
wooCommerceConnections WooCommerceConnection[]
|
||||
montifyConnections MontifyConnection[]
|
||||
voipConnections VoipConnection[]
|
||||
@@ -543,6 +551,8 @@ model Person {
|
||||
trackingEvents TrackingEvent[]
|
||||
routineTasks RoutineTask[]
|
||||
outboundSmsLogs OutboundSmsLog[]
|
||||
financialDocuments FinancialDocument[]
|
||||
financialReceivables FinancialReceivable[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -1991,6 +2001,239 @@ model WebhookDelivery {
|
||||
@@index([endpointId, createdAt])
|
||||
}
|
||||
|
||||
/// دفتر مالی داخلی: حساب صندوق/بانک/تنخواه
|
||||
model FinancialAccount {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
/// bank | cash | petty
|
||||
type String
|
||||
bankName String?
|
||||
accountRef String?
|
||||
responsibleName String?
|
||||
openingBalance Decimal @default(0) @db.Decimal(18, 2)
|
||||
openingDate DateTime
|
||||
notes String?
|
||||
isActive Boolean @default(true)
|
||||
currency String @default("IRR")
|
||||
createdById String?
|
||||
movements FinancialMovement[]
|
||||
documents FinancialDocument[] @relation("DocumentAccount")
|
||||
reconciliations FinancialReconciliation[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, isActive])
|
||||
}
|
||||
|
||||
model FinancialCategory {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
name String
|
||||
/// income | expense
|
||||
kind String
|
||||
isActive Boolean @default(true)
|
||||
documents FinancialDocument[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, kind, name])
|
||||
@@index([organizationId, kind])
|
||||
}
|
||||
|
||||
/// درآمد یا هزینهٔ ثبتشده (تعهدی). موجودی حساب را خودش عوض نمیکند.
|
||||
model FinancialDocument {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
/// income | expense
|
||||
kind String
|
||||
title String
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
bookedAt DateTime
|
||||
dueAt DateTime?
|
||||
categoryId String?
|
||||
category FinancialCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
partyName String?
|
||||
accountId String?
|
||||
account FinancialAccount? @relation("DocumentAccount", fields: [accountId], references: [id], onDelete: SetNull)
|
||||
/// cash | card_to_card | pos | transfer | other
|
||||
method String?
|
||||
/// open | partial | settled | void
|
||||
status String @default("open")
|
||||
reference String?
|
||||
notes String?
|
||||
createdById String?
|
||||
voidedAt DateTime?
|
||||
voidReason String?
|
||||
movements FinancialMovement[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, kind, bookedAt])
|
||||
@@index([organizationId, status])
|
||||
@@index([personId])
|
||||
}
|
||||
|
||||
/// گردش قطعی حساب. افتتاحیه، دریافت، پرداخت، انتقال.
|
||||
model FinancialMovement {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
accountId String
|
||||
account FinancialAccount @relation(fields: [accountId], references: [id], onDelete: Cascade)
|
||||
documentId String?
|
||||
document FinancialDocument? @relation(fields: [documentId], references: [id], onDelete: SetNull)
|
||||
receivableId String?
|
||||
receivable FinancialReceivable? @relation(fields: [receivableId], references: [id], onDelete: SetNull)
|
||||
installmentId String?
|
||||
installment FinancialInstallment? @relation(fields: [installmentId], references: [id], onDelete: SetNull)
|
||||
payrollId String?
|
||||
payroll FinancialPayroll? @relation(fields: [payrollId], references: [id], onDelete: SetNull)
|
||||
/// in | out
|
||||
direction String
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
/// opening | receipt | payment | transfer_in | transfer_out
|
||||
kind String
|
||||
transferGroupId String?
|
||||
occurredAt DateTime
|
||||
memo String?
|
||||
reference String?
|
||||
createdById String?
|
||||
voidedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([organizationId, accountId, occurredAt])
|
||||
@@index([transferGroupId])
|
||||
@@index([documentId])
|
||||
@@index([receivableId])
|
||||
@@index([installmentId])
|
||||
@@index([payrollId])
|
||||
}
|
||||
|
||||
model FinancialPayroll {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
period String
|
||||
baseAmount Decimal @db.Decimal(18, 2)
|
||||
benefits Decimal @default(0) @db.Decimal(18, 2)
|
||||
bonus Decimal @default(0) @db.Decimal(18, 2)
|
||||
deductions Decimal @default(0) @db.Decimal(18, 2)
|
||||
payable Decimal @db.Decimal(18, 2)
|
||||
dueDate DateTime
|
||||
notes String?
|
||||
/// open | partial | settled | void
|
||||
status String @default("open")
|
||||
createdById String?
|
||||
voidedAt DateTime?
|
||||
movements FinancialMovement[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([organizationId, userId, period])
|
||||
@@index([organizationId, status])
|
||||
}
|
||||
|
||||
model FinancialRecurringItem {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
/// income | expense
|
||||
kind String
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
/// weekly | monthly | yearly
|
||||
interval String
|
||||
startDate DateTime
|
||||
endDate DateTime?
|
||||
nextDue DateTime
|
||||
accountId String?
|
||||
categoryId String?
|
||||
isActive Boolean @default(true)
|
||||
createdById String?
|
||||
occurrences FinancialRecurringOccurrence[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, isActive, nextDue])
|
||||
}
|
||||
|
||||
model FinancialRecurringOccurrence {
|
||||
id String @id @default(cuid())
|
||||
itemId String
|
||||
item FinancialRecurringItem @relation(fields: [itemId], references: [id], onDelete: Cascade)
|
||||
periodKey String
|
||||
dueDate DateTime
|
||||
documentId String?
|
||||
/// pending | confirmed
|
||||
status String @default("pending")
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([itemId, periodKey])
|
||||
}
|
||||
|
||||
model FinancialReconciliation {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
accountId String
|
||||
account FinancialAccount @relation(fields: [accountId], references: [id], onDelete: Cascade)
|
||||
reconciledAt DateTime
|
||||
statedBalance Decimal @db.Decimal(18, 2)
|
||||
systemBalance Decimal @db.Decimal(18, 2)
|
||||
difference Decimal @db.Decimal(18, 2)
|
||||
notes String?
|
||||
createdById String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([organizationId, accountId, reconciledAt])
|
||||
}
|
||||
|
||||
/// قرارداد یا طلب اقساطی دفتر داخلی
|
||||
model FinancialReceivable {
|
||||
id String @id @default(cuid())
|
||||
organizationId String
|
||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||
title String
|
||||
personId String?
|
||||
person Person? @relation(fields: [personId], references: [id], onDelete: SetNull)
|
||||
partyName String?
|
||||
totalAmount Decimal @db.Decimal(18, 2)
|
||||
notes String?
|
||||
/// open | settled | void
|
||||
status String @default("open")
|
||||
createdById String?
|
||||
voidedAt DateTime?
|
||||
installments FinancialInstallment[]
|
||||
movements FinancialMovement[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([organizationId, status])
|
||||
@@index([personId])
|
||||
}
|
||||
|
||||
model FinancialInstallment {
|
||||
id String @id @default(cuid())
|
||||
receivableId String
|
||||
receivable FinancialReceivable @relation(fields: [receivableId], references: [id], onDelete: Cascade)
|
||||
position Int
|
||||
dueDate DateTime
|
||||
amount Decimal @db.Decimal(18, 2)
|
||||
reminderNotifiedAt DateTime?
|
||||
movements FinancialMovement[]
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([receivableId, position])
|
||||
@@index([dueDate])
|
||||
}
|
||||
|
||||
/// لاگ یکپارچهٔ پیامک خروجی (دستی / کمپین / اتوماسیون)
|
||||
model OutboundSmsLog {
|
||||
id String @id @default(cuid())
|
||||
|
||||
Reference in New Issue
Block a user