feat: 29K customer memos imported as Comments with real dates
- 29,178 account_memo → Comment on Customer - Timestamps converted from unix to datetime - Author mapped from staff_id → User email - Visible in Customer page comment section Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c6b5aa8f61
commit
08cf1c94e3
100
scripts/migration/import_memos.py
Normal file
100
scripts/migration/import_memos.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Import account_memo as Comments on Customer. Fix timestamps."""
|
||||
import pymysql
|
||||
import psycopg2
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from html import unescape
|
||||
|
||||
LEGACY = {"host": "10.100.80.100", "user": "facturation", "password": "VD67owoj",
|
||||
"database": "gestionclient", "connect_timeout": 30, "read_timeout": 300}
|
||||
PG = {"host": "db", "port": 5432, "user": "postgres", "password": "123",
|
||||
"dbname": "_eb65bdc0c4b1b2d6"}
|
||||
|
||||
ADMIN = "Administrator"
|
||||
|
||||
def uid(p=""):
|
||||
return p + uuid.uuid4().hex[:10]
|
||||
|
||||
def ts_to_dt(t):
|
||||
if not t or t <= 0: return None
|
||||
try: return datetime.fromtimestamp(int(t), tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
except: return None
|
||||
|
||||
def clean(v):
|
||||
if not v: return ""
|
||||
return unescape(str(v)).strip()
|
||||
|
||||
def log(msg):
|
||||
print(msg, flush=True)
|
||||
|
||||
def main():
|
||||
log("=== Import Account Memos as Comments ===")
|
||||
|
||||
mc = pymysql.connect(**LEGACY)
|
||||
cur = mc.cursor(pymysql.cursors.DictCursor)
|
||||
cur.execute("SELECT * FROM account_memo ORDER BY id")
|
||||
memos = cur.fetchall()
|
||||
cur.execute("SELECT id, email FROM staff WHERE email IS NOT NULL AND email != ''")
|
||||
staff_email = {r["id"]: r["email"] for r in cur.fetchall()}
|
||||
mc.close()
|
||||
log(" {} memos loaded".format(len(memos)))
|
||||
|
||||
pg = psycopg2.connect(**PG)
|
||||
pgc = pg.cursor()
|
||||
|
||||
pgc.execute('SELECT legacy_account_id, name FROM "tabCustomer" WHERE legacy_account_id > 0')
|
||||
cust_map = {r[0]: r[1] for r in pgc.fetchall()}
|
||||
|
||||
pgc.execute('SELECT name FROM "tabUser" WHERE enabled = 1')
|
||||
valid_users = set(r[0] for r in pgc.fetchall())
|
||||
|
||||
ok = err = 0
|
||||
for m in memos:
|
||||
cust_name = cust_map.get(m["account_id"])
|
||||
if not cust_name:
|
||||
err += 1
|
||||
continue
|
||||
|
||||
content = clean(m.get("memo")) or "(empty memo)"
|
||||
created = ts_to_dt(m.get("date_orig"))
|
||||
if not created:
|
||||
created = ts_to_dt(m.get("last_updated")) or datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
owner = staff_email.get(m.get("staff_id"), ADMIN)
|
||||
if owner not in valid_users:
|
||||
owner = ADMIN
|
||||
|
||||
try:
|
||||
pgc.execute("""
|
||||
INSERT INTO "tabComment" (
|
||||
name, creation, modified, modified_by, owner, docstatus, idx,
|
||||
comment_type, comment_email, content,
|
||||
reference_doctype, reference_name, published
|
||||
) VALUES (
|
||||
%s, %s, %s, %s, %s, 0, 0,
|
||||
'Comment', %s, %s,
|
||||
'Customer', %s, 0
|
||||
)
|
||||
""", (uid("MEMO-"), created, created, owner, owner,
|
||||
owner, content, cust_name))
|
||||
ok += 1
|
||||
except Exception as e:
|
||||
err += 1
|
||||
pg.rollback()
|
||||
if err <= 5:
|
||||
log(" ERR memo#{} -> {}".format(m["id"], str(e)[:80]))
|
||||
|
||||
if ok % 2000 == 0 and ok > 0:
|
||||
pg.commit()
|
||||
log(" {} memos imported".format(ok))
|
||||
|
||||
pg.commit()
|
||||
pg.close()
|
||||
log("")
|
||||
log("=" * 50)
|
||||
log("Memos: {} imported, {} errors".format(ok, err))
|
||||
log("=" * 50)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user