feat(02-04): Invoice model, BillingService, InvoiceService, CreditService
- Add InvoiceStatus enum + Invoice + InvoiceLine models to schema - Add Invoice relation to Subscriber model - Add invoice/invoiceLine to TENANT_SCOPED_MODELS in prisma-tenant.ts - Add invoice/invoiceLine tenant-scoped query extensions to withTenantContext() - Run migration: 20260304152900_add_invoice_model - Create invoice-service.ts: generateInvoiceNumber, getInvoice, listInvoices, updateInvoiceStatus, markOverdueInvoices, voidInvoice (with JE reversal) - Create credit-service.ts: applyCredit() — DR Subscriber Credits (1150), CR AR (1100) - Create billing-service.ts: generateInvoiceForSubscriber (idempotent, JE + auto-credit), generateMonthlyInvoices (postpaid + prepaid timing with lead days)
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InvoiceStatus" AS ENUM ('DRAFT', 'SENT', 'PARTIAL', 'PAID', 'OVERDUE', 'VOID');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Invoice" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenantId" TEXT NOT NULL,
|
||||
"invoiceNumber" TEXT NOT NULL,
|
||||
"subscriberId" TEXT NOT NULL,
|
||||
"periodStart" TIMESTAMP(3) NOT NULL,
|
||||
"periodEnd" TIMESTAMP(3) NOT NULL,
|
||||
"dueDate" TIMESTAMP(3) NOT NULL,
|
||||
"subtotal" DECIMAL(10,2) NOT NULL,
|
||||
"totalAmount" DECIMAL(10,2) NOT NULL,
|
||||
"amountPaid" DECIMAL(10,2) NOT NULL DEFAULT 0,
|
||||
"status" "InvoiceStatus" NOT NULL DEFAULT 'DRAFT',
|
||||
"journalEntryId" TEXT,
|
||||
"issuedAt" TIMESTAMP(3),
|
||||
"paidAt" TIMESTAMP(3),
|
||||
"voidedAt" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Invoice_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "InvoiceLine" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenantId" TEXT NOT NULL,
|
||||
"invoiceId" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"unitPrice" DECIMAL(10,2) NOT NULL,
|
||||
"lineTotal" DECIMAL(10,2) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "InvoiceLine_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_tenantId_idx" ON "Invoice"("tenantId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_tenantId_status_idx" ON "Invoice"("tenantId", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_tenantId_subscriberId_idx" ON "Invoice"("tenantId", "subscriberId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Invoice_tenantId_dueDate_idx" ON "Invoice"("tenantId", "dueDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Invoice_tenantId_invoiceNumber_key" ON "Invoice"("tenantId", "invoiceNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Invoice_tenantId_subscriberId_periodStart_key" ON "Invoice"("tenantId", "subscriberId", "periodStart");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceLine_invoiceId_idx" ON "InvoiceLine"("invoiceId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "InvoiceLine_tenantId_idx" ON "InvoiceLine"("tenantId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Invoice" ADD CONSTRAINT "Invoice_subscriberId_fkey" FOREIGN KEY ("subscriberId") REFERENCES "Subscriber"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "InvoiceLine" ADD CONSTRAINT "InvoiceLine_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
Reference in New Issue
Block a user