From 15e4738dd407f7508a333abc749eed1cc4e519fb Mon Sep 17 00:00:00 2001 From: DeepnaPooja Date: Fri, 23 Oct 2026 14:53:31 +0530 Subject: [PATCH] feat: Add Day End Report service and repository registration --- Distribution/Program.cs | 2 + Distribution/docs/day_end_sales.md | 133 +++++++++++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 Distribution/docs/day_end_sales.md diff --git a/Distribution/Program.cs b/Distribution/Program.cs index 3dff0fb..e41dd92 100644 --- a/Distribution/Program.cs +++ b/Distribution/Program.cs @@ -85,6 +85,8 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/Distribution/docs/day_end_sales.md b/Distribution/docs/day_end_sales.md new file mode 100644 index 0000000..478d6fb --- /dev/null +++ b/Distribution/docs/day_end_sales.md @@ -0,0 +1,133 @@ +# Day-End Sales Report — Plan (Distribution ERP) + +A per-day view of sales, collections by method, returns, expenses and the resulting income, with a +day-wise chart and a PDF export. Read-only: it adds no tables and changes no existing models. + +> Modelled on the Day-End report in the other HexDrive ERP, but adapted to this project's data. +> The big difference: **there is no cash/card split here.** `PaymentMethod` is `Cash | Cheque | Credit`, +> so the report splits collections by those three. + +--- + +## 1. What the report shows (one selected day) + +| Group | Figures | +|---|---| +| Sales | Invoiced total (finalized invoices that day), Collected, Due | +| Collections by method | Cash, Cheque, Credit (credit = extended to the store, not money received) | +| Counts | Invoices count, payments count, count by method | +| Returns | Total credit amount of sale returns that day (`SaleReturn.TotalCreditAmount`) | +| Expenses | Total + list of that day's expenses | +| Result | **Income of the day** | +| Secondary | Cash in hand movement: cash collected − cash expenses paid | + +Plus: +- Day-wise income **chart** over a date range (Sales / Expenses / Income). +- Day-wise table with a totals row. +- **PDF export** (single day, and day-wise range). + +--- + +## 2. What already exists (reused, nothing new in the DB) + +| Need | Source | +|---|---| +| Sales | `Invoice` — `Status = Finalized`, `FinalizedAt`, `TotalAmount`, `IsActive`, excluding `ShopPO.Status = Cancelled` | +| Collections | `Payment` — `Amount`, `Method`, `CollectedAt`, `FK_BankAccountId` | +| Returns | `SaleReturn` — `TotalCreditAmount` (ItemExchange is 0), `CreatedAt` | +| Expenses | `Expense` — `Amount`, `BillDate`, `PaidAt`, `Status` (`Draft/Posted/Paid/Void`), `Method` | +| Region scope | `Invoice → ShopPO → Store → Route.FK_RegionId` (same filter `PaymentReport` uses) | +| Backend pattern | `Features/PaymentReport/*` (controller + service + repository + DTOs) | +| Frontend | `lib/api/reports.ts`, `config/nav.ts`, `recharts`, `jspdf` + `jspdf-autotable` (all already installed) | + +--- + +## 3. Backend — new `Features/DayEndReport/` + +Same shape as `PaymentReport`: + +- `DayEndReportController.cs` +- `DayEndReportService.cs` +- `IDayEndReportRepository.cs` / `DayEndReportRepository.cs` +- `DayEndReportDTOs.cs` +- Register repo + service in `Program.cs` next to the `PaymentReport` lines. + +### 3.1 `GET /api/reports/day-end?date=YYYY-MM-DD®ionId=` + +Response (one day): + +| Section | Fields | +|---|---| +| Sales | `TotalSales`, `Collected`, `Due` | +| By method | `Cash`, `Cheque`, `Credit` (amount + count each) | +| Counts | `InvoiceCount`, `PaymentCount` | +| Returns | `SalesReturns` | +| Expenses | `ExpenseTotal`, `Expenses[]` (doc no, category, title, payee, method, amount) | +| Income | `Income = TotalSales − SalesReturns − ExpenseTotal` | +| Cash in hand | `CashCollected`, `CashExpensesPaid`, `NetCash` | + +### 3.2 `GET /api/reports/day-end/daily?from=&to=®ionId=` + +One row per day: `Date, TotalSales, Collected, Due, Cash, Cheque, Credit, Returns, Expenses, Income` +plus a totals row. Feeds the chart, the table and the PDF. + +- Days with no activity are returned as zeros. +- Range capped at 92 days (matches `PaymentReport`'s daily granularity; error message in the same style). + +### 3.3 Rules (need confirming — see §6) + +- **Sales** = finalized invoices by `FinalizedAt`, active, order not cancelled. +- **Collected** = payments by `CollectedAt` (includes instalments against older invoices). +- **Due** = that day's invoiced total − payments received **on the same invoices** that day? or running balance? → decision #2. +- **Expenses** = `Posted` and `Paid` expenses, `Void` and `Draft` excluded. Dated by `BillDate`. +- **Region filter** optional; unset = all regions. +- **Day boundaries**: use the same local-date handling `PaymentReport` uses (`DateTime.Now.Date`, `[day, day+1)`), so numbers agree with the Payment Analytics page. +- Permission: a `reports.day-end` view permission, seeded like the other permissions (to confirm the existing seeding pattern when implementing). + +--- + +## 4. Frontend — `/reports/day-end` + +- API: add `dayEnd` calls + types to `lib/api/reports.ts`. +- Page `app/(dashboard)/reports/day-end/page.tsx`: + - Toolbar: date picker (default today), region select, **Download PDF**. + - Summary cards: Total Sales · Collected · Due · Cash · Cheque · Credit · Returns · Expenses · **Income** (green/red by sign). + - Expenses table for the selected day. + - Chart: from/to (default last 30 days), Sales / Expenses / Income lines (`recharts`), daily table below. +- Nav: add "Day-End Sales" entry in `config/nav.ts` (Reports group), gated by the permission. + +## 5. PDF export + +- `lib/pdf/day-end-report-pdf.ts` using `jspdf` + `jspdf-autotable`. +- Page 1: header (company, region, range, generated at), period totals, chart image. +- Following pages: day-wise table with totals row. +- Single-day variant: summary figures + expense list. + +--- + +## 6. Decisions I need from you + +| # | Question | My default | +|---|---|---| +| 1 | **Income basis.** Accrual (sales − returns − expenses dated that day) or cash basis (money collected − expenses paid that day)? | Accrual; cash shown as secondary `NetCash`. | +| 2 | **"Due" meaning.** Unpaid part of that day's invoices, or the running outstanding balance? | Unpaid part of that day's invoices. | +| 3 | **Credit method.** Count `Credit` payments as collected? | No — shown separately, not in "Collected" (same as Payment Analytics). | +| 4 | **Card.** You asked for cash vs card in the other project; here only Cash/Cheque/Credit exist. Add a Card method (schema change + UI) or just report what exists? | Report what exists; no schema change. | +| 5 | **Expense date.** `BillDate` or `PaidAt`? | `BillDate`. | + +## 7. Verification + +- Backend tests (in `Distribution.Tests`): mixed methods, partial payments, cancelled order excluded, void/draft expense excluded, instalment on an older invoice, day-boundary case, empty days. +- Cross-check: the "Collected" total for a range equals Payment Analytics' collected for the same range. +- Frontend: cards match the daily table; PDF paginates over a 92-day range. + +--- + +## 8. Implemented (2026-10-23) — differences from the plan + +Built with all five recommended defaults. + +- **No region filter and no new permission.** Expenses are attributed to a warehouse, not a region, so a region filter would make income inconsistent. The endpoints follow `PaymentReport` (any authenticated user); the nav entry reuses `warehouses.view` like the other reports. +- **Endpoints:** `GET /api/reports/day-end?date=` and `GET /api/reports/day-end/daily?from=&to=`. +- **PDF:** reuses `exportPdf` from `lib/export.ts` (day-wise table with totals row). No chart image in the PDF. +- **Tests:** `Distribution.Tests/Services/DayEndReportServiceTests.cs` (12 passing). The older test files in that project (`OrderServiceTests`, `StoreServiceTests`, `AuthServiceTests`, `ItemServiceTests`, `RouteServiceTests`, `RegionServiceTests`) no longer compile, so the project can't build until they are fixed. Not touched here.