- InlineField component + useInlineEdit composable for Odoo-style dblclick editing - Client search by name, account ID, and legacy_customer_id (or_filters) - SMS/Email notification panel on ContactCard via n8n webhooks - Ticket reply thread via Communication docs - All migration scripts (51 files) now tracked - Client portal and field tech app added to monorepo - README rewritten with full feature list, migration summary, architecture - CHANGELOG updated with all recent work - ROADMAP updated with current completion status - Removed hardcoded tokens from docs (use $ERP_SERVICE_TOKEN) - .gitignore updated (docker/, .claude/, exports/, .quasar/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
127 lines
3.4 KiB
Python
127 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Nuke all migrated data EXCEPT Users + Items + Item Groups + Subscription Plans.
|
|
Deletes: Customers, Contacts, Addresses, Dynamic Links, Sales Invoices,
|
|
Payment Entries, Subscriptions, Issues, Comments, Communications,
|
|
Journal Entries, and their child tables.
|
|
|
|
Run inside erpnext-backend-1:
|
|
python3 /tmp/nuke_data.py
|
|
"""
|
|
import psycopg2
|
|
from datetime import datetime, timezone
|
|
|
|
PG = {"host": "db", "port": 5432, "user": "postgres", "password": "123",
|
|
"dbname": "_eb65bdc0c4b1b2d6"}
|
|
|
|
def log(msg):
|
|
print("[{}] {}".format(datetime.now(timezone.utc).strftime("%H:%M:%S"), msg), flush=True)
|
|
|
|
def nuke(pgc, table, where=""):
|
|
sql = 'DELETE FROM "{}"'.format(table)
|
|
if where:
|
|
sql += " WHERE " + where
|
|
pgc.execute(sql)
|
|
count = pgc.rowcount
|
|
log(" {} — {} rows deleted".format(table, count))
|
|
return count
|
|
|
|
def main():
|
|
log("=== NUKE migrated data (keep Users + Items) ===")
|
|
|
|
pg = psycopg2.connect(**PG)
|
|
pgc = pg.cursor()
|
|
|
|
# Order matters: child tables first, then parents
|
|
|
|
# 1. Journal Entry child + parent
|
|
log("")
|
|
log("--- Journal Entries ---")
|
|
nuke(pgc, "tabJournal Entry Account")
|
|
nuke(pgc, "tabJournal Entry")
|
|
pg.commit()
|
|
|
|
# 2. Payment Entry child + parent
|
|
log("")
|
|
log("--- Payment Entries ---")
|
|
nuke(pgc, "tabPayment Entry Reference")
|
|
nuke(pgc, "tabPayment Entry")
|
|
pg.commit()
|
|
|
|
# 3. Sales Invoice child + parent
|
|
log("")
|
|
log("--- Sales Invoices ---")
|
|
nuke(pgc, "tabSales Invoice Item")
|
|
nuke(pgc, "tabSales Invoice Payment")
|
|
nuke(pgc, "tabSales Invoice Timesheet")
|
|
nuke(pgc, "tabSales Taxes and Charges", "parent LIKE 'SINV-%' OR parenttype = 'Sales Invoice'")
|
|
nuke(pgc, "tabSales Invoice")
|
|
pg.commit()
|
|
|
|
# 4. Subscriptions child + parent
|
|
log("")
|
|
log("--- Subscriptions ---")
|
|
nuke(pgc, "tabSubscription Plan Detail")
|
|
nuke(pgc, "tabSubscription Invoice")
|
|
nuke(pgc, "tabSubscription")
|
|
pg.commit()
|
|
|
|
# 5. Issues + Communications
|
|
log("")
|
|
log("--- Issues + Communications ---")
|
|
nuke(pgc, "tabCommunication")
|
|
nuke(pgc, "tabCommunication Link")
|
|
nuke(pgc, "tabIssue")
|
|
pg.commit()
|
|
|
|
# 6. Comments (memos imported as comments on Customer)
|
|
log("")
|
|
log("--- Comments ---")
|
|
nuke(pgc, "tabComment", "comment_type = 'Comment' AND reference_doctype = 'Customer'")
|
|
pg.commit()
|
|
|
|
# 7. Contacts + child tables
|
|
log("")
|
|
log("--- Contacts ---")
|
|
nuke(pgc, "tabContact Phone")
|
|
nuke(pgc, "tabContact Email")
|
|
nuke(pgc, "tabContact")
|
|
pg.commit()
|
|
|
|
# 8. Addresses
|
|
log("")
|
|
log("--- Addresses ---")
|
|
nuke(pgc, "tabAddress")
|
|
pg.commit()
|
|
|
|
# 9. Dynamic Links (Contact→Customer, Address→Customer links)
|
|
log("")
|
|
log("--- Dynamic Links ---")
|
|
nuke(pgc, "tabDynamic Link", "link_doctype = 'Customer'")
|
|
pg.commit()
|
|
|
|
# 10. Customers
|
|
log("")
|
|
log("--- Customers ---")
|
|
nuke(pgc, "tabCustomer")
|
|
pg.commit()
|
|
|
|
# 11. Issue Types + Issue Priorities (will be recreated)
|
|
log("")
|
|
log("--- Issue Types + Priorities ---")
|
|
nuke(pgc, "tabIssue Type")
|
|
nuke(pgc, "tabIssue Priority")
|
|
pg.commit()
|
|
|
|
pg.close()
|
|
|
|
log("")
|
|
log("=" * 60)
|
|
log("NUKE COMPLETE")
|
|
log("Kept: Users, Items, Item Groups, Subscription Plans, Accounts")
|
|
log("Next: run migrate_all.py")
|
|
log("=" * 60)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|