Files
roa2web-service-auto/docs/service-auto/autocomplete-dual-decision.md
Claude Agent 4397027f36 feat(service-auto): multi-tenant + tier 3 lookups + D1 partener + AsyncAutoComplete
Refactor izolare multi-tenant:
- Schema Oracle rezolvată din id_firma via CONTAFIN_ORACLE.V_NOM_FIRME (cached 24h)
- server_id propagat din JWT (request.state.server_id) la oracle_pool.get_connection
- Elimină _SCHEMA='MARIUSM_AUTO' și literal 'mariusm_test' din toate query-urile
- Autorizare firmă la router (_company_id): 403 dacă id_firma nu e în JWT companies[]

Tier 3 — lookup endpoints cached 24h:
- GET /asiguratori (DEV_NOM_ASIGURATORI ← NOM_PARTENERI)
- GET /inspectori?id_asigurator=N (DEV_NOM_INSPECTORI per asig)
- GET /operatii (DEV_NOM_NORME)
- GET /parteneri?q=... (typeahead LIKE escape)
- GET /masini/{id}/detalii (VIN, cilindree, putere)
- POST /comenzi: PACK_SERII_NUMERE.aloca_numar + compensating dezaloca;
  pc_nr VFP-format prefix+seq/nrinmat; ORA-06512 stripped din detail

D1 PartnerCreateDialog (nou):
- POST /api/service-auto/parteneri → PartnerCreateRequest; 409 pe CUI
  duplicat (NOM_PARTENERI fără UNIQUE constraint — check manual);
  id_part = MAX+1 cu retry pe ORA-00001 (fără sequence în schema VFP legacy)
- Frontend PartnerCreateDialog.vue — PrimeVue, design tokens, dark-mode safe
- Integrat în ComandaNoua.vue via AutoComplete empty-action hook

Shared AsyncAutoComplete (nou):
- src/shared/components/AsyncAutoComplete.vue — typeahead async debounced
  cu emptyAction slot, force-selection, keyboard (Enter/Esc), design tokens
- ComandaNoua.vue refactorizat să folosească shared component
- SupplierDualField (data-entry) skipped — documentat în
  docs/service-auto/autocomplete-dual-decision.md (pattern diferit)

Mobile chrome (CLAUDE.md):
- ComandaNoua.vue + ComenziBrowseView.vue: MobileTopBar, BottomSheet
  filtre, MobileBottomNav, card list, isMobile resize listener

Migrații grant-uri idempotente:
- ff_2026_04_13_01_AUTO.sql — SELECT/EXECUTE pe tabele Tier 3 + index
  IX_NOM_PARTENERI_DEN_UPPER
- ff_2026_04_13_02_AUTO.sql — INSERT pe NOM_PARTENERI pentru D1

Live smoke pe MARIUSM_AUTO: /ping 1ms, /tip-deviz 7, /masini 261,
POST /parteneri id_part=70241, firma neautorizată → 403.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-05 09:37:10 +00:00

1.9 KiB

SupplierDualField — refactor decision

Decizie: SupplierDualField.vue NU se refactorizează cu AsyncAutoComplete.

Context

Task #3 a extras AsyncAutoComplete (shared) din pattern-ul typeahead async din ComandaNoua.vue. Candidatul pentru refactor a fost src/modules/data-entry/components/receipts/SupplierDualField.vue.

Motive pentru skip

  1. Filtru client-side, nu async remote SupplierDualField filtrează o listă partners preîncărcată în memorie (props.partners.filter(...) pe nume + CUI). AsyncAutoComplete e construit pe searchFn: (q) => Promise<Item[]> (remote). Adaptarea ar cere un wrapper artificial async (q) => partners.filter(...) care nu aduce valoare.

  2. force-selection: false vs force-selection: true SupplierDualField permite intrare free-text (forceSelection: false) pentru că users pot tasta manual CUI/nume furnizor. AsyncAutoComplete impune force-selection: true ca invariant de securitate (evită ID-uri fantomă). Schimbarea ar rupe flow-ul existent.

  3. Dropdown manual + câmp CUI separat Componenta e composite: AutoComplete (nume) + InputText (CUI) + toggle adresă

    • sync-button + status badges (oracle/local/warning), totul cu propriile update:* emits. AutoComplete-ul e doar o parte — extragerea lui izolat ar lăsa componenta într-o stare hibridă, mai complicată decât acum.
  4. Prop dropdown SupplierDualField folosește dropdown (buton chevron care arată toată lista). AsyncAutoComplete nu expune acest mod (ar contrazice pattern-ul async „caută minim N caractere").

Concluzie

Pattern-urile diferă fundamental. Păstrăm SupplierDualField neschimbat. AsyncAutoComplete rămâne dedicat pattern-urilor de typeahead async, cu sursa de date remote (ex: ComandaNoua.vue → partener service-auto, și viitoare formulare similare).