1624 lines
50 KiB
Plaintext
1624 lines
50 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
output = "../generated"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ENUMS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
enum CompanyStatus {
|
|
PENDING
|
|
TRIALING
|
|
ACTIVE
|
|
PAST_DUE
|
|
SUSPENDED
|
|
CANCELLED
|
|
}
|
|
|
|
enum Plan {
|
|
STARTER
|
|
GROWTH
|
|
PRO
|
|
}
|
|
|
|
enum BillingPeriod {
|
|
MONTHLY
|
|
ANNUAL
|
|
}
|
|
|
|
enum SubscriptionStatus {
|
|
TRIALING
|
|
ACTIVE
|
|
PAYMENT_PENDING
|
|
PAST_DUE
|
|
SUSPENDED
|
|
CANCELLED
|
|
EXPIRED
|
|
PAUSED
|
|
UNPAID
|
|
}
|
|
|
|
enum InvoiceStatus {
|
|
PENDING
|
|
PAID
|
|
FAILED
|
|
REFUNDED
|
|
VOIDED
|
|
}
|
|
|
|
enum BillingInvoiceTerms {
|
|
DUE_ON_RECEIPT
|
|
NET_7
|
|
NET_15
|
|
NET_30
|
|
NET_45
|
|
NET_60
|
|
}
|
|
|
|
enum BillingInvoiceStatus {
|
|
DRAFT
|
|
OPEN
|
|
PAID
|
|
PARTIALLY_PAID
|
|
PAYMENT_PENDING
|
|
PAST_DUE
|
|
VOID
|
|
UNCOLLECTIBLE
|
|
REFUNDED
|
|
PARTIALLY_REFUNDED
|
|
}
|
|
|
|
enum BillingInvoiceType {
|
|
SUBSCRIPTION_INITIAL
|
|
SUBSCRIPTION_RENEWAL
|
|
TRIAL_CONVERSION
|
|
SUBSCRIPTION_UPGRADE
|
|
SUBSCRIPTION_DOWNGRADE_CREDIT
|
|
USAGE_BASED
|
|
ONE_TIME
|
|
MANUAL
|
|
CORRECTION
|
|
CANCELLATION_FEE
|
|
}
|
|
|
|
enum BillingLineItemType {
|
|
SUBSCRIPTION_FEE
|
|
SEAT_FEE
|
|
USAGE_FEE
|
|
SETUP_FEE
|
|
DISCOUNT
|
|
TAX
|
|
CREDIT
|
|
PRORATION
|
|
REFUND_ADJUSTMENT
|
|
MANUAL_ADJUSTMENT
|
|
PROFESSIONAL_SERVICES
|
|
CANCELLATION_FEE
|
|
}
|
|
|
|
enum BillingPaymentMethodType {
|
|
CARD
|
|
ACH_DEBIT
|
|
BANK_TRANSFER
|
|
WIRE_TRANSFER
|
|
MANUAL_INVOICE
|
|
PURCHASE_ORDER
|
|
}
|
|
|
|
enum BillingPaymentIntentStatus {
|
|
REQUIRES_PAYMENT_METHOD
|
|
REQUIRES_CONFIRMATION
|
|
REQUIRES_ACTION
|
|
PROCESSING
|
|
SUCCEEDED
|
|
FAILED
|
|
CANCELED
|
|
REFUNDED
|
|
PARTIALLY_REFUNDED
|
|
}
|
|
|
|
enum BillingPaymentAttemptStatus {
|
|
PENDING
|
|
PROCESSING
|
|
SUCCEEDED
|
|
FAILED
|
|
CANCELED
|
|
REFUNDED
|
|
PARTIALLY_REFUNDED
|
|
}
|
|
|
|
enum BillingRefundStatus {
|
|
PENDING
|
|
SUCCEEDED
|
|
FAILED
|
|
}
|
|
|
|
enum BillingCreditNoteStatus {
|
|
ISSUED
|
|
APPLIED
|
|
VOID
|
|
}
|
|
|
|
enum PaymentProvider {
|
|
AMANPAY
|
|
PAYPAL
|
|
}
|
|
|
|
enum PaymentStatus {
|
|
PENDING
|
|
SUCCEEDED
|
|
FAILED
|
|
REFUNDED
|
|
PARTIALLY_REFUNDED
|
|
}
|
|
|
|
enum PaymentType {
|
|
CHARGE
|
|
DEPOSIT
|
|
REFUND
|
|
}
|
|
|
|
enum EmployeeRole {
|
|
OWNER
|
|
MANAGER
|
|
AGENT
|
|
}
|
|
|
|
enum VehicleStatus {
|
|
AVAILABLE
|
|
RENTED
|
|
MAINTENANCE
|
|
OUT_OF_SERVICE
|
|
}
|
|
|
|
enum VehicleCategory {
|
|
ECONOMY
|
|
COMPACT
|
|
MIDSIZE
|
|
FULLSIZE
|
|
SUV
|
|
LUXURY
|
|
VAN
|
|
TRUCK
|
|
}
|
|
|
|
enum Transmission {
|
|
AUTOMATIC
|
|
MANUAL
|
|
}
|
|
|
|
enum FuelType {
|
|
GASOLINE
|
|
DIESEL
|
|
ELECTRIC
|
|
HYBRID
|
|
}
|
|
|
|
enum OfferType {
|
|
PERCENTAGE
|
|
FIXED_AMOUNT
|
|
FREE_DAY
|
|
SPECIAL_RATE
|
|
}
|
|
|
|
enum ReservationStatus {
|
|
DRAFT
|
|
CONFIRMED
|
|
ACTIVE
|
|
COMPLETED
|
|
CANCELLED
|
|
NO_SHOW
|
|
}
|
|
|
|
enum BookingSource {
|
|
DASHBOARD
|
|
PUBLIC_SITE
|
|
MARKETPLACE
|
|
API
|
|
}
|
|
|
|
enum CancelledBy {
|
|
COMPANY
|
|
RENTER
|
|
SYSTEM
|
|
}
|
|
|
|
enum LicenseStatus {
|
|
PENDING
|
|
VALID
|
|
EXPIRING
|
|
APPROVED
|
|
DENIED
|
|
EXPIRED
|
|
}
|
|
|
|
enum InsuranceType {
|
|
CDW
|
|
SCDW
|
|
THEFT
|
|
THIRD_PARTY
|
|
FULL
|
|
BASIC
|
|
ROADSIDE
|
|
PERSONAL
|
|
CUSTOM
|
|
}
|
|
|
|
enum InsuranceChargeType {
|
|
PER_DAY
|
|
PER_RENTAL
|
|
PERCENTAGE_OF_RENTAL
|
|
}
|
|
|
|
enum DamageReportType {
|
|
CHECKIN
|
|
CHECKOUT
|
|
}
|
|
|
|
enum PricingRuleType {
|
|
SURCHARGE
|
|
DISCOUNT
|
|
}
|
|
|
|
enum PricingCondition {
|
|
AGE_LESS_THAN
|
|
AGE_GREATER_THAN
|
|
LICENSE_YEARS_LESS_THAN
|
|
LICENSE_YEARS_GREATER_THAN
|
|
}
|
|
|
|
enum PriceAdjustmentType {
|
|
PERCENTAGE
|
|
FLAT_PER_DAY
|
|
FLAT_TOTAL
|
|
}
|
|
|
|
enum AdditionalDriverCharge {
|
|
FREE
|
|
PER_DAY
|
|
FLAT
|
|
}
|
|
|
|
enum FuelPolicyType {
|
|
FULL_TO_FULL
|
|
FULL_TO_EMPTY
|
|
SAME_TO_SAME
|
|
PREPAID
|
|
FREE
|
|
}
|
|
|
|
enum InspectionType {
|
|
CHECKIN
|
|
CHECKOUT
|
|
}
|
|
|
|
enum FuelLevel {
|
|
FULL
|
|
SEVEN_EIGHTHS
|
|
THREE_QUARTERS
|
|
FIVE_EIGHTHS
|
|
HALF
|
|
THREE_EIGHTHS
|
|
QUARTER
|
|
ONE_EIGHTH
|
|
EMPTY
|
|
}
|
|
|
|
enum DiagramView {
|
|
TOP
|
|
FRONT
|
|
REAR
|
|
LEFT
|
|
RIGHT
|
|
}
|
|
|
|
enum DamageType {
|
|
SCRATCH
|
|
DENT
|
|
CRACK
|
|
CHIP
|
|
MISSING
|
|
STAIN
|
|
OTHER
|
|
}
|
|
|
|
enum DamageSeverity {
|
|
MINOR
|
|
MODERATE
|
|
MAJOR
|
|
}
|
|
|
|
enum ReportingPeriod {
|
|
WEEKLY
|
|
MONTHLY
|
|
QUARTERLY
|
|
ANNUAL
|
|
}
|
|
|
|
enum ReportFormat {
|
|
PDF
|
|
CSV
|
|
BOTH
|
|
}
|
|
|
|
enum AdminRole {
|
|
SUPER_ADMIN
|
|
ADMIN
|
|
SUPPORT
|
|
FINANCE
|
|
VIEWER
|
|
}
|
|
|
|
enum AdminResource {
|
|
COMPANIES
|
|
COMPANY_EMPLOYEES
|
|
SUBSCRIPTIONS
|
|
PAYMENTS
|
|
OFFERS
|
|
RENTERS
|
|
ADMIN_USERS
|
|
AUDIT_LOGS
|
|
PLATFORM_METRICS
|
|
}
|
|
|
|
enum AdminAction {
|
|
READ
|
|
CREATE
|
|
UPDATE
|
|
DELETE
|
|
SUSPEND
|
|
IMPERSONATE
|
|
}
|
|
|
|
enum NotificationType {
|
|
NEW_BOOKING
|
|
BOOKING_CANCELLED
|
|
PAYMENT_RECEIVED
|
|
PAYMENT_FAILED
|
|
SUBSCRIPTION_TRIAL_ENDING
|
|
SUBSCRIPTION_SUSPENDED
|
|
VEHICLE_MAINTENANCE_DUE
|
|
OFFER_EXPIRING
|
|
NEW_REVIEW_RECEIVED
|
|
BOOKING_CONFIRMED
|
|
PICKUP_REMINDER_24H
|
|
PICKUP_REMINDER_2H
|
|
VEHICLE_READY
|
|
RETURN_REMINDER
|
|
BOOKING_CANCELLED_BY_COMPANY
|
|
REFUND_PROCESSED
|
|
NEW_OFFER_FROM_SAVED_COMPANY
|
|
REVIEW_REQUEST
|
|
}
|
|
|
|
enum NotificationChannel {
|
|
EMAIL
|
|
SMS
|
|
WHATSAPP
|
|
IN_APP
|
|
PUSH
|
|
}
|
|
|
|
enum NotificationStatus {
|
|
PENDING
|
|
SENT
|
|
DELIVERED
|
|
FAILED
|
|
READ
|
|
}
|
|
|
|
enum CalendarBlockType {
|
|
MANUAL
|
|
MAINTENANCE
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// B2B — COMPANY SIDE
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model Company {
|
|
id String @id @default(cuid())
|
|
name String
|
|
slug String @unique
|
|
email String @unique
|
|
phone String?
|
|
address Json?
|
|
status CompanyStatus @default(PENDING)
|
|
subscriptionPaymentRef String?
|
|
apiKey String @unique @default(cuid())
|
|
|
|
subscription Subscription?
|
|
billingAccounts BillingAccount[]
|
|
billingInvoices BillingInvoice[]
|
|
brand BrandSettings?
|
|
employees Employee[]
|
|
vehicles Vehicle[]
|
|
offers Offer[]
|
|
reservations Reservation[]
|
|
customers Customer[]
|
|
rentalPayments RentalPayment[]
|
|
subscriptionInvoices SubscriptionInvoice[]
|
|
contractSettings ContractSettings?
|
|
accountingSettings AccountingSettings?
|
|
insurancePolicies InsurancePolicy[]
|
|
pricingRules PricingRule[]
|
|
notifications Notification[] @relation("CompanyNotifications")
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
BillingEvent BillingEvent[]
|
|
|
|
@@map("companies")
|
|
}
|
|
|
|
model Subscription {
|
|
id String @id @default(cuid())
|
|
companyId String @unique
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
plan Plan @default(STARTER)
|
|
billingPeriod BillingPeriod @default(MONTHLY)
|
|
status SubscriptionStatus @default(TRIALING)
|
|
currency String @default("MAD")
|
|
trialStartAt DateTime?
|
|
trialEndAt DateTime?
|
|
trialUsed Boolean @default(false)
|
|
currentPeriodStart DateTime?
|
|
currentPeriodEnd DateTime?
|
|
paymentPendingSince DateTime?
|
|
paymentDueAt DateTime?
|
|
pastDueSince DateTime?
|
|
suspendedAt DateTime?
|
|
endedAt DateTime?
|
|
cancelledAt DateTime?
|
|
cancelAtPeriodEnd Boolean @default(false)
|
|
retryCount Int @default(0)
|
|
maxRetryCount Int @default(5)
|
|
invoices SubscriptionInvoice[]
|
|
billingInvoices BillingInvoice[]
|
|
events SubscriptionEvent[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
BillingEvent BillingEvent[]
|
|
|
|
@@map("subscriptions")
|
|
}
|
|
|
|
model SubscriptionEvent {
|
|
id String @id @default(cuid())
|
|
subscriptionId String
|
|
subscription Subscription @relation(fields: [subscriptionId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
eventType String
|
|
source String @default("system")
|
|
payload Json @default("{}")
|
|
occurredAt DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([subscriptionId])
|
|
@@index([companyId])
|
|
@@map("subscription_events")
|
|
}
|
|
|
|
model SubscriptionInvoice {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
subscriptionId String
|
|
subscription Subscription @relation(fields: [subscriptionId], references: [id])
|
|
providerInvoiceId String?
|
|
amount Int
|
|
currency String @default("MAD")
|
|
status InvoiceStatus
|
|
amanpayTransactionId String? @unique
|
|
paypalCaptureId String? @unique
|
|
paymentProvider PaymentProvider @default(AMANPAY)
|
|
billingInvoiceId String? @unique
|
|
billingInvoice BillingInvoice? @relation(fields: [billingInvoiceId], references: [id])
|
|
dueAt DateTime?
|
|
paidAt DateTime?
|
|
failedAt DateTime?
|
|
voidedAt DateTime?
|
|
attempts PaymentAttempt[]
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([companyId])
|
|
@@map("subscription_invoices")
|
|
}
|
|
|
|
model BillingAccount {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
isPrimary Boolean @default(true)
|
|
legalName String
|
|
billingEmail String
|
|
billingAddress Json?
|
|
taxId String?
|
|
taxExempt Boolean @default(false)
|
|
defaultCurrency String @default("MAD")
|
|
defaultPaymentMethodId String?
|
|
defaultPaymentMethod BillingPaymentMethod? @relation("BillingAccountDefaultPaymentMethod", fields: [defaultPaymentMethodId], references: [id])
|
|
invoiceTerms BillingInvoiceTerms @default(DUE_ON_RECEIPT)
|
|
netTermsDays Int @default(0)
|
|
providerCustomerId String?
|
|
dunningPaused Boolean @default(false)
|
|
dunningPausedAt DateTime?
|
|
dunningPausedBy String?
|
|
metadata Json @default("{}")
|
|
paymentMethods BillingPaymentMethod[] @relation("BillingAccountPaymentMethods")
|
|
invoices BillingInvoice[]
|
|
paymentIntents BillingPaymentIntent[]
|
|
paymentAttempts BillingPaymentAttempt[]
|
|
creditBalances BillingCreditBalance[]
|
|
creditLedgerEntries BillingCreditLedgerEntry[]
|
|
creditNotes BillingCreditNote[]
|
|
refunds BillingRefund[]
|
|
events BillingEvent[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([companyId, isPrimary])
|
|
@@map("billing_accounts")
|
|
}
|
|
|
|
model BillingPaymentMethod {
|
|
id String @id @default(cuid())
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation("BillingAccountPaymentMethods", fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
type BillingPaymentMethodType
|
|
providerPaymentMethodId String?
|
|
label String?
|
|
brand String?
|
|
last4 String?
|
|
expMonth Int?
|
|
expYear Int?
|
|
isDefault Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
metadata Json @default("{}")
|
|
defaultForBillingAccounts BillingAccount[] @relation("BillingAccountDefaultPaymentMethod")
|
|
paymentIntents BillingPaymentIntent[]
|
|
paymentAttempts BillingPaymentAttempt[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([billingAccountId])
|
|
@@map("billing_payment_methods")
|
|
}
|
|
|
|
model BillingInvoice {
|
|
id String @id @default(cuid())
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
subscriptionId String?
|
|
subscription Subscription? @relation(fields: [subscriptionId], references: [id])
|
|
legacySubscriptionInvoice SubscriptionInvoice?
|
|
invoiceNumber String? @unique
|
|
invoiceSequence Int? @unique
|
|
invoiceType BillingInvoiceType
|
|
status BillingInvoiceStatus @default(DRAFT)
|
|
currency String @default("MAD")
|
|
subtotalAmount Int @default(0)
|
|
discountAmount Int @default(0)
|
|
creditAmount Int @default(0)
|
|
taxAmount Int @default(0)
|
|
totalAmount Int @default(0)
|
|
amountPaid Int @default(0)
|
|
amountDue Int @default(0)
|
|
invoiceDate DateTime?
|
|
dueAt DateTime?
|
|
finalizedAt DateTime?
|
|
paidAt DateTime?
|
|
voidedAt DateTime?
|
|
markedUncollectibleAt DateTime?
|
|
billingName String?
|
|
billingEmail String?
|
|
billingAddress Json?
|
|
providerInvoiceId String?
|
|
paymentProvider PaymentProvider?
|
|
isSubscriptionBlocking Boolean @default(false)
|
|
adminReason String?
|
|
metadata Json @default("{}")
|
|
createdByAdminId String?
|
|
lineItems BillingInvoiceLineItem[]
|
|
paymentIntents BillingPaymentIntent[]
|
|
paymentAttempts BillingPaymentAttempt[]
|
|
taxRecords BillingTaxRecord[]
|
|
creditNotes BillingCreditNote[]
|
|
refunds BillingRefund[]
|
|
events BillingEvent[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
BillingCreditLedgerEntry BillingCreditLedgerEntry[]
|
|
|
|
@@index([billingAccountId])
|
|
@@index([companyId])
|
|
@@index([subscriptionId])
|
|
@@map("billing_invoices")
|
|
}
|
|
|
|
model BillingInvoiceLineItem {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
subscriptionId String?
|
|
plan Plan?
|
|
type BillingLineItemType
|
|
description String
|
|
quantity Int @default(1)
|
|
unitAmount Int
|
|
amount Int
|
|
currency String @default("MAD")
|
|
periodStart DateTime?
|
|
periodEnd DateTime?
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@map("billing_invoice_line_items")
|
|
}
|
|
|
|
model BillingPaymentIntent {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
paymentMethodId String?
|
|
paymentMethod BillingPaymentMethod? @relation(fields: [paymentMethodId], references: [id])
|
|
providerPaymentIntentId String?
|
|
status BillingPaymentIntentStatus @default(REQUIRES_PAYMENT_METHOD)
|
|
amount Int
|
|
currency String @default("MAD")
|
|
metadata Json @default("{}")
|
|
paymentAttempts BillingPaymentAttempt[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([invoiceId])
|
|
@@index([billingAccountId])
|
|
@@map("billing_payment_intents")
|
|
}
|
|
|
|
model BillingPaymentAttempt {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
paymentIntentId String?
|
|
paymentIntent BillingPaymentIntent? @relation(fields: [paymentIntentId], references: [id])
|
|
paymentMethodId String?
|
|
paymentMethod BillingPaymentMethod? @relation(fields: [paymentMethodId], references: [id])
|
|
providerPaymentId String?
|
|
status BillingPaymentAttemptStatus
|
|
amount Int
|
|
currency String @default("MAD")
|
|
failureCode String?
|
|
failureMessage String?
|
|
attemptedAt DateTime
|
|
metadata Json @default("{}")
|
|
refunds BillingRefund[]
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@index([billingAccountId])
|
|
@@map("billing_payment_attempts")
|
|
}
|
|
|
|
model BillingCreditBalance {
|
|
id String @id @default(cuid())
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
currency String @default("MAD")
|
|
balanceAmount Int @default(0)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([billingAccountId, currency])
|
|
@@map("billing_credit_balances")
|
|
}
|
|
|
|
model BillingCreditLedgerEntry {
|
|
id String @id @default(cuid())
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
invoiceId String?
|
|
invoice BillingInvoice? @relation(fields: [invoiceId], references: [id], onDelete: SetNull)
|
|
type String
|
|
amount Int
|
|
currency String @default("MAD")
|
|
reason String
|
|
createdBy String?
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([billingAccountId])
|
|
@@map("billing_credit_ledger_entries")
|
|
}
|
|
|
|
model BillingCreditNote {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
amount Int
|
|
currency String @default("MAD")
|
|
reason String
|
|
status BillingCreditNoteStatus @default(ISSUED)
|
|
createdBy String?
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@index([billingAccountId])
|
|
@@map("billing_credit_notes")
|
|
}
|
|
|
|
model BillingRefund {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
paymentAttemptId String?
|
|
paymentAttempt BillingPaymentAttempt? @relation(fields: [paymentAttemptId], references: [id], onDelete: SetNull)
|
|
billingAccountId String
|
|
billingAccount BillingAccount @relation(fields: [billingAccountId], references: [id], onDelete: Cascade)
|
|
amount Int
|
|
currency String @default("MAD")
|
|
reason String
|
|
status BillingRefundStatus @default(PENDING)
|
|
providerRefundId String?
|
|
createdBy String?
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@index([billingAccountId])
|
|
@@map("billing_refunds")
|
|
}
|
|
|
|
model BillingTaxRecord {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice BillingInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
jurisdiction String?
|
|
taxRate Float?
|
|
taxAmount Int
|
|
taxType String?
|
|
taxExempt Boolean @default(false)
|
|
exemptionReason String?
|
|
providerTaxId String?
|
|
metadata Json @default("{}")
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@map("billing_tax_records")
|
|
}
|
|
|
|
model BillingEvent {
|
|
id String @id @default(cuid())
|
|
billingAccountId String?
|
|
billingAccount BillingAccount? @relation(fields: [billingAccountId], references: [id], onDelete: SetNull)
|
|
invoiceId String?
|
|
invoice BillingInvoice? @relation(fields: [invoiceId], references: [id], onDelete: SetNull)
|
|
subscriptionId String?
|
|
subscription Subscription? @relation(fields: [subscriptionId], references: [id], onDelete: SetNull)
|
|
companyId String?
|
|
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
|
|
eventType String
|
|
source String
|
|
payload Json @default("{}")
|
|
occurredAt DateTime
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([billingAccountId])
|
|
@@index([invoiceId])
|
|
@@index([subscriptionId])
|
|
@@index([companyId])
|
|
@@map("billing_events")
|
|
}
|
|
|
|
model PaymentAttempt {
|
|
id String @id @default(cuid())
|
|
invoiceId String
|
|
invoice SubscriptionInvoice @relation(fields: [invoiceId], references: [id], onDelete: Cascade)
|
|
subscriptionId String
|
|
providerPaymentId String?
|
|
status String
|
|
failureCode String?
|
|
failureMessage String?
|
|
attemptedAt DateTime
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([invoiceId])
|
|
@@map("payment_attempts")
|
|
}
|
|
|
|
model BrandSettings {
|
|
id String @id @default(cuid())
|
|
companyId String @unique
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
displayName String
|
|
tagline String?
|
|
logoUrl String?
|
|
faviconUrl String?
|
|
heroImageUrl String?
|
|
primaryColor String @default("#1A56DB")
|
|
accentColor String @default("#F59E0B")
|
|
subdomain String @unique
|
|
customDomain String? @unique
|
|
customDomainVerified Boolean @default(false)
|
|
customDomainAddedAt DateTime?
|
|
publicEmail String?
|
|
publicPhone String?
|
|
publicAddress String?
|
|
publicCity String?
|
|
publicCountry String?
|
|
websiteUrl String?
|
|
whatsappNumber String?
|
|
facebookUrl String?
|
|
instagramUrl String?
|
|
defaultLocale String @default("en")
|
|
defaultCurrency String @default("MAD")
|
|
amanpayMerchantId String?
|
|
amanpaySecretKey String?
|
|
paypalEmail String?
|
|
paypalMerchantId String?
|
|
paymentMethodsEnabled PaymentProvider[]
|
|
isListedOnMarketplace Boolean @default(true)
|
|
marketplaceRating Float?
|
|
homePageConfig Json? @map("home_page_config")
|
|
menuConfig Json? @map("menu_config")
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("brand_settings")
|
|
}
|
|
|
|
model Employee {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
clerkUserId String @unique
|
|
firstName String
|
|
lastName String
|
|
email String
|
|
phone String?
|
|
passwordHash String?
|
|
passwordResetToken String? @unique
|
|
passwordResetExpiresAt DateTime?
|
|
role EmployeeRole @default(AGENT)
|
|
preferredLanguage String @default("en")
|
|
isActive Boolean @default(true)
|
|
|
|
notifications Notification[] @relation("EmployeeNotifications")
|
|
notificationPreferences NotificationPreference[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@map("employees")
|
|
}
|
|
|
|
model Vehicle {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
make String
|
|
model String
|
|
year Int
|
|
color String
|
|
licensePlate String
|
|
vin String?
|
|
category VehicleCategory @default(ECONOMY)
|
|
seats Int @default(5)
|
|
transmission Transmission @default(AUTOMATIC)
|
|
fuelType FuelType @default(GASOLINE)
|
|
features String[]
|
|
dailyRate Int
|
|
status VehicleStatus @default(AVAILABLE)
|
|
photos String[]
|
|
mileage Int?
|
|
notes String?
|
|
isPublished Boolean @default(true)
|
|
pickupLocations String[] @default([])
|
|
allowDifferentDropoff Boolean @default(false)
|
|
dropoffLocations String[] @default([])
|
|
|
|
reservations Reservation[]
|
|
maintenance MaintenanceLog[]
|
|
offerVehicles OfferVehicle[]
|
|
calendarBlocks VehicleCalendarBlock[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([companyId, status])
|
|
@@index([companyId, isPublished])
|
|
@@map("vehicles")
|
|
}
|
|
|
|
model Offer {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
title String
|
|
description String?
|
|
termsAndConds String?
|
|
imageUrl String?
|
|
type OfferType
|
|
discountValue Int
|
|
specialRate Int?
|
|
appliesToAll Boolean @default(true)
|
|
categories VehicleCategory[]
|
|
minRentalDays Int?
|
|
maxRentalDays Int?
|
|
promoCode String? @unique
|
|
maxRedemptions Int?
|
|
redemptionCount Int @default(0)
|
|
validFrom DateTime
|
|
validUntil DateTime
|
|
isActive Boolean @default(true)
|
|
isPublic Boolean @default(true)
|
|
isFeatured Boolean @default(false)
|
|
|
|
vehicles OfferVehicle[]
|
|
reservations Reservation[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([isPublic, isActive, validUntil])
|
|
@@map("offers")
|
|
}
|
|
|
|
model OfferVehicle {
|
|
offerId String
|
|
offer Offer @relation(fields: [offerId], references: [id], onDelete: Cascade)
|
|
vehicleId String
|
|
vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
|
|
|
|
@@id([offerId, vehicleId])
|
|
@@map("offer_vehicles")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// B2C — RENTER SIDE
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model Renter {
|
|
id String @id @default(cuid())
|
|
firstName String
|
|
lastName String
|
|
email String @unique
|
|
phone String?
|
|
passwordHash String
|
|
driverLicense String?
|
|
dateOfBirth DateTime?
|
|
nationality String?
|
|
preferredLocale String @default("en")
|
|
preferredCurrency String @default("MAD")
|
|
fcmToken String?
|
|
emailVerified Boolean @default(false)
|
|
phoneVerified Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
|
|
reservations Reservation[] @relation("RenterReservations")
|
|
savedCompanies RenterSavedCompany[]
|
|
reviews Review[]
|
|
notifications Notification[] @relation("RenterNotifications")
|
|
notificationPreferences NotificationPreference[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("renters")
|
|
}
|
|
|
|
model RenterSavedCompany {
|
|
renterId String
|
|
renter Renter @relation(fields: [renterId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
savedAt DateTime @default(now())
|
|
|
|
@@id([renterId, companyId])
|
|
@@map("renter_saved_companies")
|
|
}
|
|
|
|
model Customer {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
renterId String?
|
|
firstName String
|
|
lastName String
|
|
email String
|
|
phone String?
|
|
driverLicense String?
|
|
dateOfBirth DateTime?
|
|
nationality String?
|
|
address Json?
|
|
notes String?
|
|
flagged Boolean @default(false)
|
|
flagReason String?
|
|
|
|
licenseExpiry DateTime?
|
|
licenseIssuedAt DateTime?
|
|
licenseCountry String?
|
|
licenseImageUrl String?
|
|
licenseNumber String?
|
|
licenseCategory String?
|
|
licenseExpired Boolean @default(false)
|
|
licenseExpiringSoon Boolean @default(false)
|
|
licenseValidationStatus LicenseStatus @default(PENDING)
|
|
licenseApprovedBy String?
|
|
licenseApprovedAt DateTime?
|
|
licenseApprovalNote String?
|
|
|
|
reservations Reservation[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([companyId, email])
|
|
@@index([companyId])
|
|
@@map("customers")
|
|
}
|
|
|
|
model Reservation {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
vehicleId String
|
|
vehicle Vehicle @relation(fields: [vehicleId], references: [id])
|
|
customerId String
|
|
customer Customer @relation(fields: [customerId], references: [id])
|
|
renterId String?
|
|
renter Renter? @relation("RenterReservations", fields: [renterId], references: [id])
|
|
offerId String?
|
|
offer Offer? @relation(fields: [offerId], references: [id])
|
|
promoCodeUsed String?
|
|
vehicleCategory VehicleCategory?
|
|
source BookingSource @default(DASHBOARD)
|
|
marketplaceRef String?
|
|
status ReservationStatus @default(DRAFT)
|
|
startDate DateTime
|
|
endDate DateTime
|
|
pickupLocation String?
|
|
returnLocation String?
|
|
dailyRate Int
|
|
discountAmount Int @default(0)
|
|
totalDays Int
|
|
totalAmount Int
|
|
depositAmount Int @default(0)
|
|
paymentStatus String @default("UNPAID")
|
|
paidAmount Int @default(0)
|
|
checkedInAt DateTime?
|
|
checkedOutAt DateTime?
|
|
checkInMileage Int?
|
|
checkOutMileage Int?
|
|
notes String?
|
|
cancelReason String?
|
|
cancelledBy CancelledBy?
|
|
contractNumber String? @unique
|
|
invoiceNumber String? @unique
|
|
reviewToken String? @unique
|
|
checkInFuelLevel String?
|
|
checkOutFuelLevel String?
|
|
|
|
insurances ReservationInsurance[]
|
|
insuranceTotal Int @default(0)
|
|
additionalDrivers AdditionalDriver[]
|
|
additionalDriverTotal Int @default(0)
|
|
pricingRulesApplied Json?
|
|
pricingRulesTotal Int @default(0)
|
|
damageReports DamageReport[]
|
|
rentalPayments RentalPayment[]
|
|
inspections DamageInspection[]
|
|
review Review?
|
|
damageChargeAmount Int?
|
|
damageChargeNote String?
|
|
extras Json?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([companyId, status])
|
|
@@index([vehicleId, startDate, endDate])
|
|
@@index([renterId])
|
|
@@map("reservations")
|
|
}
|
|
|
|
model RentalPayment {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
reservationId String
|
|
reservation Reservation @relation(fields: [reservationId], references: [id])
|
|
amount Int
|
|
currency String @default("MAD")
|
|
status PaymentStatus @default(PENDING)
|
|
type PaymentType @default(CHARGE)
|
|
paymentProvider PaymentProvider
|
|
amanpayTransactionId String? @unique
|
|
paypalCaptureId String? @unique
|
|
paymentMethod String?
|
|
paidAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([reservationId])
|
|
@@map("rental_payments")
|
|
}
|
|
|
|
model Review {
|
|
id String @id @default(cuid())
|
|
reservationId String @unique
|
|
reservation Reservation @relation(fields: [reservationId], references: [id])
|
|
renterId String?
|
|
renter Renter? @relation(fields: [renterId], references: [id])
|
|
companyId String
|
|
overallRating Int
|
|
vehicleRating Int?
|
|
serviceRating Int?
|
|
comment String?
|
|
isPublished Boolean @default(true)
|
|
companyReply String?
|
|
companyRepliedAt DateTime?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([companyId])
|
|
@@map("reviews")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// NOTIFICATIONS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model Notification {
|
|
id String @id @default(cuid())
|
|
companyId String?
|
|
company Company? @relation("CompanyNotifications", fields: [companyId], references: [id], onDelete: Cascade)
|
|
employeeId String?
|
|
employee Employee? @relation("EmployeeNotifications", fields: [employeeId], references: [id], onDelete: Cascade)
|
|
renterId String?
|
|
renter Renter? @relation("RenterNotifications", fields: [renterId], references: [id], onDelete: Cascade)
|
|
type NotificationType
|
|
title String
|
|
body String
|
|
data Json?
|
|
channel NotificationChannel
|
|
status NotificationStatus @default(PENDING)
|
|
sentAt DateTime?
|
|
failReason String?
|
|
readAt DateTime?
|
|
providerMessageId String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([companyId])
|
|
@@index([renterId])
|
|
@@map("notifications")
|
|
}
|
|
|
|
model NotificationPreference {
|
|
id String @id @default(cuid())
|
|
employeeId String?
|
|
employee Employee? @relation(fields: [employeeId], references: [id], onDelete: Cascade)
|
|
renterId String?
|
|
renter Renter? @relation(fields: [renterId], references: [id], onDelete: Cascade)
|
|
notificationType NotificationType
|
|
channel NotificationChannel
|
|
enabled Boolean @default(true)
|
|
|
|
@@unique([employeeId, notificationType, channel])
|
|
@@unique([renterId, notificationType, channel])
|
|
@@map("notification_preferences")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// MAINTENANCE
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model MaintenanceLog {
|
|
id String @id @default(cuid())
|
|
vehicleId String
|
|
vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
|
|
type String
|
|
description String?
|
|
cost Int?
|
|
mileage Int?
|
|
performedAt DateTime
|
|
nextDueAt DateTime?
|
|
nextDueMileage Int?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([vehicleId])
|
|
@@map("maintenance_logs")
|
|
}
|
|
|
|
model VehicleCalendarBlock {
|
|
id String @id @default(cuid())
|
|
vehicleId String
|
|
vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
|
|
startDate DateTime @db.Date
|
|
endDate DateTime @db.Date
|
|
reason String?
|
|
type CalendarBlockType @default(MANUAL)
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([vehicleId])
|
|
@@index([vehicleId, startDate, endDate])
|
|
@@map("vehicle_calendar_blocks")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// DOCUMENTS — CONTRACT SETTINGS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model ContractSettings {
|
|
id String @id @default(cuid())
|
|
companyId String @unique
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
legalName String?
|
|
registrationNumber String?
|
|
taxId String?
|
|
terms String @default("")
|
|
fuelPolicy String @default("The vehicle must be returned with the same fuel level as at pickup.")
|
|
depositPolicy String @default("The security deposit is refundable within 7 days after return, subject to vehicle inspection.")
|
|
lateFeePolicy String @default("Late returns will incur a charge of 1 additional day rate per hour of delay.")
|
|
damagePolicy String @default("The renter is liable for any damage not covered by insurance.")
|
|
additionalClauses String[] @default([])
|
|
signatureRequired Boolean @default(true)
|
|
contractFooterNote String?
|
|
invoiceFooterNote String?
|
|
showTax Boolean @default(false)
|
|
taxRate Float?
|
|
taxLabel String?
|
|
contractPrefix String @default("CNT")
|
|
invoicePrefix String @default("INV")
|
|
fuelPolicyType FuelPolicyType @default(FULL_TO_FULL)
|
|
fuelPolicyNote String?
|
|
fuelChargePerLiter Int?
|
|
fuelShortfallFee Int?
|
|
lateFeePerHour Int?
|
|
taxLines Json?
|
|
lastContractSeq Int @default(0)
|
|
lastInvoiceSeq Int @default(0)
|
|
additionalDriverCharge AdditionalDriverCharge @default(FREE)
|
|
additionalDriverDailyRate Int @default(0)
|
|
additionalDriverFlatRate Int @default(0)
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("contract_settings")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// INSURANCE
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model InsurancePolicy {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
name String
|
|
description String?
|
|
type InsuranceType
|
|
chargeType InsuranceChargeType
|
|
chargeValue Int
|
|
isRequired Boolean @default(false)
|
|
isActive Boolean @default(true)
|
|
sortOrder Int @default(0)
|
|
|
|
reservations ReservationInsurance[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@index([companyId, isActive])
|
|
@@map("insurance_policies")
|
|
}
|
|
|
|
model ReservationInsurance {
|
|
id String @id @default(cuid())
|
|
reservationId String
|
|
reservation Reservation @relation(fields: [reservationId], references: [id], onDelete: Cascade)
|
|
insurancePolicyId String
|
|
insurancePolicy InsurancePolicy @relation(fields: [insurancePolicyId], references: [id])
|
|
policyName String
|
|
policyType InsuranceType
|
|
chargeType InsuranceChargeType
|
|
chargeValue Int
|
|
totalCharge Int
|
|
|
|
@@unique([reservationId, insurancePolicyId])
|
|
@@map("reservation_insurances")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ADDITIONAL DRIVERS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model AdditionalDriver {
|
|
id String @id @default(cuid())
|
|
reservationId String
|
|
reservation Reservation @relation(fields: [reservationId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
firstName String
|
|
lastName String
|
|
email String?
|
|
phone String?
|
|
driverLicense String
|
|
licenseExpiry DateTime?
|
|
licenseIssuedAt DateTime?
|
|
dateOfBirth DateTime?
|
|
nationality String?
|
|
chargeType AdditionalDriverCharge @default(FREE)
|
|
chargeValue Int @default(0)
|
|
totalCharge Int @default(0)
|
|
licenseExpired Boolean @default(false)
|
|
licenseExpiringSoon Boolean @default(false)
|
|
requiresApproval Boolean @default(false)
|
|
approvedBy String?
|
|
approvedAt DateTime?
|
|
approvalNote String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([reservationId])
|
|
@@index([companyId])
|
|
@@map("additional_drivers")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// DAMAGE REPORTS
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model DamageReport {
|
|
id String @id @default(cuid())
|
|
reservationId String
|
|
reservation Reservation @relation(fields: [reservationId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
type DamageReportType
|
|
damages Json
|
|
photos String[]
|
|
fuelLevel FuelLevel @default(FULL)
|
|
mileage Int?
|
|
inspectedAt DateTime @default(now())
|
|
inspectedBy String?
|
|
customerSignedAt DateTime?
|
|
customerName String?
|
|
|
|
@@unique([reservationId, type])
|
|
@@index([companyId])
|
|
@@map("damage_reports")
|
|
}
|
|
|
|
model DamageInspection {
|
|
id String @id @default(cuid())
|
|
reservationId String
|
|
reservation Reservation @relation(fields: [reservationId], references: [id], onDelete: Cascade)
|
|
companyId String
|
|
type InspectionType
|
|
mileage Int?
|
|
fuelLevel FuelLevel
|
|
fuelCharge Int?
|
|
generalCondition String?
|
|
employeeNotes String?
|
|
customerAgreed Boolean @default(false)
|
|
inspectedAt DateTime @default(now())
|
|
inspectedBy String?
|
|
damagePoints DamagePoint[]
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([reservationId, type])
|
|
@@index([reservationId])
|
|
@@index([companyId])
|
|
@@map("damage_inspections")
|
|
}
|
|
|
|
model DamagePoint {
|
|
id String @id @default(cuid())
|
|
inspectionId String
|
|
inspection DamageInspection @relation(fields: [inspectionId], references: [id], onDelete: Cascade)
|
|
viewType DiagramView
|
|
x Float
|
|
y Float
|
|
damageType DamageType
|
|
severity DamageSeverity @default(MINOR)
|
|
description String?
|
|
isPreExisting Boolean @default(false)
|
|
|
|
@@index([inspectionId])
|
|
@@map("damage_points")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// PRICING RULES
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model PricingRule {
|
|
id String @id @default(cuid())
|
|
companyId String
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
name String
|
|
type PricingRuleType
|
|
condition PricingCondition
|
|
conditionValue Int
|
|
adjustmentType PriceAdjustmentType
|
|
adjustmentValue Int
|
|
isActive Boolean @default(true)
|
|
description String?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([companyId])
|
|
@@map("pricing_rules")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ACCOUNTING
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model AccountingSettings {
|
|
id String @id @default(cuid())
|
|
companyId String @unique
|
|
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
|
|
reportingPeriod ReportingPeriod @default(MONTHLY)
|
|
fiscalYearStart Int @default(1)
|
|
currency String @default("MAD")
|
|
accountantEmail String?
|
|
accountantName String?
|
|
autoSendReport Boolean @default(false)
|
|
reportFormat ReportFormat @default(PDF)
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("accounting_settings")
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════
|
|
// ADMIN PANEL
|
|
// ═══════════════════════════════════════════════════════════════
|
|
|
|
model AdminUser {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
firstName String
|
|
lastName String
|
|
passwordHash String
|
|
role AdminRole @default(SUPPORT)
|
|
isActive Boolean @default(true)
|
|
totpSecret String?
|
|
totpEnabled Boolean @default(false)
|
|
lastLoginAt DateTime?
|
|
lastLoginIp String?
|
|
passwordResetToken String? @unique
|
|
passwordResetExpiresAt DateTime?
|
|
|
|
auditLogs AuditLog[]
|
|
permissions AdminPermission[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("admin_users")
|
|
}
|
|
|
|
model AdminPermission {
|
|
id String @id @default(cuid())
|
|
adminUserId String
|
|
adminUser AdminUser @relation(fields: [adminUserId], references: [id], onDelete: Cascade)
|
|
resource AdminResource
|
|
actions AdminAction[]
|
|
|
|
@@unique([adminUserId, resource])
|
|
@@map("admin_permissions")
|
|
}
|
|
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
adminUserId String
|
|
adminUser AdminUser @relation(fields: [adminUserId], references: [id])
|
|
action String
|
|
resource String
|
|
resourceId String?
|
|
companyId String?
|
|
before Json?
|
|
after Json?
|
|
ipAddress String?
|
|
userAgent String?
|
|
note String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([adminUserId])
|
|
@@index([companyId])
|
|
@@index([action])
|
|
@@map("audit_logs")
|
|
}
|
|
|
|
model PricingConfig {
|
|
id String @id @default(cuid())
|
|
plan String
|
|
billingPeriod String
|
|
amount Int
|
|
|
|
updatedAt DateTime @updatedAt
|
|
updatedBy String?
|
|
|
|
@@unique([plan, billingPeriod])
|
|
@@map("pricing_configs")
|
|
}
|
|
|
|
model PlanFeature {
|
|
id String @id @default(cuid())
|
|
plan Plan
|
|
label String
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([plan, sortOrder])
|
|
@@map("plan_features")
|
|
}
|
|
|
|
model PricingPromotion {
|
|
id String @id @default(cuid())
|
|
code String @unique
|
|
name String
|
|
description String?
|
|
discountType String // 'PERCENTAGE' | 'FIXED'
|
|
discountValue Int // percentage (1-100) or centimes for FIXED
|
|
plans String[] // empty array = all plans
|
|
periods String[] // empty array = all periods
|
|
maxUses Int?
|
|
usedCount Int @default(0)
|
|
validFrom DateTime
|
|
validUntil DateTime?
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
createdBy String?
|
|
|
|
@@index([isActive])
|
|
@@map("pricing_promotions")
|
|
}
|