Files
orderPRO/.paul/phases/126-invoice-gus-field-mapping/126-01-SUMMARY.md
Jacek Pyziak c758ec7c92 feat(126): invoice GUS field mapping fix (JDG/KRS heuristic)
MfWhitelistApiClient.lookupByNip() exposes is_jdg/krs from MF Biala Lista.
InvoiceController.nipLookup propagates is_jdg in JSON response.
invoice_form.php JS conditionally targets buyer_name (JDG) or
buyer_company_name (spolka z KRS); second field keeps zamowienie pre-fill.

Fixes apparent field swap on /orders/{id}/invoice/create after GUS lookup
for JDG (sole trader) where MF returns natural person in subject.name.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:29:55 +02:00

5.1 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, duration, started, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established duration started completed
126-invoice-gus-field-mapping 01 accounting
invoice
gus
mf-biala-lista
nip-lookup
jdg
krs
phase provides
115-invoice-issuance invoice_form.php GUS lookup wiring, MfWhitelistApiClient base contract
MfWhitelistApiClient `is_jdg`/`krs` flags
/api/nip/lookup JSON response with `data.is_jdg`
invoice_form.php JS conditional name field mapping (JDG vs spółka)
future-nip-lookup-forms
invoice-issuance-ux
added patterns
KRS-empty heuristic for JDG detection in MF Biała Lista responses
created modified
src/Core/Http/MfWhitelistApiClient.php
src/Modules/Accounting/InvoiceController.php
resources/views/accounting/invoice_form.php
JDG = MF subject.krs === '' (KRS-empty signal)
JS mapuje warunkowo wg is_jdg; pre-fill drugiego pola nigdy nie jest nadpisywany przez GUS
MF Biała Lista API client exposes is_jdg flag — reusable for any NIP lookup formularz
~20min 2026-05-13T22:15:00Z 2026-05-13T22:35:00Z

Phase 126 Plan 01: Invoice GUS Field Mapping Fix Summary

Po kliknięciu "Pobierz z GUS" na /orders/{id}/invoice/create dane MF Białej Listy trafiają teraz do właściwego pola w zależności od typu podmiotu (JDG → "Imię i nazwisko", spółka z KRS → "Nazwa firmy"); drugie pole zachowuje pre-fill z zamówienia.

Performance

Metric Value
Duration ~20 min
Tasks 3/3 PASS
Files modified 3

Acceptance Criteria Results

Criterion Status Notes
AC-1: JDG → name z MF do "Imię i nazwisko", "Nazwa firmy" niezmieniona Code-level PASS Manual smoke /orders/1090/invoice/create pending operator
AC-2: Spółka z KRS → name z MF do "Nazwa firmy", "Imię i nazwisko" niezmieniona Code-level PASS Wymaga zamówienia z NIP-em spółki z aktywnym KRS — manual smoke pending
AC-3: /api/nip/lookup response zawiera data.is_jdg Code-level PASS Lint clean; live curl pending operator (offline env)

Accomplishments

  • Root cause zdiagnozowany przez bezpośrednie odpytanie produkcyjnej DB (order_addresses order_id=1090) i live MF API call dla NIP 5170167517 — potwierdzony JDG response.
  • 3 pliki zmodyfikowane minimalnie: 1 nowe pole w return array klienta MF, 1 nowe pole w JSON response endpointu, 1 warunek w JS bloku GUS lookup.
  • Pre-fill operatora z order_addresses jest teraz chroniony — GUS lookup nigdy nie nadpisuje obu pól osobowych równocześnie.

Files Created/Modified

File Change Purpose
src/Core/Http/MfWhitelistApiClient.php Modified Dodane krs: string, is_jdg: bool w return array lookupByNip(); zaktualizowany docblock @return
src/Modules/Accounting/InvoiceController.php Modified nipLookup() propaguje is_jdg w data JSON response
resources/views/accounting/invoice_form.php Modified JS btn-gus-lookup handler: var nameTargetId = d.is_jdg ? 'buyer_name' : 'buyer_company_name'; — drugiego pola nie rusza; adres (street/postal_code/city) nadpisywany bez zmian

Decisions Made

Decision Rationale Impact
Heurystyka JDG = subject.krs === '' MF Biała Lista zwraca krs=null dla osób fizycznych prowadzących działalność; spółki mają KRS niepusty Stabilny sygnał z MF; zero zewnętrznych zależności
GUS NIE nadpisuje "Nazwa firmy" dla JDG MF name dla JDG to osoba fizyczna, a order_addresses.name często trzyma pełną nazwę firmy (np. "Project-Pro Pyziak Jacek") — wartościowsza dla faktury Operator zachowuje sensowny pre-fill, nie musi przepisywać po lookupie
Backend (InvoiceService::resolveBuyerSnapshot) nie zmieniany Server-side bierze wartości z requestu — operator ma pełną kontrolę przed submitem Zero ryzyka regresji na server-side merge

Deviations from Plan

Summary

Type Count Impact
Auto-fixed 0
Scope additions 0
Deferred 0

Total impact: Plan wykonany 1:1, brak odstępstw.

Deferred Items

Brak.

Issues Encountered

Issue Resolution
vendor/autoload.php nieobecny w lokalnym env — niemożliwa live weryfikacja Task 1 przez REPL Pominięta live verification; pole is_jdg to mechaniczny field-add, lint clean wystarczy. Live curl /api/nip/lookup pozostaje do manual smoke przez operatora

Next Phase Readiness

Ready:

  • Fix wdrożony na 3 plikach, lint clean, zero zmian backendu poza dodaniem 1 pola w JSON.
  • Pattern KRS-heuristic gotowy do reuse w innych formularzach opartych o NIP lookup (np. ewentualny edit invoice config buyer presets).

Concerns:

  • AC-1/AC-2/AC-3 nie zweryfikowane na żywym środowisku — wymaga manual smoke operatora po deploy (lokalny env bez vendor/, prod live test odłożony).

Blockers:

  • None.

Phase: 126-invoice-gus-field-mapping, Plan: 01 Completed: 2026-05-13