""" Import account suspensions as flags on Customer. Also imports bon_travail as Comments on Customer (work order history). Run inside erpnext-backend-1: /home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/import_suspensions.py """ import frappe import pymysql import os, sys, time from datetime import datetime, timezone from html import unescape sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) os.chdir("/home/frappe/frappe-bench/sites") frappe.init(site="erp.gigafibre.ca", sites_path=".") frappe.connect() frappe.local.flags.ignore_permissions = True print("Connected:", frappe.local.site) legacy = pymysql.connect( host="legacy-db", user="facturation", password="VD67owoj", database="gestionclient", cursorclass=pymysql.cursors.DictCursor ) cust_map = {} for r in frappe.db.sql('SELECT name, legacy_account_id FROM "tabCustomer" WHERE legacy_account_id > 0', as_dict=True): cust_map[int(r['legacy_account_id'])] = r['name'] print(f" {len(cust_map)} customers mapped") staff_map = {} # No legacy_staff_id on Employee — build from legacy DB with legacy.cursor() as cur: cur.execute("SELECT id, CONCAT(first_name, ' ', last_name) as name FROM staff WHERE first_name IS NOT NULL") for r in cur.fetchall(): staff_map[r['id']] = r['name'].strip() def ts_to_date(unix_ts): if not unix_ts or unix_ts <= 0: return None try: return datetime.fromtimestamp(int(unix_ts), tz=timezone.utc).strftime("%Y-%m-%d") except (ValueError, OSError): return None def ts_to_dt(unix_ts): if not unix_ts or unix_ts <= 0: return None try: return datetime.fromtimestamp(int(unix_ts), tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S") except (ValueError, OSError): return None # ═══════════════════════════════════════════════════════════ # 1. Account Suspensions → Customer.is_suspended # ═══════════════════════════════════════════════════════════ print("\n=== Importing suspensions ===") with legacy.cursor() as cur: cur.execute("SELECT account_id, note FROM account_suspension") susp_rows = cur.fetchall() updated = 0 for r in susp_rows: cust = cust_map.get(r['account_id']) if not cust: continue frappe.db.sql( 'UPDATE "tabCustomer" SET is_suspended = 1, suspension_note = %s WHERE name = %s', ((r['note'] or '').strip(), cust) ) updated += 1 frappe.db.commit() print(f" {updated} customers marked as suspended") # ═══════════════════════════════════════════════════════════ # 2. Bons de travail → Comments on Customer # ═══════════════════════════════════════════════════════════ print("\n=== Importing bons de travail as Comments ===") # Check if already imported (by content prefix) existing = frappe.db.sql( "SELECT COUNT(*) FROM \"tabComment\" WHERE comment_type='Comment' AND content LIKE %s", ("🔧 Bon de travail%",) )[0][0] if existing: print(f" {existing} work order comments already exist — skipping") else: with legacy.cursor() as cur: cur.execute(""" SELECT bt.id, bt.account_id, bt.date, bt.tech1, bt.tech2, bt.heure_arrive_t1, bt.heure_depart_t1, bt.heure_arrive_t2, bt.heure_depart_t2, bt.note, bt.subtotal, bt.tps, bt.tvq, bt.total FROM bon_travail bt ORDER BY bt.id """) bt_rows = cur.fetchall() print(f" {len(bt_rows)} bons de travail to import") T0 = time.time() created = skipped = 0 for bt in bt_rows: cust = cust_map.get(bt['account_id']) if not cust: skipped += 1 continue dt = ts_to_dt(bt['date']) date_str = ts_to_date(bt['date']) or '?' tech1_name = staff_map.get(bt['tech1'], f"Tech #{bt['tech1']}") if bt['tech1'] else '' tech2_name = staff_map.get(bt['tech2'], f"Tech #{bt['tech2']}") if bt['tech2'] else '' lines = [f"Bon de travail #{bt['id']} — {date_str}"] if tech1_name: time_range = f" ({bt['heure_arrive_t1'] or '?'} - {bt['heure_depart_t1'] or '?'})" if bt.get('heure_arrive_t1') else '' lines.append(f"Tech 1: {tech1_name}{time_range}") if tech2_name: time_range = f" ({bt['heure_arrive_t2'] or '?'} - {bt['heure_depart_t2'] or '?'})" if bt.get('heure_arrive_t2') else '' lines.append(f"Tech 2: {tech2_name}{time_range}") if bt['note']: lines.append(f"Note: {unescape(bt['note']).strip()}") if bt['total'] and float(bt['total']) > 0: lines.append(f"Total: ${float(bt['total']):.2f} (TPS: ${float(bt['tps'] or 0):.2f}, TVQ: ${float(bt['tvq'] or 0):.2f})") content = "
".join(lines) doc = frappe.get_doc({ "doctype": "Comment", "comment_type": "Comment", "reference_doctype": "Customer", "reference_name": cust, "content": content, "comment_email": "migration@targo.ca", "creation": dt or "2020-01-01 00:00:00", "modified": dt or "2020-01-01 00:00:00", }) doc.insert(ignore_permissions=True) created += 1 if created % 1000 == 0: frappe.db.commit() print(f" [{created}/{len(bt_rows)}] [{time.time()-T0:.0f}s]") frappe.db.commit() print(f" Created: {created}, Skipped: {skipped} [{time.time()-T0:.0f}s]") legacy.close() frappe.destroy() print("\nDone!")