gigafibre-fsm/scripts/migration/import_items.py
louispaulb 607ea54b5c refactor: reduce token count, DRY code, consolidate docs
Backend services:
- targo-hub: extract deepGetValue to helpers.js, DRY disconnect reasons
  lookup map, compact CAPABILITIES, consolidate vision.js prompts/schemas,
  extract dispatch scoring weights, trim section dividers across 9 files
- modem-bridge: extract getSession() helper (6 occurrences), resetIdleTimer(),
  consolidate DM query factory, fix duplicate username fill bug, trim headers
  (server.js -36%, tplink-session.js -47%, docker-compose.yml -57%)

Frontend:
- useWifiDiagnostic: extract THRESHOLDS const, split processDiagnostic into
  6 focused helpers (processOnlineStatus, processWanIPs, processRadios,
  processMeshNodes, processClients, checkRadioIssues)
- EquipmentDetail: merge duplicate ROLE_LABELS, remove verbose comments

Documentation (17 → 13 files, -1,400 lines):
- New consolidated README.md (architecture, services, dependencies, auth)
- Merge ECOSYSTEM-OVERVIEW into ARCHITECTURE.md
- Merge MIGRATION-PLAN + ARCHITECTURE-COMPARE + FIELD-GAP + CHANGELOG → MIGRATION.md
- Merge COMPETITIVE-ANALYSIS into PLATFORM-STRATEGY.md
- Update ROADMAP.md with current phase status
- Delete CONTEXT.md (absorbed into README)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:39:58 -04:00

137 lines
4.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Migration Script: Legacy product -> ERPNext Item
Python 3.5 compatible (no f-strings)
"""
import json
import sys
import requests
import pymysql
try:
from html import unescape
except ImportError:
try:
from HTMLParser import HTMLParser
unescape = HTMLParser().unescape
except:
unescape = lambda x: x
LEGACY = {
"host": "legacy-db",
"user": "facturation",
"password": "VD67owoj",
"database": "gestionclient",
}
ERP_URL = "https://erp.gigafibre.ca"
ERP_TOKEN = "token b273a666c86d2d0:06120709db5e414"
CAT_MAP = {
1: u"Garantie prolongée",
2: u"Intérêts et frais divers",
3: u"Impression",
4: u"Mensualités sans fil",
5: u"Technicien",
6: u"Frais d'activation",
7: u"Equipement internet sans fil",
8: u"Installation et équipement internet sans fil",
9: u"Téléphonie",
10: u"Site internet",
11: u"Nom de domaine",
12: u"Services informatique",
13: u"Location d'espace",
14: u"Pièces informatique",
15: u"Hébergement",
16: u"Téléchargement supplémentaire",
17: u"Adresse IP Fixe",
18: u"Infographie",
19: u"Revenus - Frais de recouvrement",
20: u"Créances irrécouvrables",
21: u"Location point à point",
22: u"Frais pour irrécouvrables",
23: u"Internet camping",
24: u"Transport",
25: u"Frais divers taxables",
26: u"Installation et équipement fibre",
27: u"SPECIAL",
28: u"Quincaillerie",
29: u"Equipement internet fibre",
30: u"Location espace cloud",
31: u"Honoraires",
32: u"Mensualités fibre",
33: u"Mensualités télévision",
34: u"Installation et équipement télé",
}
SERVICE_CATS = {1,2,4,6,9,11,12,13,15,16,17,18,19,20,21,22,23,24,25,27,30,31,32,33}
def erp_post(doctype, data):
url = "{}/api/resource/{}".format(ERP_URL, doctype)
headers = {"Authorization": ERP_TOKEN, "Content-Type": "application/json"}
r = requests.post(url, headers=headers, json={"data": json.dumps(data)}, timeout=30, verify=True)
try:
return r.status_code, r.json()
except:
return r.status_code, {"error": r.text[:200]}
def main():
conn = pymysql.connect(**LEGACY)
cur = conn.cursor(pymysql.cursors.DictCursor)
cur.execute("""
SELECT p.*,
(SELECT COUNT(*) FROM service s WHERE s.product_id = p.id AND s.status = 1) as active_services
FROM product p
ORDER BY p.id
""")
products = cur.fetchall()
created = 0
skipped = 0
errors = 0
for p in products:
sku = p["sku"] or "LEGACY-{}".format(p["id"])
cat_id = p["category"] or 4
item_group = CAT_MAP.get(cat_id, "Products")
sku = unescape(sku).strip()
is_service = cat_id in SERVICE_CATS
disabled = 1 if (not p["active"] and p["active_services"] == 0) else 0
item_data = {
"doctype": "Item",
"item_code": sku,
"item_name": sku,
"item_group": item_group,
"stock_uom": "Nos",
"is_stock_item": 0 if is_service else 1,
"disabled": disabled,
"description": "Legacy product ID: {}".format(p["id"]),
"standard_rate": float(p["price"] or 0),
}
status, resp = erp_post("Item", item_data)
resp_str = str(resp)
if status == 200 and resp.get("data"):
created += 1
print(" OK {:<30s} ${:>8.2f} grp={:<25s} svc={}".format(
sku, float(p["price"] or 0), item_group[:25], p["active_services"]))
elif "DuplicateEntryError" in resp_str or "already exists" in resp_str.lower():
skipped += 1
print(" SKIP {:<30s} (already exists)".format(sku))
else:
errors += 1
err_msg = str(resp.get("exc_type", resp.get("message", resp_str)))[:80]
print(" ERR {:<30s} -> {}".format(sku, err_msg))
conn.close()
print("\n=== DONE: {} created, {} skipped, {} errors (total {}) ===".format(
created, skipped, errors, len(products)))
if __name__ == "__main__":
main()