Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/architecture/regional-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Backend consumers of `resolveRegionalSnapshot()`:
| `main/services/cash-close-export.ts` | Regional currency, locale, timezone, and formatting preferences when serializing X and Z report HTML without pre-resolved options. |
| `main/services/refund.ts` | Refund minor units and the business timezone used for the refund window. |
| `main/services/daily-sales-export.ts` | Currency minor-unit factor for the accounting export, and regional locale and formatting preferences for `serializeDailySalesExportHtml`. |
| `main/services/daily-invoices-export.ts` | Regional locale and formatting preferences for `buildDailyInvoicesExportDataset` and `serializeDailyInvoicesExportHtml`. |
| `main/services/expenses.ts` | Store currency and business timezone for expense business-date resolution. |
| `main/services/whatsapp.ts` | Store regional snapshot for WhatsApp message formatting. |
| `main/routes/menu-csv.ts` | Amount formatting and separators for menu and add-on CSV export. |
Expand Down
37 changes: 33 additions & 4 deletions docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@ day-boundary rules.
| `GET` | `/z-report/export` | `reports.view` (`ROLE_ACCESS.ownerManager` by default) | query: `?date`, `?format` (required: `csv`, `xlsx`, or `html`) | Exports the stored Z-report snapshot for a closed business date (or print-styled HTML for PDF/browser print when `format=html`). Returns `400` with `{ error: "format must be xlsx, csv, or html" }` when `format` is missing or invalid, and `404` with `{ error: "Day not closed" }` when the day has not been closed. Sets `Content-Disposition` to `attachment; filename="z-report-Z<z_number>-<date>.<format>"`. |
| `POST` | `/cash-closes/:id/whatsapp` | `reports.view` + `whatsapp.use` | path: `id`; body: `phone_e164`, `body` (non-empty, max 4096 chars) | Sends the submitted report body and returns `{ success: true, messageId }`; when WhatsApp is disconnected, returns `{ fallback: true, reason: "not_connected" }` so the client can open WhatsApp for sharing. Invalid input returns `400`; an unknown day close returns `404`. |
| `GET` | `/daily-sales/export` | `reports.daily-sales.export` (owner by default) | query: `?date`, `?from`, `?to`, `?format`, `?part` | See [GET `/api/reports/daily-sales/export`](#get-apireportsdaily-salesexport). |
| `GET` | `/daily-invoices/export` | `reports.daily-sales.export` (owner by default) | query: `?date`, `?from`, `?to`, `?format` | See [GET `/api/reports/daily-invoices/export`](#get-apireportsdaily-invoicesexport). |
| `GET` | `/customer-sales/export` | `reports.customer-sales.export` (owner by default) | query: `?start_date`, `?end_date`, `?format` | One row per item sold with customer details, for a business-date range of at most 366 days. `format` is `xlsx` or `csv`; invalid format, reversed range, or oversized range returns `400`. See [customer sales export](daily-sales-export.md#customer-sales-export). |

### GET `/api/reports/daily-sales/export`
Expand Down Expand Up @@ -895,6 +896,34 @@ reconciliation contract, the summary metric field order, and the worksheet/CSV c

Errors: `400` for an invalid `format`, a CSV without `part`, mixed `date` and `from`/`to` arguments, an incomplete range, an invalid calendar date, `to < from`, a range exceeding 93 days, or an `html` export exceeding the 15 MB PDF size limit; `401` unauthenticated; `403` non-owner; `409` for a concurrent-write conflict; `500` otherwise.

### GET `/api/reports/daily-invoices/export`

Compiled daily invoices export (`reports.daily-sales.export`, owner by default) for one tenant
business date (`?date=YYYY-MM-DD`, defaults to the current business date) or an inclusive
business-date range (`?from=YYYY-MM-DD&to=YYYY-MM-DD`, up to 366 calendar days). Returns a
print-styled A4 portrait HTML document (`format=html`, default when omitted) formatted with the
store's regional locale and preferences (`resolveRegionalSnapshot`), used by `exportReportAsPdf` for
desktop PDF export (`invoices-YYYY-MM-DD.pdf` or `invoices-YYYY-MM-DD_to_YYYY-MM-DD.pdf`) and
browser print fallback.

Page 1 renders a bounded fiscal summary cover page (store legal name, tax registration ID with the
active country tax pack's `registrationNumberLabel` or country profile `taxIdLabel`, address,
business date/range, timezone, business-day start, currency, total invoices count, gross sales, net
base, tax collected, in-period refunds, net revenue, the VAT/tax summary table by rate, refund scope
reconciliation across in-period, prior-bill, outside-period, and lifetime totals, and summary
reconciliation metrics) reused from `buildDailySalesExportDataset` (see
[daily sales export](daily-sales-export.md)). When the window has issued invoices, page 2+ renders
all bills paid in the business-day window (`payment_status IN ('paid', 'partially_refunded',
'refunded')`) ordered by ascending business date and numeric `bill_number` sequence (`paid_at`,
`id`, and `bill_number` tie-breakers), with `page-break-inside: avoid; break-inside: avoid;` on each
`.invoice-card`, `[PAID]`, `[PARTIALLY REFUNDED]`, and `[REFUNDED]` status badges, non-excluded line
items (unit price, pre-tax subtotal, and after-tax total), tax components, payment details, and
`[In Period]` / `[Outside Period]` refund details. A trailing page-broken appendix renders the
per-day tax breakdown table and any prior-period invoices refunded during the selected period.

- Returns `200` with `Content-Type: text/html; charset=utf-8` and `Content-Disposition: attachment; filename="invoices-YYYY-MM-DD.html"` (or `invoices-YYYY-MM-DD_to_YYYY-MM-DD.html`).
- Errors: `400` for an unsupported `format`, mixed `date` and `from`/`to` arguments, an incomplete or reversed range, an invalid calendar date, a range exceeding 366 days, more than 5,000 matching invoices (`MAX_DAILY_INVOICES_COUNT`), or an HTML export exceeding the 15 MB PDF size limit; `401` unauthenticated; `403` when lacking `reports.daily-sales.export`; `409` for unconfigured regional settings or a concurrent-write conflict; `500` otherwise.

### Inline endpoints (registered outside a router)

These seven are declared on `app` inside `registerRoutes` in `main/routes/index.ts`, not on a
Expand Down Expand Up @@ -1169,17 +1198,17 @@ documents only the two routes.

## Coverage

This page lists 310 HTTP route registrations across 309 distinct rows, and one WebSocket contract:
This page lists 311 HTTP route registrations across 310 distinct rows, and one WebSocket contract:

- `281` on the main API: 273 router registrations, 7 inline registrations in `main/routes/index.ts`,
- `282` on the main API: 274 router registrations, 7 inline registrations in `main/routes/index.ts`,
and `GET /api/health` in `main/server.ts`.
- `8` REST routes on the KDS server, plus 3 static handlers.
- `21` route registrations on the Server App, of which 13 forward to the main API. Two of those 21
are mutually exclusive `GET /` handlers under one path, which is why 21 registrations render as 20
rows.

Every one of the 309 rows is listed with its method, path, authorization gate, and the parameters
its handler reads. The **Response** column carries a note for 173 of them: 145 main-API endpoints,
Every one of the 310 rows is listed with its method, path, authorization gate, and the parameters
its handler reads. The **Response** column carries a note for 174 of them: 146 main-API endpoints,
all 8 KDS-server routes, and the 20 Server App routes. The remaining 146 main-API endpoints are
listed with method, path, gate, and parameters only, and this page asserts nothing about what they
return. Those rows are complete as a route inventory and silent as a contract; the handler in
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/app/(dashboard)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,36 @@ export default function DashboardPage() {
}
};

const exportDailyInvoices = async () => {
if (isExporting) return;
setIsExporting(true);
try {
const dateParams =
periodMode === 'day'
? { date: selectedDate }
: { from: range.startDate, to: range.endDate };
const span =
periodMode === 'day' || range.startDate === range.endDate
? range.startDate
: `${range.startDate}_to_${range.endDate}`;

await exportReportAsPdf({
endpoint: '/reports/daily-invoices/export',
params: dateParams,
filename: `invoices-${span}.pdf`,
pageSize: 'A4',
});
} catch (error) {
toast.error(
error instanceof MenuPopupBlockedError
? tProducts('menuPopupBlocked')
: tCommon('downloadFailed'),
);
} finally {
setIsExporting(false);
}
};

const exportCustomerSales = async (format: 'xlsx' | 'csv') => {
if (isExporting) return;
setIsExporting(true);
Expand Down Expand Up @@ -900,6 +930,10 @@ export default function DashboardPage() {
<FileText size={14} />
{t('exportPdf')}
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => exportDailyInvoices()}>
<FileText size={14} />
{t('exportInvoicesPdf')}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuLabel>{t('exportCustomerSales')}</DropdownMenuLabel>
<DropdownMenuItem onSelect={() => exportCustomerSales('xlsx')}>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "إكسل (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "الفواتير (PDF)",
"exportCsvHint": "يتم تنزيل خمسة ملفات بتنسيق CSV: «الملخص» و«اليومي» و«الضرائب» و«العناصر» و«المدفوعات».",
"exportCsvStarted": "جاري تنزيل ملفات CSV الخاصة بالملخص واليومي والضرائب والعناصر والمدفوعات…",
"exportCustomerSales": "مبيعات العملاء",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/bn.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "এক্সেল (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "ইনভয়েস (PDF)",
"exportCsvHint": "CSV পাঁচটি ফাইল ডাউনলোড করে: সারাংশ, দৈনিক, কর, আইটেম এবং পেমেন্ট।",
"exportCsvStarted": "সারাংশ, দৈনিক, কর, আইটেম এবং পেমেন্ট CSV ফাইল ডাউনলোড করা হচ্ছে...",
"exportCustomerSales": "গ্রাহক বিক্রয়",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Rechnungen (PDF)",
"exportCsvHint": "Der CSV-Download enthält fünf Dateien: Übersicht, Täglich, Steuern, Artikel und Zahlungen.",
"exportCsvStarted": "Übersichts-, Tages-, Steuer-, Artikel- und Zahlungs-CSV-Dateien werden heruntergeladen…",
"exportCustomerSales": "Kundenumsätze",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Invoices (PDF)",
"exportCsvHint": "CSV downloads five files: summary, daily, taxes, items and payments.",
"exportCsvStarted": "Downloading summary, daily, taxes, items and payments CSV files…",
"exportCustomerSales": "Customer sales",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Facturas (PDF)",
"exportCsvHint": "El CSV descarga cinco archivos: resumen, diario, impuestos, artículos y pagos.",
"exportCsvStarted": "Descargando archivos CSV de resumen, diario, impuestos, artículos y pagos…",
"exportCustomerSales": "Ventas por cliente",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/fa.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "اکسل (.xlsx)",
"exportCsv": "CSV",
"exportPdf": "PDF",
"exportInvoicesPdf": "فاکتورها (PDF)",
"exportCsvHint": "CSV پنج فایل دانلود می‌کند: خلاصه، روزانه، مالیات‌ها، اقلام و پرداخت‌ها.",
"exportCsvStarted": "در حال دانلود فایل‌های CSV خلاصه، روزانه، مالیات‌ها، اقلام و پرداخت‌ها…",
"exportCustomerSales": "فروش مشتریان",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/fil.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Mga Invoice (PDF)",
"exportCsvHint": "Ang CSV ay magda-download ng limang file: summary, daily, taxes, items at payments.",
"exportCsvStarted": "Dina-download ang summary, daily, taxes, items at payments na CSV…",
"exportCustomerSales": "Benta ng customer",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Factures (PDF)",
"exportCsvHint": "Le CSV télécharge cinq fichiers : résumé, quotidien, taxes, articles et paiements.",
"exportCsvStarted": "Téléchargement des fichiers CSV résumé, quotidien, taxes, articles et paiements…",
"exportCustomerSales": "Ventes par client",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "चालान (PDF)",
"exportCsvHint": "सीएसवी पाँच फ़ाइलें डाउनलोड करता है: सारांश, दैनिक, कर, आइटम और भुगतान।",
"exportCsvStarted": "सारांश, दैनिक, कर, आइटम और भुगतान CSV फ़ाइलें डाउनलोड हो रही हैं…",
"exportCustomerSales": "ग्राहक बिक्री",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Faktur (PDF)",
"exportCsvHint": "CSV mengunduh lima berkas: ringkasan, harian, pajak, item, dan pembayaran.",
"exportCsvStarted": "Mengunduh berkas CSV ringkasan, harian, pajak, item, dan pembayaran…",
"exportCustomerSales": "Penjualan pelanggan",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Fatture (PDF)",
"exportCsvHint": "Il CSV scarica cinque file: riepilogo, giornaliero, imposte, articoli e pagamenti.",
"exportCsvStarted": "Download dei file CSV di riepilogo, giornaliero, imposte, articoli e pagamenti in corso…",
"exportCustomerSales": "Vendite per cliente",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@
"exportXlsx": "Excel(.xlsx)",
"exportCsv": "CSV(.csv)",
"exportPdf": "PDF(.pdf)",
"exportInvoicesPdf": "請求書(PDF)",
"exportCsvHint": "CSVでは概要、日次、税金、明細、支払いの5つのファイルをダウンロードします。",
"exportCsvStarted": "概要、日次、税金、明細、支払いのCSVファイルをダウンロードしています…",
"exportCustomerSales": "顧客別売上",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "청구서 (PDF)",
"exportCsvHint": "CSV는 요약, 일별, 세금, 항목, 결제 다섯 파일을 다운로드합니다.",
"exportCsvStarted": "요약, 일별, 세금, 항목 및 결제 CSV 파일을 다운로드하는 중…",
"exportCustomerSales": "고객별 매출",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/ne.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "एक्सेल (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "बीजकहरू (PDF)",
"exportCsvHint": "CSV ले पाँच फाइलहरू डाउनलोड गर्छ: सारांश, दैनिक, करहरू, वस्तुहरू र भुक्तानीहरू।",
"exportCsvStarted": "सारांश, दैनिक, करहरू, वस्तुहरू र भुक्तानीहरू CSV फाइलहरू डाउनलोड गर्दै...",
"exportCustomerSales": "ग्राहक बिक्री",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Facturen (PDF)",
"exportCsvHint": "CSV downloadt vijf bestanden: samenvatting, dagelijks, belastingen, artikelen en betalingen.",
"exportCsvStarted": "Samenvatting, dagelijks, belastingen, artikelen en betalingen CSV-bestanden downloaden…",
"exportCustomerSales": "Klantverkoop",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Faturas (PDF)",
"exportCsvHint": "O CSV baixa cinco arquivos: resumo, diário, impostos, itens e pagamentos.",
"exportCsvStarted": "Baixando arquivos CSV de resumo, diário, impostos, itens e pagamentos…",
"exportCustomerSales": "Vendas por cliente",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Счета (PDF)",
"exportCsvHint": "CSV загружает пять файлов: сводку, по дням, налоги, позиции и платежи.",
"exportCsvStarted": "Загрузка CSV-файлов сводки, по дням, налогов, позиций и платежей…",
"exportCustomerSales": "Продажи по клиентам",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/sq.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "Faturat (PDF)",
"exportCsvHint": "Shkarkimi CSV jep pesë skedarë: përmbledhjen, ditoren, taksat, artikujt dhe pagesat.",
"exportCsvStarted": "Po shkarkohen skedarët CSV të përmbledhjes, ditores, taksave, artikujve dhe pagesave...",
"exportCustomerSales": "Shitjet sipas klientit",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/i18n/messages/th.json
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@
"exportXlsx": "Excel (.xlsx)",
"exportCsv": "CSV (.csv)",
"exportPdf": "PDF (.pdf)",
"exportInvoicesPdf": "ใบแจ้งหนี้ (PDF)",
"exportCsvHint": "CSV จะดาวน์โหลด 5 ไฟล์: สรุป รายวัน ภาษี รายการสินค้า และการชำระเงิน",
"exportCsvStarted": "กำลังดาวน์โหลดไฟล์ CSV สรุป รายวัน ภาษี รายการสินค้า และการชำระเงิน…",
"exportCustomerSales": "ยอดขายตามลูกค้า",
Expand Down
Loading
Loading