Phase 03: Operational Modules - 5 plans in 3 waves - Wave 1: 03-01 (zones), 03-03 (tickets) — parallel - Wave 2: 03-02 (collector collections), 03-04 (job orders) — parallel - Wave 3: 03-05 (technician compensation) - Ready for execution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
16 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 03-operational-modules | 02 | execute | 2 |
|
|
true |
|
Purpose: This is the core cash flow tracking for field operations — collectors log what they receive, management verifies what they remit, and every peso is traceable through the double-entry ledger. Output: Collection/Remittance models, 3 service files, 6 API routes, integration tests.
<execution_context> @C:\Users\KevinAsprec.claude/get-shit-done/workflows/execute-plan.md @C:\Users\KevinAsprec.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/03-operational-modules/03-CONTEXT.md @.planning/phases/03-operational-modules/03-RESEARCH.md @.planning/phases/03-operational-modules/03-01-SUMMARY.md @prisma/schema.prisma @src/lib/prisma-tenant.ts @src/lib/accounting/chart-of-accounts.ts @src/lib/accounting/journal-entry-service.ts @src/lib/services/payment-service.ts (FIFO pattern reference — adapt for 1030 account) @src/lib/services/zone-service.ts (zone scoping reference) @src/lib/__tests__/payment.test.ts (test pattern reference) Task 1: Collection/Remittance schema, 1030 account, migration, tenant scoping prisma/schema.prisma src/lib/prisma-tenant.ts src/lib/accounting/chart-of-accounts.ts 1. Add 1030 Cash in Transit to ISP_CHART_OF_ACCOUNTS in chart-of-accounts.ts: ``` { code: "1030", name: "Cash in Transit", accountType: "ASSET", normalBalance: "DEBIT", parentCode: "1000" } ``` Insert AFTER 1020 Cash in Bank and BEFORE 1100 Accounts Receivable to maintain code order.-
Add enums to schema.prisma:
enum CollectionStatus { COMPLETED VOIDED }enum RemittanceStatus { PENDING VERIFIED }
-
Add Collection model:
- id (uuid), tenantId
- collectorId (String, FK to User — the collector who made the collection)
- subscriberId (String, FK to Subscriber)
- amount (Decimal @db.Decimal(10,2)) — lump sum received from subscriber
- collectionDate (DateTime) — when collected in the field
- status (CollectionStatus, default COMPLETED)
- notes (String?)
- journalEntryId (String?) — JE created on collection (DR 1030, CR 1100)
- voidedAt (DateTime?), voidedById (String?), voidJournalEntryId (String?)
- createdAt, updatedAt
- Relations: collector -> User, subscriber -> Subscriber
- Add PaymentAllocation relation: collectionAllocations PaymentAllocation[] (reuse PaymentAllocation or create CollectionAllocation — prefer creating CollectionAllocation to avoid polluting PaymentAllocation with nullable fields)
- Actually, create CollectionAllocation as a separate model (same structure as PaymentAllocation but for collections): id, tenantId, collectionId, invoiceId, amount, createdAt, @@index([collectionId]), @@index([invoiceId]), @@index([tenantId])
- @@unique([tenantId, collectorId, subscriberId, collectionDate]) — prevent double-recording same subscriber same day same collector
- @@index([tenantId]), @@index([tenantId, collectorId]), @@index([tenantId, collectionDate])
-
Add Remittance model:
- id (uuid), tenantId
- collectorId (String, FK to User)
- remittanceDate (DateTime) — the date of remittance
- collectedTotal (Decimal @db.Decimal(10,2)) — sum of collector's collections for the period (derived at creation time, stored for audit trail)
- verifiedTotal (Decimal? @db.Decimal(10,2)) — amount counted by office staff (null until verified)
- variance (Decimal? @db.Decimal(10,2)) — collectedTotal - verifiedTotal (null until verified)
- status (RemittanceStatus, default PENDING)
- verifiedById (String?, FK to User)
- verifiedAt (DateTime?)
- journalEntryId (String?) — JE created on verification (DR 1010, CR 1030)
- notes (String?)
- createdAt, updatedAt
- Relations: collector -> User, verifiedBy -> User
- @@index([tenantId]), @@index([tenantId, collectorId]), @@index([tenantId, remittanceDate])
-
Add reverse relations on User:
collections Collection[],verifiedRemittances Remittance[]Add reverse relation on Subscriber:collections Collection[] -
Run
npx prisma migrate dev --name add-collections-remittances -
Add Collection, CollectionAllocation, and Remittance to TENANT_SCOPED_MODELS in prisma-tenant.ts with FULL 12-operation extension blocks.
npx prisma migrate devsucceedsnpx tsc --noEmitpasses- Grep chart-of-accounts.ts confirms "1030" exists
- Grep prisma-tenant.ts confirms "collection", "collectionAllocation", "remittance" in TENANT_SCOPED_MODELS Collection, CollectionAllocation, and Remittance models exist, 1030 Cash in Transit added to COA, migration applied, tenant scoping configured.
-
Create src/lib/services/remittance-service.ts:
createRemittance(tenantPrisma, tenantId, { collectorId, remittanceDate }):- Calculate collectedTotal: sum of all COMPLETED collections by this collector for this date (or unremitted collections if date-based grouping is complex — use all COMPLETED collections by collector where no remittance has been created yet). Simpler approach: sum COMPLETED collections by collectorId where collectionDate = remittanceDate.
- Create Remittance with status PENDING, collectedTotal set.
verifyRemittance(tenantPrisma, tenantId, { remittanceId, verifiedTotal, verifiedById, notes? }):- Load remittance, validate status is PENDING
- Calculate variance: collectedTotal - verifiedTotal (positive = collector short, negative = collector over)
- Create JE via JournalEntryService.createEntry: DR 1010 Cash on Hand (verifiedTotal), CR 1030 Cash in Transit (verifiedTotal). Note: JE is for verified amount, NOT collected total. Variance does NOT block.
- Update remittance: verifiedTotal, variance, verifiedById, verifiedAt, journalEntryId, status = VERIFIED
listRemittances(tenantPrisma, { collectorId?, status?, dateFrom?, dateTo? })— filtered list
-
Create src/lib/services/collection-report-service.ts:
getDailyCollectionSummary(tenantPrisma, { date, collectorId? }):- For each collector active on the given date:
- collectedTotal: sum of COMPLETED collections on that date
- remittedTotal: sum of VERIFIED remittance verifiedTotal on that date
- variance: collectedTotal - remittedTotal
- collectionCount: count of collections
- Return array of { collectorId, collectorName, collectedTotal, remittedTotal, variance, collectionCount }
- For each collector active on the given date:
getCollectorCollectionDetail(tenantPrisma, { collectorId, date }):- Per-subscriber breakdown for drill-down: subscriber name, amount, collection time
-
Create API routes:
- POST /api/collections: withPermission("create", "Payment") -> recordCollection (collectors have "create" Payment permission)
- GET /api/collections: withPermission("read", "Payment") -> getCollectionHistory with query param filters
- GET /api/collections/[id]: withPermission("read", "Payment") -> single collection detail
- POST /api/collections/[id]/void: withPermission("manage", "Payment") -> voidCollection (admin/staff only)
- POST /api/remittances: withPermission("manage", "Payment") -> createRemittance (staff initiates)
- POST /api/remittances/[id]/verify: withPermission("manage", "Payment") -> verifyRemittance (staff verifies)
- GET /api/reports/collections: withPermission("read", "Report") -> getDailyCollectionSummary with date query param
-
Create src/lib/tests/collector-service.test.ts:
- Setup: create tenant (seeds COA including 1030 now), admin user, collector user, create 2 zones, assign collector to zone 1, create service plan, create 2 subscribers in zone 1, create 1 subscriber in zone 2, generate invoices for subscribers
- Test: recordCollection succeeds for subscriber in collector's zone
- Test: recordCollection FIFO allocates to oldest invoice first
- Test: recordCollection throws for subscriber NOT in collector's zones
- Test: collection creates JE with DR 1030, CR 1100 (verify journal entry lines)
- Test: overpayment adds to subscriber.creditBalance
- Test: voidCollection reverses JE and invoice allocations
- Test: cross-tenant isolation
- Cleanup: collectionAllocations -> collections -> invoiceLines -> invoices -> journalEntryLines -> null reversesEntryId -> journalEntries -> zoneAssignments -> subscribers -> servicePlans -> zones -> tenantSettings -> accountingPeriods -> accounts -> ticketCategories -> users -> tenant
-
Create src/lib/tests/remittance-service.test.ts:
- Setup: reuse similar setup, record some collections first
- Test: createRemittance calculates correct collectedTotal
- Test: verifyRemittance with matching amount (zero variance)
- Test: verifyRemittance with different amount (non-zero variance, still completes)
- Test: verification creates JE with DR 1010, CR 1030 for verifiedTotal
- Test: cannot verify already-verified remittance
- Cleanup: remittances -> collectionAllocations -> collections -> (same chain as above)
npx vitest run src/lib/__tests__/collector-service.test.ts— all tests passnpx vitest run src/lib/__tests__/remittance-service.test.ts— all tests passnpx tsc --noEmitpasses Collectors can record zone-scoped collections with FIFO allocation, collections create correct JEs (DR 1030 CR 1100), remittance verification creates correct JEs (DR 1010 CR 1030), variance recorded but non-blocking, daily summary report works, all tests pass.
<success_criteria>
- Collection model with FIFO allocation (same pattern as PaymentService but with 1030)
- Zone enforcement on collections (collector can only collect from their zones)
- Remittance two-party verification (collector collects, staff counts and verifies)
- Correct accounting chain: Collection DR 1030/CR 1100, Remittance DR 1010/CR 1030
- Variance recorded but non-blocking
- Daily collection summary report with per-collector totals
- Collector balances derived (no stored balance field)
- All integration tests pass </success_criteria>