From 8a51925da830f983916fa81d92f8e3f214180ac2 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Mon, 6 Jul 2026 23:09:16 -0400 Subject: [PATCH] devices: import du manquant + fix liens SS.device orphelins + catch-up quotidien MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - import_devices_and_enrich.py : creds via env (secret hors repo) + SKIP_ENRICH (devices seuls). Rattrapage : 1160 devices importés (tous les devices F courants sont maintenant en Service Equipment). - FIX bug d'import : rename_all_doctypes.py avait renommé Service Equipment (EQ-{md5}→EQP-{seq}) sans cascader vers Service Subscription.device → 6980 liens orphelins ("Could not find Device: EQ-…", bloquait les saves pleine-doc). 5241 remappés via legacy_device_id+md5 (UPDATE PG direct). Résiduel 1739 = device supprimé côté F (1584 Actif / 155 Annulé) → décision NULL vs relink en attente. - Récurrence : tickets-daily.sh importe désormais AUSSI les devices (SKIP_ENRICH=1), quotidien 04:30. Co-Authored-By: Claude Opus 4.8 --- .../migration/import_devices_and_enrich.py | 9 ++++-- scripts/targo-sync/README.md | 26 +++++++++++----- scripts/targo-sync/tickets-daily.sh | 31 ++++++++++++------- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/scripts/migration/import_devices_and_enrich.py b/scripts/migration/import_devices_and_enrich.py index 8f4b049..93a2bda 100644 --- a/scripts/migration/import_devices_and_enrich.py +++ b/scripts/migration/import_devices_and_enrich.py @@ -26,9 +26,9 @@ now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") # LEGACY DB CONNECTION # ═══════════════════════════════════════════════════════════════ conn = pymysql.connect( - host="legacy-db", + host=os.environ.get("LEGACY_HOST", "10.100.80.100"), user="facturation", - password="*******", + password=os.environ.get("LEGACY_PW", ""), # secret via env (jamais commité) database="gestionclient", cursorclass=pymysql.cursors.DictCursor ) @@ -225,6 +225,11 @@ if batch: print("Inserted {} new devices ({} already existed)".format(inserted, skipped)) +if os.environ.get("SKIP_ENRICH", "0") == "1": + print("SKIP_ENRICH=1 → devices importés, on saute l'enrichissement (Phase 3) + Phase 4") + conn.close() + import sys; sys.exit(0) + # ═══════════════════════════════════════════════════════════════ # PHASE 3: Enrich Service Locations with fibre data # ═══════════════════════════════════════════════════════════════ diff --git a/scripts/targo-sync/README.md b/scripts/targo-sync/README.md index 3514012..685aa89 100644 --- a/scripts/targo-sync/README.md +++ b/scripts/targo-sync/README.md @@ -52,13 +52,23 @@ Réconciliation visible dans OPS : page **/sync-legacy** → carte « Réconcili ## Fichiers -## Tickets → Issue (cron QUOTIDIEN séparé) +## Catch-up QUOTIDIEN — tickets + appareils (cron séparé) -`tickets-daily.sh` (cron `30 4 * * *`) lance `migrate_tickets.py` (idempotent, skip par -`legacy_ticket_id`) pour n'importer que les nouveaux tickets. Séparé de `run.sh` (horaire) car -le scan de 252k tickets est trop lourd pour l'horaire. Le canonique de `migrate_tickets.py` est -`scripts/migration/` ; en déployer une copie dans `/opt/targo-sync/`. Messages des tickets *closed* -non importés (deferred ; `import_ticket_msgs.py` au besoin). +`tickets-daily.sh` (cron `30 4 * * *`) lance deux imports idempotents (skip par `legacy_*_id`, +n'importent que les nouveaux) : +- **`migrate_tickets.py`** → `tabIssue` (skip par `legacy_ticket_id`). Messages des tickets *closed* + non importés (deferred ; `import_ticket_msgs.py` au besoin). +- **`import_devices_and_enrich.py`** (avec `SKIP_ENRICH=1` = devices seulement) → `tabService Equipment` + (skip par `legacy_device_id`). Sans `SKIP_ENRICH`, enrichit aussi les Service Location (fibre/OLT/VLAN). + +Séparé de `run.sh` (horaire) car les scans complets (252k tickets / 11k devices) sont trop lourds +pour l'horaire. Canoniques dans `scripts/migration/` ; en déployer une copie dans `/opt/targo-sync/`. + +⚠️ **Bug d'import historique corrigé 2026-07-06** : `rename_all_doctypes.py` a renommé les +`Service Equipment` (`EQ-{md5}` → `EQP-{seq}`) SANS mettre à jour `Service Subscription.device` +→ 6980 liens orphelins (`Could not find Device: EQ-…`, bloquait les saves pleine-doc Frappe). +5241 remappés (via `legacy_device_id`+md5) ; 1739 résiduels pointaient un device supprimé côté F +(à trancher : NULL vs relink au device courant du lieu). Voir mémoire `feedback_device_hierarchy`. ## 🔐 Secrets — JAMAIS dans le repo @@ -73,5 +83,7 @@ Ne **jamais** committer une copie prod d'un script qui aurait le mot de passe en | `run.sh` | Orchestrateur cron horaire (4 étapes DAG) | | `sync_services_incremental.py` | Service Location (delivery) + Service Subscription (service) : création + prix + **statut (fix fantômes raffiné)** | | `sync_invoices_incremental.py` | Sales Invoice (miroir des factures F ; statut reflétant F) | -| `tickets-daily.sh` | Wrapper cron quotidien → `migrate_tickets.py` (secret via `secrets.env`) | +| `tickets-daily.sh` | Wrapper cron quotidien → `migrate_tickets.py` + `import_devices_and_enrich.py` (secret via `secrets.env`) | +| `migrate_tickets.py` | (déployé depuis `scripts/migration/`) tickets F → Issue | +| `import_devices_and_enrich.py` | (déployé depuis `scripts/migration/`) devices F → Service Equipment | | `secrets.env` | **Hôte seulement, non versionné** : `LEGACY_PW=…` | diff --git a/scripts/targo-sync/tickets-daily.sh b/scripts/targo-sync/tickets-daily.sh index e15ce08..4733eb1 100644 --- a/scripts/targo-sync/tickets-daily.sh +++ b/scripts/targo-sync/tickets-daily.sh @@ -1,25 +1,34 @@ #!/bin/bash -# Import QUOTIDIEN incrémental des tickets F → ERPNext Issue. -# migrate_tickets.py est idempotent (skip par legacy_ticket_id) : ne crée que les nouveaux. -# Complète le rattrapage 2026-07-06. Séparé du cron horaire run.sh (le scan de 252k tickets -# est trop lourd pour l'horaire ; quotidien suffit — les tickets s'accumulent lentement). +# Catch-up QUOTIDIEN legacy → ERPNext : tickets (Issue) + appareils (Service Equipment). +# Scripts idempotents (skip par legacy_*_id) : n'importent que les nouveaux. +# Séparé de run.sh (horaire) car les scans complets (252k tickets / 11k devices) sont lourds. +# (Nom de fichier conservé pour la stabilité du crontab.) # # Déploiement (hôte) : -# scp scripts/migration/migrate_tickets.py root@:/opt/targo-sync/migrate_tickets.py -# scp scripts/targo-sync/tickets-daily.sh root@:/opt/targo-sync/ && chmod +x /opt/targo-sync/tickets-daily.sh +# scp scripts/migration/migrate_tickets.py scripts/migration/import_devices_and_enrich.py root@:/opt/targo-sync/ +# scp scripts/targo-sync/tickets-daily.sh root@:/opt/targo-sync/ && chmod +x /opt/targo-sync/tickets-daily.sh # echo 'LEGACY_PW=' > /opt/targo-sync/secrets.env && chmod 600 /opt/targo-sync/secrets.env # secret HORS repo # crontab: 30 4 * * * /opt/targo-sync/tickets-daily.sh set -uo pipefail DIR=/opt/targo-sync LOG="$DIR/tickets-sync.log" -[ -f "$LOG" ] && tail -n 2000 "$LOG" > "$LOG.tmp" 2>/dev/null && mv "$LOG.tmp" "$LOG" +[ -f "$LOG" ] && tail -n 3000 "$LOG" > "$LOG.tmp" 2>/dev/null && mv "$LOG.tmp" "$LOG" exec >> "$LOG" 2>&1 -echo "===== $(date -Is) tickets-daily =====" +echo "===== $(date -Is) daily-catchup (tickets + appareils) =====" exec 9>"$DIR/.tickets.lock" flock -n 9 || { echo "déjà en cours, skip"; exit 0; } # secret (LEGACY_PW) chargé depuis un fichier hôte non versionné -[ -f "$DIR/secrets.env" ] && . "$DIR/secrets.env" +[ -f "$DIR/secrets.env" ] && set -a && . "$DIR/secrets.env" && set +a +LH="${LEGACY_HOST:-10.100.80.100}" + +echo "-- tickets → Issue --" docker cp "$DIR/migrate_tickets.py" erpnext-backend-1:/tmp/migrate_tickets.py 2>/dev/null -docker exec -e LEGACY_PW="${LEGACY_PW:-}" -e LEGACY_HOST="${LEGACY_HOST:-10.100.80.100}" -e PG_HOST=db \ - erpnext-backend-1 /home/frappe/frappe-bench/env/bin/python /tmp/migrate_tickets.py 2>&1 | tail -12 +docker exec -e LEGACY_PW="${LEGACY_PW:-}" -e LEGACY_HOST="$LH" -e PG_HOST=db \ + erpnext-backend-1 /home/frappe/frappe-bench/env/bin/python /tmp/migrate_tickets.py 2>&1 | tail -6 + +echo "-- appareils → Service Equipment (device-only) --" +docker cp "$DIR/import_devices_and_enrich.py" erpnext-backend-1:/tmp/import_devices.py 2>/dev/null +docker exec -e LEGACY_PW="${LEGACY_PW:-}" -e LEGACY_HOST="$LH" -e SKIP_ENRICH=1 \ + erpnext-backend-1 /home/frappe/frappe-bench/env/bin/python /tmp/import_devices.py 2>&1 | tail -4 + echo "done $(date -Is)"