diff --git a/nexa_coa_setup/scripts/reclass_historical_411000.py b/nexa_coa_setup/scripts/reclass_historical_411000.py new file mode 100644 index 00000000..09989eda --- /dev/null +++ b/nexa_coa_setup/scripts/reclass_historical_411000.py @@ -0,0 +1,62 @@ +"""Reclassify all 200 lines on legacy 411000 to proper Nexa accounts based on +keyword rules. Run on prod via odoo-shell.""" + +acct_4030 = env['account.account'].search([('code', '=', '4030')], limit=1).id # Support & Maintenance +acct_4230 = env['account.account'].search([('code', '=', '4230')], limit=1).id # Tech Support hourly +acct_4320 = env['account.account'].search([('code', '=', '4320')], limit=1).id # Hardware Resale +legacy_acct = env['account.account'].with_context(active_test=False).search([('code', '=', '411000')], limit=1).id + +# (priority, regex pattern (case-insensitive), target_account_id, label) +import re +RULES = [ + ('Computer & Server Maintenance', acct_4030, 'Support & Maintenance'), + ('Server Backup & Monitoring', acct_4030, 'Support & Maintenance'), + ('Membership Fee', acct_4030, 'Support & Maintenance (membership)'), + ('[CUSTCOMP]', acct_4320, 'Hardware Resale (custom PC)'), + ('Custom Computer', acct_4320, 'Hardware Resale (custom PC)'), + ('ustom Computer', acct_4320, 'Hardware Resale (typo'), # the 'ustom Computer' typo entry + ('HP Desk Computer', acct_4320, 'Hardware Resale (HP desktop)'), + ('Server 2019', acct_4320, 'Hardware Resale (Windows Server license)'), + ('Server Rack', acct_4320, 'Hardware Resale (rack)'), + ('16 Port POE', acct_4320, 'Hardware Resale (switch)'), + ('CPU:', acct_4320, 'Hardware Resale (custom build)'), + ('Cleaning Supplies', acct_4320, 'Hardware Resale (consumables)'), + ('ONSITE-', acct_4230, 'Tech Support — onsite'), + ('OFFSITE-', acct_4230, 'Tech Support — offsite'), + ('Onsite Sever Setup', acct_4230, 'Tech Support — setup'), + ('Server Setup', acct_4230, 'Tech Support — setup'), + ('Wiring for', acct_4230, 'Tech Support — installation'), +] + +# Find all lines on 411000 +env.cr.execute(""" + SELECT aml.id, aml.name, aml.credit + FROM account_move_line aml + JOIN account_move m ON m.id = aml.move_id + WHERE aml.account_id = %s AND m.move_type = 'out_invoice' +""", (legacy_acct,)) +lines = env.cr.fetchall() + +bucket = {acct_4030: 0, acct_4230: 0, acct_4320: 0} +unmatched = [] +for line_id, line_name, credit in lines: + name = (line_name or '').strip() + matched = False + for pattern, target, label in RULES: + if pattern.lower() in name.lower(): + env.cr.execute("UPDATE account_move_line SET account_id = %s WHERE id = %s", + (target, line_id)) + bucket[target] += 1 + matched = True + break + if not matched: + unmatched.append((line_id, name[:60], credit)) + +print(f"Reclassified {bucket[acct_4030]} lines -> 4030 Support & Maintenance") +print(f"Reclassified {bucket[acct_4230]} lines -> 4230 Tech Support — Hourly") +print(f"Reclassified {bucket[acct_4320]} lines -> 4320 Hardware Resale") +print(f"Unmatched: {len(unmatched)}") +for u in unmatched[:20]: + print(f" id={u[0]} amount={u[2]} name={u[1]!r}") +env.cr.commit() +print(">>> done <<<")