Commit Graph

5 Commits

Author SHA1 Message Date
BOHA
40a859f5e1 feat(invoices)!: Obsah sections, internal-only notes, unified per-page PDF header+footer
Invoices now mirror the issued-orders document model:

- New invoice_sections table (CZ/EN rich-text "Obsah") edited via the
  shared SectionsEditor, printed inline right after the items on the
  PDF. Full-replace on update, same transaction as items.
- Printed notes dropped: the notes column is removed (migration merges
  existing content into internal_notes first); the form field is now
  "Interni poznamky", never printed. Legacy payloads sending notes are
  silently stripped.
- Form cleanup: Cislo faktury and Vystavil fields removed (number lives
  in the header, issued_by auto-fills); page header title restyled to
  the orders/offers pattern (number span + status chip).
- Unified per-page PDF header for the red-accent family: shared
  buildPdfHeaderTemplate in pdf-shared (22mm logo, red heading, red
  rule) rendered by a Puppeteer headerTemplate on EVERY page of both
  invoices and issued orders (incl. the /file fallback render); body
  headers are print-hidden. htmlToPdf gained the headerTemplate option.
- Footer parity: invoices get the per-page "Vystavil + Strana X z Y"
  footer; the invoice bottom block (notice + QR/VAT recap + Prevzal)
  is break-inside: avoid so a page break can never split it.
- @page margins now match the template space (32mm top, 18mm bottom) -
  Chromium lays out by CSS @page margins, which also fixes issued
  orders' content running into the 18mm footer zone on full pages.

BREAKING CHANGE: invoices.notes column dropped (data merged into
internal_notes); deploy must run prisma migrate deploy + generate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 19:02:37 +02:00
BOHA
975a555af5 fix(dates): @db.Date filters built from local midnight queried the wrong day
Prisma truncates a JS Date used in a WHERE filter on a @db.Date column to
its UTC date part. Under TZ=Europe/Prague a local-midnight boundary
(new Date(y,m,d) = 22:00/23:00Z of the previous day) therefore filtered as
the PREVIOUS calendar date. Same class as the dashboard fix; full sweep of
every @db.Date filter in the codebase. New shared helper
utcMidnightOfLocalDay() in src/utils/date.ts.

Fixed (all previously off by one day):
- attendance.service: getStatus today+month windows; getWorkfund (last day
  of each month was double-counted across months); getPrintData (monthly
  print included prev month's last day); listAttendance (admin month view
  included prev month's last day AND dropped the selected month's last
  day); createAttendance duplicate/overlap validation (checked only the
  PREVIOUS day - same-day duplicates were never caught, neighbors falsely
  rejected)
- invoice-alerts: the 'splatnost za 3 dny' advance alert had NEVER fired
  (due==today+3 was outside the fetched window); window computation
  extracted as computeAlertWindow() + pure tests
- invoices.service: month list/totals filter dropped invoices issued on the
  month's last day; getInvoiceStats month/year bounds; markOverdueInvoices
  boundary; auto paid_date could store yesterday during 00:00-02:00
- received-invoices auto paid_date, issued-orders default order_date: same
  night-window write hazard, now via the helper
- attendance.schema: shift_date hardened to isoDateString (bare YYYY-MM-DD)

+9 regression tests (month boundaries, same-day duplicate, last-day-of-month
invoice in list+totals, alert window).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:29:28 +02:00
BOHA
1826fc7976 fix: audit fix pass #1 — all 19 verified HIGH findings + critical dep cleanup
Fixes every CRITICAL/HIGH finding from the 2026-06-09 full-codebase audit
(REVIEW_FINDINGS.md); each fix went through independent spec + code-quality
review. Plan and per-task log: docs/superpowers/plans/2026-06-10-audit-high-fix-pass.md

- attendance: schemas accept the combined local datetimes the forms/service
  use (new dateTimeString helpers in schemas/common.ts), breaks persist on
  create, AttendanceCreate submit rebuilt — every submit 400'd since 519edce
- 2fa: backup codes wired to /totp/backup-verify (+ remember-me parity),
  enrollment QR generated locally via qrcode (CSP-blocked external service
  also leaked the secret), dashboard shows per-user enrollment, not policy
- invoices/orders: per-line VAT survives re-saves (numberOr 0-respecting
  coercion in formatters.ts), billing_text persists on update, issued-order
  status transitions update UI gates
- trips: real pagination on all 3 pages, GET /trips/stats server aggregate
  (shared buildTripsWhere + legacy distance coalesce), vehicle_id applies on
  PUT with both-vehicle odometer recompute, print rebuilt (sync window.open,
  escaped template, server totals)
- orders api: attachment_data PDF blob excluded from all non-binary reads
- warehouse: unit field is a Select over UnitEnum, receipt attachments
  downloadable via new authenticated GET route
- downloads: shared RFC 5987 contentDisposition helper — Czech filenames no
  longer 500 (warehouse, received-invoices, orders endpoints)
- misc: block-env hook actually blocks (exit 2 + stderr), project create
  works with empty dates, NaN filter guards on trips endpoints
- deps: remove unused concurrently (clears both critical advisories), pin
  @hono/node-server >=1.19.13 via overrides (clears the 3 moderates without
  the Prisma 6 downgrade), drop deprecated @types stubs

Gates: tsc -b clean - vitest 30 files / 342 tests (31 new) - eslint 0 errors
- build OK

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:59:47 +02:00
BOHA
519edce373 fix: 2026-06-09 full-codebase audit hardening
Validation: shared NaN-guarded Zod coercion helpers in schemas/common.ts replace
the raw number|string transform idiom across every schema (the root-cause NaN bug
class); emailOrEmpty + lenient isoDateString/timeString.

Security: roles privilege-escalation closed; refresh-token family revocation on
reuse; TOTP uses config params; read endpoints permission-guarded; received-invoices
gross VAT on all paths; orders-pdf custom-items authz.

Concurrency: $queryRaw SELECT...FOR UPDATE locks in ascending-id order (warehouse
confirm/cancel, attendance lockUserRow); uniqueness checks moved into create
transactions (TOCTOU -> 409); deterministic id tiebreak on second-precision
timestamp ordering (plan resolveCell/resolveGrid, warehouse FIFO).

Frontend: Rules-of-Hooks fixed across ~14 pages + PlanCellModal; UTC-date persisted
fields; dashboard invalidation gaps; stale-closure confirm bugs.

Tooling/tests: ESLint flat config (react-hooks/rules-of-hooks = error) + Prettier;
tsconfig.test.json so tsc -b type-checks the tests; removed 3 dead deps; npm audit
fix (8 -> 3). Suite 195 -> 247 (happy-path auth, FIFO oldest-first, flakiness fixes),
isolated on app_test via .env.test with a hard-throw setup guard.

Gates: tsc 0 | build 0 | vitest 247/247 | eslint 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 06:45:26 +02:00
BOHA
8c278be941 test: add regression tests for Critical+High FLAWS_REPORT fixes
- Tests caught 2 real bugs:
  - Zod NaN bypass in orders/offers schemas (Number(v) || fallback)
  - invoiceTotalWithVat using Number() on { toNumber() } objects
- 7 new test files covering auth, env, exchange rates, NAS paths,
  schema NaN rejection, invoice VAT calculation, customer validation
- 45 tests passing, build clean

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 11:04:20 +02:00