feat(efectivo): the EFE cash receipt book, folio and posting in one step
The office still issues cash receipts from Access (EFE MENU -> EFE). This is that form: cliente, fecha, monto + moneda, concepto, elaboró (the logged-in user), fecha de depósito, and a folio that continues the legacy book. - cash_receipts, folio unique. Next folio = one past the highest of the platform's receipts and the imported utilities EFECTIVO journal, so after the cutover import it lands on the office's next number (13935 on prod today). A typed folio the legacy book already used is refused. - Issuing a receipt posts its credit in the same database transaction, as legacy posted to DATOS2: reference C<folio>, CASH DEPOSIT, pseudo check CASH<MMDD><P|D>. Dollars with a rate credit a pesos ledger (1,500 USD at 16.80 -> 25,200 MXN, as C13830 did). Voiding that row voids the receipt. - /efectivo: issue, search, record the deposit date; /efectivo/<folio> prints the receipt. - Reporte de efectivo now lists platform receipts by receipt, not by check, so each is counted once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fd5df240bc
commit
ca76f4d57a
14 files changed
+959
-3
No files matched your search
@@ -0,0 +1,33 @@
|
||||
-- EFE cash receipt book (2026-10-08 meeting). Each receipt posts its own ledger
|
||||
-- credit, reference C<folio>, in the same database transaction.
|
||||
-- CreateTable
|
||||
CREATE TABLE `cash_receipts` (
|
||||
`id` VARCHAR(191) NOT NULL,
|
||||
`folio` INTEGER NOT NULL,
|
||||
`customerId` VARCHAR(191) NOT NULL,
|
||||
`receivedAt` DATETIME(3) NOT NULL,
|
||||
`amount` DECIMAL(12, 2) NOT NULL,
|
||||
`currency` ENUM('USD', 'MXN') NOT NULL,
|
||||
`exchangeRate` DECIMAL(10, 4) NULL,
|
||||
`concept` TEXT NOT NULL,
|
||||
`preparedById` VARCHAR(191) NOT NULL,
|
||||
`depositedAt` DATETIME(3) NULL,
|
||||
`transactionId` VARCHAR(191) NOT NULL,
|
||||
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
|
||||
UNIQUE INDEX `cash_receipts_folio_key`(`folio`),
|
||||
UNIQUE INDEX `cash_receipts_transactionId_key`(`transactionId`),
|
||||
INDEX `cash_receipts_customerId_idx`(`customerId`),
|
||||
INDEX `cash_receipts_receivedAt_idx`(`receivedAt`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `cash_receipts` ADD CONSTRAINT `cash_receipts_customerId_fkey` FOREIGN KEY (`customerId`) REFERENCES `customers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `cash_receipts` ADD CONSTRAINT `cash_receipts_preparedById_fkey` FOREIGN KEY (`preparedById`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `cash_receipts` ADD CONSTRAINT `cash_receipts_transactionId_fkey` FOREIGN KEY (`transactionId`) REFERENCES `transactions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
@@ -131,6 +131,7 @@ model Customer {
|
||||
|
||||
statementDocuments StatementDocument[]
|
||||
statementSplits StatementDocumentSplit[]
|
||||
cashReceipts CashReceipt[]
|
||||
policyOcrDocuments PolicyOcrDocument[] @relation("PolicyOcrDocumentCustomer")
|
||||
|
||||
emailNotificationLogs EmailNotificationLog[]
|
||||
@@ -884,6 +885,7 @@ model Transaction {
|
||||
/// Set only on OCR-posted rows — the statement page this came from.
|
||||
statementDocument StatementDocument?
|
||||
statementSplit StatementDocumentSplit? @relation("StatementDocumentSplitTransaction")
|
||||
cashReceipt CashReceipt?
|
||||
policyOcrDocument PolicyOcrDocument? @relation("PolicyOcrDocumentTransaction")
|
||||
|
||||
@@unique([legacySourceDb, legacySourceTable, legacyId])
|
||||
@@ -1005,6 +1007,7 @@ model User {
|
||||
|
||||
statementBatches StatementBatch[] @relation("StatementBatchUploader")
|
||||
statementsReviewed StatementDocument[] @relation("StatementDocumentReviewer")
|
||||
cashReceipts CashReceipt[] @relation("CashReceiptPreparer")
|
||||
|
||||
policyOcrBatches PolicyOcrBatch[] @relation("PolicyOcrBatchUploader")
|
||||
policyOcrReviewed PolicyOcrDocument[] @relation("PolicyOcrDocumentReviewer")
|
||||
@@ -1287,3 +1290,35 @@ model AppSetting {
|
||||
|
||||
@@map("app_settings")
|
||||
}
|
||||
|
||||
/// The EFE cash receipt book (legacy EFE form / EFECTIVO table): the paper the
|
||||
/// office hands a customer who pays in cash. A journal, not a ledger — the
|
||||
/// money reaches the customer's balance through `transaction`, posted with it
|
||||
/// as `C<folio>` exactly as legacy posted to DATOS2. Voiding that row voids
|
||||
/// the receipt.
|
||||
model CashReceipt {
|
||||
id String @id @default(uuid())
|
||||
/// Printed receipt number. Continues the legacy book's sequence.
|
||||
folio Int @unique
|
||||
customerId String
|
||||
customer Customer @relation(fields: [customerId], references: [id])
|
||||
receivedAt DateTime
|
||||
amount Decimal @db.Decimal(12, 2)
|
||||
currency Currency
|
||||
/// Set when dollars are credited to a pesos ledger, as legacy did; the
|
||||
/// posted row then carries amount × rate in MXN.
|
||||
exchangeRate Decimal? @db.Decimal(10, 4)
|
||||
concept String @db.Text
|
||||
/// ELABORÓ — whoever was logged in.
|
||||
preparedById String
|
||||
preparedBy User @relation("CashReceiptPreparer", fields: [preparedById], references: [id])
|
||||
/// FECHA DEPÓSITO — filled in when the cash reaches the bank.
|
||||
depositedAt DateTime?
|
||||
transactionId String @unique
|
||||
transaction Transaction @relation(fields: [transactionId], references: [id])
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([customerId])
|
||||
@@index([receivedAt])
|
||||
@@map("cash_receipts")
|
||||
}
|
||||
Reference in new issue
Block a user