Skip to content

feat(invoices): per-line-item KDV rates with mixed-rate support#4

Open
AltanEsmer wants to merge 1 commit into
mainfrom
feat/invoice-line-items-multi-vat
Open

feat(invoices): per-line-item KDV rates with mixed-rate support#4
AltanEsmer wants to merge 1 commit into
mainfrom
feat/invoice-line-items-multi-vat

Conversation

@AltanEsmer

Copy link
Copy Markdown
Owner

Summary

  • Adds line_items[] to the Invoice schema so a single invoice can carry products with different KDV rates (e.g. %10 and %16 on the same invoice — a Turkish tax requirement).
  • Invoice-level subtotal / vat_amount / total become cached aggregates, always recomputed server-side from line_items. Invoice-level vat_rate is the single shared rate or null when mixed ("Karışık").
  • New editable line-items table in the invoice form; manual total override retained only for single-line invoices.
  • Invoice list shows a Karışık tag with a tooltip listing the distinct rates, and rows expand to reveal the per-line breakdown (with TRY equivalents for foreign-currency invoices).
  • Excel export now includes a second Kalemler sheet with one row per line item; the main Faturalar sheet writes Karışık in the KDV Oranı column for mixed-rate invoices.
  • Backward-compatible: an idempotent migration in loadData() synthesizes a single line from the existing flat fields for every legacy invoice on first load.

Files touched

  • database.js — new _computeInvoiceTotals helper, line-items migration, payload normalization in addInvoice / updateInvoice, per-line TRY equivalents in _computeTryEquivalent, dashboard aggregation uses the cached vat_amount, updated sample seed.
  • src/components/InvoiceFormLineItems.jsx (new) — editable line-items table with per-line chip-based KDV selector.
  • src/components/InvoiceFormMoneyZone.jsx — trimmed to currency + manual-total switch + total display + FX reveal.
  • src/pages/InvoiceForm.js — drives lineItems state, disables manual total for multi-line invoices.
  • src/components/InvoiceTable.jsxKarışık tag in the KDV column, expandable rows showing line items.
  • src/pages/InvoiceList.js — builds the second-sheet lineItems payload; main sheet tolerates the Karışık sentinel.
  • main.jsexport-to-excel handler optionally writes the Kalemler sheet and writes non-numeric KDV cells as text.
  • src/index.css — styles for the line-items table and summary strip.
  • docs/DATA-MODEL.md — documents the new line_items field and adds a mixed-rate invoice example.

Test plan

  • npm run dev — launch app, verify legacy invoices auto-migrated (no console errors, expanded row shows a single auto-generated line)
  • Add a TRY invoice with two lines at %10 and %16 — list shows Karışık tag with tooltip; expanded row shows both lines; aggregates correct
  • Edit a legacy invoice — single line prefilled, save round-trips with identical totals
  • Add a USD invoice with two mixed-rate lines + an existing FX rate for that month — expanded row shows per-line TRY equivalents
  • Edit the FX rate — confirm invoice-level and per-line TRY values both update
  • Single-line invoice with manual total override — value persists; toggling to multi-line disables the override
  • Export to Excel — Faturalar sheet shows Karışık in KDV Oranı for mixed rows; Kalemler sheet lists one row per line with line totals
  • Dashboard VAT-by-month unchanged for legacy data; new mixed invoice contributes its full vat_amount

🤖 Generated with Claude Code

Invoices can now hold multiple products each with its own KDV rate
(e.g. one line at %10 and another at %16 in the same invoice). Invoice-level
subtotal/vat_amount/total are kept as cached aggregates and always
recomputed server-side from line_items; vat_rate is the shared rate when
all lines agree, or null when mixed ("Karışık").

- database.js: new _computeInvoiceTotals helper, idempotent migration that
  synthesizes a single line for legacy records, validation and mutators
  always normalize line_items and recompute aggregates, _computeTryEquivalent
  now emits per-line TRY equivalents
- InvoiceForm.js + new InvoiceFormLineItems.jsx: editable line-items table
  with chip-based per-line KDV selector; manual total override kept only
  for single-line invoices to preserve the sum-of-lines invariant
- InvoiceFormMoneyZone.jsx: trimmed to currency selector, manual total
  toggle, total display, and FX reveal
- InvoiceTable.jsx: "Karışık" tag + tooltip in KDV column, expandable rows
  showing the per-line breakdown with TRY equivalents
- InvoiceList.js Excel export builds a flat lineItems array for a second
  "Kalemler" sheet; KDV Oranı column tolerates the "Karışık" string
- main.js export-to-excel handler optionally writes the "Kalemler" sheet
  and writes mixed-rate KDV cells as text instead of percent
- docs/DATA-MODEL.md updated with line_items schema and mixed-rate example

Legacy invoices auto-migrate on first load to a single line carrying the
existing rate; aggregate fields preserved so Dashboard / reports keep
working unchanged.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant