billing invoice

This commit is contained in:
root
2026-05-25 05:35:55 -04:00
parent 8d0b7a5ceb
commit 33b6bb55f0
12 changed files with 5434 additions and 645 deletions
@@ -0,0 +1,493 @@
CREATE TYPE "BillingInvoiceTerms" AS ENUM (
'DUE_ON_RECEIPT',
'NET_7',
'NET_15',
'NET_30',
'NET_45',
'NET_60'
);
CREATE TYPE "BillingInvoiceStatus" AS ENUM (
'DRAFT',
'OPEN',
'PAID',
'PARTIALLY_PAID',
'PAYMENT_PENDING',
'PAST_DUE',
'VOID',
'UNCOLLECTIBLE',
'REFUNDED',
'PARTIALLY_REFUNDED'
);
CREATE TYPE "BillingInvoiceType" AS ENUM (
'SUBSCRIPTION_INITIAL',
'SUBSCRIPTION_RENEWAL',
'TRIAL_CONVERSION',
'SUBSCRIPTION_UPGRADE',
'SUBSCRIPTION_DOWNGRADE_CREDIT',
'USAGE_BASED',
'ONE_TIME',
'MANUAL',
'CORRECTION',
'CANCELLATION_FEE'
);
CREATE TYPE "BillingLineItemType" AS ENUM (
'SUBSCRIPTION_FEE',
'SEAT_FEE',
'USAGE_FEE',
'SETUP_FEE',
'DISCOUNT',
'TAX',
'CREDIT',
'PRORATION',
'REFUND_ADJUSTMENT',
'MANUAL_ADJUSTMENT',
'PROFESSIONAL_SERVICES',
'CANCELLATION_FEE'
);
CREATE TYPE "BillingPaymentMethodType" AS ENUM (
'CARD',
'ACH_DEBIT',
'BANK_TRANSFER',
'WIRE_TRANSFER',
'MANUAL_INVOICE',
'PURCHASE_ORDER'
);
CREATE TYPE "BillingPaymentIntentStatus" AS ENUM (
'REQUIRES_PAYMENT_METHOD',
'REQUIRES_CONFIRMATION',
'REQUIRES_ACTION',
'PROCESSING',
'SUCCEEDED',
'FAILED',
'CANCELED',
'REFUNDED',
'PARTIALLY_REFUNDED'
);
CREATE TYPE "BillingPaymentAttemptStatus" AS ENUM (
'PENDING',
'PROCESSING',
'SUCCEEDED',
'FAILED',
'CANCELED',
'REFUNDED',
'PARTIALLY_REFUNDED'
);
CREATE TYPE "BillingRefundStatus" AS ENUM (
'PENDING',
'SUCCEEDED',
'FAILED'
);
CREATE TYPE "BillingCreditNoteStatus" AS ENUM (
'ISSUED',
'APPLIED',
'VOID'
);
CREATE SEQUENCE "billing_invoice_sequence_seq" START 1;
CREATE TABLE "billing_accounts" (
"id" TEXT NOT NULL,
"companyId" TEXT NOT NULL,
"isPrimary" BOOLEAN NOT NULL DEFAULT true,
"legalName" TEXT NOT NULL,
"billingEmail" TEXT NOT NULL,
"billingAddress" JSONB,
"taxId" TEXT,
"taxExempt" BOOLEAN NOT NULL DEFAULT false,
"defaultCurrency" TEXT NOT NULL DEFAULT 'MAD',
"defaultPaymentMethodId" TEXT,
"invoiceTerms" "BillingInvoiceTerms" NOT NULL DEFAULT 'DUE_ON_RECEIPT',
"netTermsDays" INTEGER NOT NULL DEFAULT 0,
"providerCustomerId" TEXT,
"dunningPaused" BOOLEAN NOT NULL DEFAULT false,
"dunningPausedAt" TIMESTAMP(3),
"dunningPausedBy" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_accounts_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_payment_methods" (
"id" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"type" "BillingPaymentMethodType" NOT NULL,
"providerPaymentMethodId" TEXT,
"label" TEXT,
"brand" TEXT,
"last4" TEXT,
"expMonth" INTEGER,
"expYear" INTEGER,
"isDefault" BOOLEAN NOT NULL DEFAULT false,
"isActive" BOOLEAN NOT NULL DEFAULT true,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_payment_methods_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_invoices" (
"id" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"companyId" TEXT NOT NULL,
"subscriptionId" TEXT,
"invoiceNumber" TEXT,
"invoiceSequence" INTEGER,
"invoiceType" "BillingInvoiceType" NOT NULL,
"status" "BillingInvoiceStatus" NOT NULL DEFAULT 'DRAFT',
"currency" TEXT NOT NULL DEFAULT 'MAD',
"subtotalAmount" INTEGER NOT NULL DEFAULT 0,
"discountAmount" INTEGER NOT NULL DEFAULT 0,
"creditAmount" INTEGER NOT NULL DEFAULT 0,
"taxAmount" INTEGER NOT NULL DEFAULT 0,
"totalAmount" INTEGER NOT NULL DEFAULT 0,
"amountPaid" INTEGER NOT NULL DEFAULT 0,
"amountDue" INTEGER NOT NULL DEFAULT 0,
"invoiceDate" TIMESTAMP(3),
"dueAt" TIMESTAMP(3),
"finalizedAt" TIMESTAMP(3),
"paidAt" TIMESTAMP(3),
"voidedAt" TIMESTAMP(3),
"markedUncollectibleAt" TIMESTAMP(3),
"billingName" TEXT,
"billingEmail" TEXT,
"billingAddress" JSONB,
"providerInvoiceId" TEXT,
"paymentProvider" "PaymentProvider",
"isSubscriptionBlocking" BOOLEAN NOT NULL DEFAULT false,
"adminReason" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdByAdminId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_invoices_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_invoice_line_items" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"subscriptionId" TEXT,
"plan" "Plan",
"type" "BillingLineItemType" NOT NULL,
"description" TEXT NOT NULL,
"quantity" INTEGER NOT NULL DEFAULT 1,
"unitAmount" INTEGER NOT NULL,
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"periodStart" TIMESTAMP(3),
"periodEnd" TIMESTAMP(3),
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_invoice_line_items_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_payment_intents" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"paymentMethodId" TEXT,
"providerPaymentIntentId" TEXT,
"status" "BillingPaymentIntentStatus" NOT NULL DEFAULT 'REQUIRES_PAYMENT_METHOD',
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_payment_intents_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_payment_attempts" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"paymentIntentId" TEXT,
"paymentMethodId" TEXT,
"providerPaymentId" TEXT,
"status" "BillingPaymentAttemptStatus" NOT NULL,
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"failureCode" TEXT,
"failureMessage" TEXT,
"attemptedAt" TIMESTAMP(3) NOT NULL,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_payment_attempts_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_credit_balances" (
"id" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"balanceAmount" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_credit_balances_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_credit_ledger_entries" (
"id" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"invoiceId" TEXT,
"type" TEXT NOT NULL,
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"reason" TEXT NOT NULL,
"createdBy" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_credit_ledger_entries_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_credit_notes" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"billingAccountId" TEXT NOT NULL,
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"reason" TEXT NOT NULL,
"status" "BillingCreditNoteStatus" NOT NULL DEFAULT 'ISSUED',
"createdBy" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_credit_notes_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_refunds" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"paymentAttemptId" TEXT,
"billingAccountId" TEXT NOT NULL,
"amount" INTEGER NOT NULL,
"currency" TEXT NOT NULL DEFAULT 'MAD',
"reason" TEXT NOT NULL,
"status" "BillingRefundStatus" NOT NULL DEFAULT 'PENDING',
"providerRefundId" TEXT,
"createdBy" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_refunds_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_tax_records" (
"id" TEXT NOT NULL,
"invoiceId" TEXT NOT NULL,
"jurisdiction" TEXT,
"taxRate" DOUBLE PRECISION,
"taxAmount" INTEGER NOT NULL,
"taxType" TEXT,
"taxExempt" BOOLEAN NOT NULL DEFAULT false,
"exemptionReason" TEXT,
"providerTaxId" TEXT,
"metadata" JSONB NOT NULL DEFAULT '{}',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_tax_records_pkey" PRIMARY KEY ("id")
);
CREATE TABLE "billing_events" (
"id" TEXT NOT NULL,
"billingAccountId" TEXT,
"invoiceId" TEXT,
"subscriptionId" TEXT,
"companyId" TEXT,
"eventType" TEXT NOT NULL,
"source" TEXT NOT NULL,
"payload" JSONB NOT NULL DEFAULT '{}',
"occurredAt" TIMESTAMP(3) NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "billing_events_pkey" PRIMARY KEY ("id")
);
ALTER TABLE "subscription_invoices"
ADD COLUMN "billingInvoiceId" TEXT;
CREATE UNIQUE INDEX "subscription_invoices_billingInvoiceId_key" ON "subscription_invoices"("billingInvoiceId");
CREATE UNIQUE INDEX "billing_invoices_invoiceNumber_key" ON "billing_invoices"("invoiceNumber");
CREATE UNIQUE INDEX "billing_invoices_invoiceSequence_key" ON "billing_invoices"("invoiceSequence");
CREATE UNIQUE INDEX "billing_credit_balances_billingAccountId_currency_key" ON "billing_credit_balances"("billingAccountId", "currency");
CREATE INDEX "billing_accounts_companyId_idx" ON "billing_accounts"("companyId");
CREATE INDEX "billing_accounts_companyId_isPrimary_idx" ON "billing_accounts"("companyId", "isPrimary");
CREATE INDEX "billing_payment_methods_billingAccountId_idx" ON "billing_payment_methods"("billingAccountId");
CREATE INDEX "billing_invoices_billingAccountId_idx" ON "billing_invoices"("billingAccountId");
CREATE INDEX "billing_invoices_companyId_idx" ON "billing_invoices"("companyId");
CREATE INDEX "billing_invoices_subscriptionId_idx" ON "billing_invoices"("subscriptionId");
CREATE INDEX "billing_invoice_line_items_invoiceId_idx" ON "billing_invoice_line_items"("invoiceId");
CREATE INDEX "billing_payment_intents_invoiceId_idx" ON "billing_payment_intents"("invoiceId");
CREATE INDEX "billing_payment_intents_billingAccountId_idx" ON "billing_payment_intents"("billingAccountId");
CREATE INDEX "billing_payment_attempts_invoiceId_idx" ON "billing_payment_attempts"("invoiceId");
CREATE INDEX "billing_payment_attempts_billingAccountId_idx" ON "billing_payment_attempts"("billingAccountId");
CREATE INDEX "billing_credit_ledger_entries_billingAccountId_idx" ON "billing_credit_ledger_entries"("billingAccountId");
CREATE INDEX "billing_credit_notes_invoiceId_idx" ON "billing_credit_notes"("invoiceId");
CREATE INDEX "billing_credit_notes_billingAccountId_idx" ON "billing_credit_notes"("billingAccountId");
CREATE INDEX "billing_refunds_invoiceId_idx" ON "billing_refunds"("invoiceId");
CREATE INDEX "billing_refunds_billingAccountId_idx" ON "billing_refunds"("billingAccountId");
CREATE INDEX "billing_tax_records_invoiceId_idx" ON "billing_tax_records"("invoiceId");
CREATE INDEX "billing_events_billingAccountId_idx" ON "billing_events"("billingAccountId");
CREATE INDEX "billing_events_invoiceId_idx" ON "billing_events"("invoiceId");
CREATE INDEX "billing_events_subscriptionId_idx" ON "billing_events"("subscriptionId");
CREATE INDEX "billing_events_companyId_idx" ON "billing_events"("companyId");
ALTER TABLE "billing_accounts"
ADD CONSTRAINT "billing_accounts_companyId_fkey"
FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_methods"
ADD CONSTRAINT "billing_payment_methods_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_accounts"
ADD CONSTRAINT "billing_accounts_defaultPaymentMethodId_fkey"
FOREIGN KEY ("defaultPaymentMethodId") REFERENCES "billing_payment_methods"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_invoices"
ADD CONSTRAINT "billing_invoices_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_invoices"
ADD CONSTRAINT "billing_invoices_companyId_fkey"
FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_invoices"
ADD CONSTRAINT "billing_invoices_subscriptionId_fkey"
FOREIGN KEY ("subscriptionId") REFERENCES "subscriptions"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "subscription_invoices"
ADD CONSTRAINT "subscription_invoices_billingInvoiceId_fkey"
FOREIGN KEY ("billingInvoiceId") REFERENCES "billing_invoices"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_invoice_line_items"
ADD CONSTRAINT "billing_invoice_line_items_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_intents"
ADD CONSTRAINT "billing_payment_intents_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_intents"
ADD CONSTRAINT "billing_payment_intents_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_intents"
ADD CONSTRAINT "billing_payment_intents_paymentMethodId_fkey"
FOREIGN KEY ("paymentMethodId") REFERENCES "billing_payment_methods"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_payment_attempts"
ADD CONSTRAINT "billing_payment_attempts_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_attempts"
ADD CONSTRAINT "billing_payment_attempts_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_payment_attempts"
ADD CONSTRAINT "billing_payment_attempts_paymentIntentId_fkey"
FOREIGN KEY ("paymentIntentId") REFERENCES "billing_payment_intents"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_payment_attempts"
ADD CONSTRAINT "billing_payment_attempts_paymentMethodId_fkey"
FOREIGN KEY ("paymentMethodId") REFERENCES "billing_payment_methods"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_credit_balances"
ADD CONSTRAINT "billing_credit_balances_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_credit_ledger_entries"
ADD CONSTRAINT "billing_credit_ledger_entries_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_credit_ledger_entries"
ADD CONSTRAINT "billing_credit_ledger_entries_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_credit_notes"
ADD CONSTRAINT "billing_credit_notes_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_credit_notes"
ADD CONSTRAINT "billing_credit_notes_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_refunds"
ADD CONSTRAINT "billing_refunds_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_refunds"
ADD CONSTRAINT "billing_refunds_paymentAttemptId_fkey"
FOREIGN KEY ("paymentAttemptId") REFERENCES "billing_payment_attempts"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_refunds"
ADD CONSTRAINT "billing_refunds_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_tax_records"
ADD CONSTRAINT "billing_tax_records_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE "billing_events"
ADD CONSTRAINT "billing_events_billingAccountId_fkey"
FOREIGN KEY ("billingAccountId") REFERENCES "billing_accounts"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_events"
ADD CONSTRAINT "billing_events_invoiceId_fkey"
FOREIGN KEY ("invoiceId") REFERENCES "billing_invoices"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_events"
ADD CONSTRAINT "billing_events_subscriptionId_fkey"
FOREIGN KEY ("subscriptionId") REFERENCES "subscriptions"("id") ON DELETE SET NULL ON UPDATE CASCADE;
ALTER TABLE "billing_events"
ADD CONSTRAINT "billing_events_companyId_fkey"
FOREIGN KEY ("companyId") REFERENCES "companies"("id") ON DELETE SET NULL ON UPDATE CASCADE;
INSERT INTO "billing_accounts" (
"id",
"companyId",
"isPrimary",
"legalName",
"billingEmail",
"billingAddress",
"taxExempt",
"defaultCurrency",
"invoiceTerms",
"netTermsDays",
"metadata"
)
SELECT
'ba_' || c."id",
c."id",
true,
c."name",
c."email",
c."address",
false,
COALESCE(a."currency", 'MAD'),
'DUE_ON_RECEIPT'::"BillingInvoiceTerms",
0,
'{}'::jsonb
FROM "companies" c
LEFT JOIN "accounting_settings" a ON a."companyId" = c."id"
WHERE NOT EXISTS (
SELECT 1
FROM "billing_accounts" ba
WHERE ba."companyId" = c."id" AND ba."isPrimary" = true
);
+613 -205
View File
@@ -52,6 +52,99 @@ enum InvoiceStatus {
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
@@ -340,54 +433,59 @@ model Company {
subscriptionPaymentRef String?
apiKey String @unique @default(cuid())
subscription Subscription?
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")
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
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[]
events SubscriptionEvent[]
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
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
BillingEvent BillingEvent[]
@@map("subscriptions")
}
@@ -421,6 +519,8 @@ model SubscriptionInvoice {
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?
@@ -433,6 +533,314 @@ model SubscriptionInvoice {
@@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
@@ -450,19 +858,19 @@ model PaymentAttempt {
}
model BrandSettings {
id String @id @default(cuid())
companyId String @unique
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
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)
primaryColor String @default("#1A56DB")
accentColor String @default("#F59E0B")
subdomain String @unique
customDomain String? @unique
customDomainVerified Boolean @default(false)
customDomainAddedAt DateTime?
publicEmail String?
publicPhone String?
@@ -473,17 +881,17 @@ model BrandSettings {
whatsappNumber String?
facebookUrl String?
instagramUrl String?
defaultLocale String @default("en")
defaultCurrency String @default("MAD")
defaultLocale String @default("en")
defaultCurrency String @default("MAD")
amanpayMerchantId String?
amanpaySecretKey String?
paypalEmail String?
paypalMerchantId String?
paymentMethodsEnabled PaymentProvider[]
isListedOnMarketplace Boolean @default(true)
isListedOnMarketplace Boolean @default(true)
marketplaceRating Float?
homePageConfig Json? @map("home_page_config")
menuConfig Json? @map("menu_config")
homePageConfig Json? @map("home_page_config")
menuConfig Json? @map("menu_config")
updatedAt DateTime @updatedAt
@@ -491,20 +899,20 @@ model BrandSettings {
}
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)
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[]
@@ -517,34 +925,34 @@ model Employee {
}
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)
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[]
reservations Reservation[]
maintenance MaintenanceLog[]
offerVehicles OfferVehicle[]
calendarBlocks VehicleCalendarBlock[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -556,28 +964,28 @@ model Vehicle {
}
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)
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[]
@@ -621,10 +1029,10 @@ model Renter {
phoneVerified Boolean @default(false)
isActive Boolean @default(true)
reservations Reservation[] @relation("RenterReservations")
reservations Reservation[] @relation("RenterReservations")
savedCompanies RenterSavedCompany[]
reviews Review[]
notifications Notification[] @relation("RenterNotifications")
notifications Notification[] @relation("RenterNotifications")
notificationPreferences NotificationPreference[]
createdAt DateTime @default(now())
@@ -635,7 +1043,7 @@ model Renter {
model RenterSavedCompany {
renterId String
renter Renter @relation(fields: [renterId], references: [id], onDelete: Cascade)
renter Renter @relation(fields: [renterId], references: [id], onDelete: Cascade)
companyId String
savedAt DateTime @default(now())
@@ -684,52 +1092,52 @@ model Customer {
}
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
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)
insuranceTotal Int @default(0)
additionalDrivers AdditionalDriver[]
additionalDriverTotal Int @default(0)
additionalDriverTotal Int @default(0)
pricingRulesApplied Json?
pricingRulesTotal Int @default(0)
pricingRulesTotal Int @default(0)
damageReports DamageReport[]
rentalPayments RentalPayment[]
inspections DamageInspection[]
@@ -843,9 +1251,9 @@ model NotificationPreference {
// ═══════════════════════════════════════════════════════════════
model MaintenanceLog {
id String @id @default(cuid())
id String @id @default(cuid())
vehicleId String
vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
vehicle Vehicle @relation(fields: [vehicleId], references: [id], onDelete: Cascade)
type String
description String?
cost Int?
@@ -882,37 +1290,37 @@ model VehicleCalendarBlock {
// ═══════════════════════════════════════════════════════════════
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)
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
@@ -1046,16 +1454,16 @@ model DamageInspection {
}
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)
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")
@@ -1168,7 +1576,7 @@ model AuditLog {
}
model PricingConfig {
id String @id @default(cuid())
id String @id @default(cuid())
plan String
billingPeriod String
amount Int
@@ -1197,10 +1605,10 @@ model PricingPromotion {
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
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