#!/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": "10.100.80.100", "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()