feat(address): ROA address cache refresh — 8-field format + manual refresh endpoint

Phase 5 address format upgrade (pre-existing working tree changes):
- import_service: extend vadrese_parteneri query to 8 fields (strada/numar/bloc/scara/apart/etaj/localitate/judet); strip trailing city name from address string passed to Oracle
- sync_service: extend _addr_match to compare bloc/scara/apart in addition to strada/numar
- 05_pack_import_parteneri.pck: updated PL/SQL package

New: address cache refresh mechanism:
- sqlite_service: add get_order_address_ids(), update_order_address_cache() (targeted 3-column update, no ANAF fields touched), get_orders_with_address_ids()
- sync.py: POST /api/orders/{order_number}/refresh-address endpoint (404/422/503/200); batch Oracle address refresh in refresh_invoices (single IN roundtrip, per-order mismatch recomputed)
- UI: refresh button (⟳) in ADRESE modal header (base.html); refreshOrderAddress() with loading state + toast (dashboard.js v43); window._detailOrderNumber global (shared.js v32)
- tests: TestRefreshOrderAddress — 4 tests (404, 422, 503, 200 with 8-field assert)

Oracle prod fix applied directly: ADRESE_PARTENERI id_adresa=4116 STRADA VASILE→VASILE GOLDIS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-04-07 12:35:18 +00:00
parent a8ad54a604
commit ecde7fe440
10 changed files with 377 additions and 10 deletions

View File

@@ -494,6 +494,8 @@ function _renderReceipt(items, order) {
async function renderOrderDetailModal(orderNumber, opts) {
opts = opts || {};
window._detailOrderNumber = orderNumber;
// Reset modal state
document.getElementById('detailOrderNumber').textContent = '#' + orderNumber;
document.getElementById('detailCustomer').textContent = '...';
@@ -831,6 +833,13 @@ function fmtAddr(a) {
if (!a) return '\u2014';
if (typeof a === 'string') return a;
const parts = [a.address || a.strada || '', a.numar || ''].filter(Boolean);
const extras = [
a.bloc ? 'Bl.' + a.bloc : '',
a.scara ? 'Sc.' + a.scara : '',
a.apart ? 'Ap.' + a.apart : '',
a.etaj ? 'Et.' + a.etaj : '',
].filter(Boolean).join(' ');
if (extras) parts.push(extras);
const line1 = parts.join(' ').trim();
const line2 = [a.city || a.localitate || '', a.region || a.judet || ''].filter(Boolean).join(', ');
return [line1, line2].filter(Boolean).join(', ');
@@ -845,7 +854,7 @@ function addrMatch(gomag, roa) {
.replace(/[^A-Z0-9]/g, '');
}
const gStreet = norm(gomag.address || gomag.strada || '');
const rStreet = norm((roa.strada || '') + (roa.numar || ''));
const rStreet = norm((roa.strada||'') + (roa.numar||'') + (roa.bloc||'') + (roa.scara||'') + (roa.apart||''));
const gCity = norm(gomag.city || gomag.localitate || '');
const rCity = norm(roa.localitate || '');
const gRegion = norm(gomag.region || gomag.judet || '');