From 12b9da3e3689da503140bcd25129079b7f69cbce Mon Sep 17 00:00:00 2001 From: louispaulb Date: Mon, 20 Jul 2026 10:21:06 -0400 Subject: [PATCH] =?UTF-8?q?fix(legacy-sync):=20adresse/pin=20du=20job=20?= =?UTF-8?q?=3D=20adresse=20de=20service=20du=20billet=20(d=C3=A9m=C3=A9nag?= =?UTF-8?q?ement/multi-adresses)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug (capture LEG-254850 « Patrick Leclair », qui a DÉMÉNAGÉ Saint-Louis→Franklin) : l'adresse affichée + le pin carte pointaient l'ANCIENNE propriété. Cause : buildJob prenait address+coords de la DELIVERY legacy (t.dv_*, périmée), alors que service_location est apparié par la VILLE du ticket (= l'adresse pour laquelle le billet a été créé). Fix : on écrase address+coords par la Service Location LIÉE UNIQUEMENT si la delivery correspond à une AUTRE Service Location DU MÊME CLIENT (déménagement/multi-adresses). Un SITE EXTERNE (ex. cabane à sucre) ne matche aucune SL → on garde l'adresse du billet. + postal_code au fetch SL. Discriminant via _slCache (déjà peuplé, pas de re-fetch). Backfill prod : 519 jobs open/assigned → 15 « propre-autre-adresse » corrigés (pin <1 km d'une autre SL du client), 26 sites externes gardés, ~31 même-ville laissés (précision). LEG-254850 corrigé à part (→ Franklin). Co-Authored-By: Claude Opus 4.8 --- services/targo-hub/lib/legacy-dispatch-sync.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/services/targo-hub/lib/legacy-dispatch-sync.js b/services/targo-hub/lib/legacy-dispatch-sync.js index b92ab82..7b64d78 100644 --- a/services/targo-hub/lib/legacy-dispatch-sync.js +++ b/services/targo-hub/lib/legacy-dispatch-sync.js @@ -412,7 +412,7 @@ async function resolveServiceLocation (custName, city) { if (!custName) return null let list = _slCache.get(custName) if (!list) { - list = (await erp.list('Service Location', { filters: [['customer', '=', custName]], fields: ['name', 'address_line', 'city', 'latitude', 'longitude'], limit: 10 })) || [] + list = (await erp.list('Service Location', { filters: [['customer', '=', custName]], fields: ['name', 'address_line', 'city', 'postal_code', 'latitude', 'longitude'], limit: 10 })) || [] _slCache.set(custName, list) } if (!list.length) return null @@ -560,7 +560,21 @@ async function buildJob (t, { dryRun = false } = {}) { if (!coordSrc) { const dev = await resolveDevCoords(pool(), { pmid: t.dv_pmid, dlat: t.dv_lat, dlon: t.dv_lon, address: svcAddr || billAddr, camp }); if (dev) { payload.latitude = dev.lat; payload.longitude = dev.lon; coordSrc = dev.src } } if (sl) { payload.service_location = sl.name - if (!coordSrc) { const sc = coord(sl.latitude, sl.longitude); if (sc) { payload.latitude = sc.lat; payload.longitude = sc.lon; coordSrc = 'service_location' } } // repli si rien d'autre + const sc = coord(sl.latitude, sl.longitude) + // ADRESSE DE SERVICE DU BILLET : l'adresse/coords viennent de la delivery legacy, qui peut être PÉRIMÉE (client + // DÉMÉNAGÉ) ou viser une AUTRE propriété du client. La Service Location est appariée par la VILLE du ticket (= + // l'adresse pour laquelle le billet a été créé). On écrase par la SL LIÉE UNIQUEMENT si la delivery correspond à + // une AUTRE Service Location DU MÊME CLIENT (cas déménagement/multi-adresses, bug LEG-254850 : delivery = ancienne + // adresse Saint-Louis, SL = nouvelle Franklin). Un site EXTERNE (ex. cabane à sucre) ne matche AUCUNE SL → on + // GARDE l'adresse du billet. _slCache est déjà peuplé par resolveServiceLocation (ligne « let sl = … » ci-dessus). + const delivCity = norm(svcAddr ? t.dv_city : t.city) + const slList = (cust && _slCache.get(cust.name)) || [] + const ownOtherAddr = sl.city && delivCity && norm(sl.city) !== delivCity && slList.some(l => l.name !== sl.name && norm(l.city) === delivCity) + if (sc && ownOtherAddr) { + payload.latitude = sc.lat; payload.longitude = sc.lon; coordSrc = 'service_location_override' + const slAddr = [sl.address_line, sl.city, sl.postal_code].filter(Boolean).join(', ') + if (slAddr) payload.address = slAddr.slice(0, 140) + } else if (!coordSrc && sc) { payload.latitude = sc.lat; payload.longitude = sc.lon; coordSrc = 'service_location' } // repli si rien d'autre } if (!coordSrc && addr) { // replis géocodage sur l'adresse de service (sinon facturation) : RQA → OSM (validé) → CENTRE DU CODE POSTAL (borné) const useSvc = !!svcAddr