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>
119 lines
5.1 KiB
Markdown
119 lines
5.1 KiB
Markdown
---
|
|
phase: 126-invoice-gus-field-mapping
|
|
plan: 01
|
|
subsystem: accounting
|
|
tags: [invoice, gus, mf-biala-lista, nip-lookup, jdg, krs]
|
|
|
|
requires:
|
|
- phase: 115-invoice-issuance
|
|
provides: invoice_form.php GUS lookup wiring, MfWhitelistApiClient base contract
|
|
provides:
|
|
- 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)
|
|
affects: [future-nip-lookup-forms, invoice-issuance-ux]
|
|
|
|
tech-stack:
|
|
added: []
|
|
patterns:
|
|
- "KRS-empty heuristic for JDG detection in MF Biała Lista responses"
|
|
|
|
key-files:
|
|
created: []
|
|
modified:
|
|
- src/Core/Http/MfWhitelistApiClient.php
|
|
- src/Modules/Accounting/InvoiceController.php
|
|
- resources/views/accounting/invoice_form.php
|
|
|
|
key-decisions:
|
|
- "JDG = MF subject.krs === '' (KRS-empty signal)"
|
|
- "JS mapuje warunkowo wg is_jdg; pre-fill drugiego pola nigdy nie jest nadpisywany przez GUS"
|
|
|
|
patterns-established:
|
|
- "MF Biała Lista API client exposes is_jdg flag — reusable for any NIP lookup formularz"
|
|
|
|
duration: ~20min
|
|
started: 2026-05-13T22:15:00Z
|
|
completed: 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*
|