diff --git a/nexa_coa_setup/data/01_account_account.xml b/nexa_coa_setup/data/01_account_account.xml
index 9325387a..0125aae2 100644
--- a/nexa_coa_setup/data/01_account_account.xml
+++ b/nexa_coa_setup/data/01_account_account.xml
@@ -14,99 +14,99 @@
these accounts were at codes 119100/119900 — codes updated in-place via
scripts/fix_gl_codes.py without rewriting ir.model.data. -->
- 115200
+ 1120
Due From Shareholder — Gurpreet
asset_current
- 115900
+ 1130
Due From Associated Corporations
asset_current
- 118100
+ 1210
HST/GST Input Tax Credit (ITC) Receivable
asset_current
- 118200
+ 1220
HST/GST Instalments Paid
asset_current
- 118300
+ 1230
QST Input Tax Refund Receivable
asset_current
- 151100
+ 1510
Computer Hardware & Equipment (CCA Class 50)
asset_fixed
- 151200
+ 1520
Office Furniture & Equipment (CCA Class 8)
asset_fixed
- 151300
+ 1530
Vehicles (CCA Class 10/10.1)
asset_fixed
- 151400
+ 1540
Leasehold Improvements (CCA Class 13)
asset_fixed
- 151500
+ 1550
Acquired Software & Intangibles (CCA Class 14.1)
asset_fixed
- 151600
+ 1560
Tools & Small Equipment <$500 (CCA Class 12)
asset_fixed
- 154100
+ 1710
Acc. Depreciation — Computer Hardware
asset_fixed
- 154200
+ 1720
Acc. Depreciation — Office Furniture
asset_fixed
- 154300
+ 1730
Acc. Depreciation — Vehicles
asset_fixed
- 154400
+ 1740
Acc. Depreciation — Leasehold Improvements
asset_fixed
- 154500
+ 1750
Acc. Depreciation — Acquired Software
asset_fixed
@@ -116,75 +116,75 @@
- 213100
+ 2110
HST/GST Collected on Sales
liability_current
- 213500
+ 2120
QST Collected on Sales
liability_current
- 214100
+ 2130
Net HST/GST Payable
liability_current
- 215100
+ 2210
Source Deductions Payable — Federal Tax
liability_current
- 215200
+ 2220
Source Deductions Payable — CPP
liability_current
- 215300
+ 2230
Source Deductions Payable — EI
liability_current
- 216100
+ 2310
Corporate Income Tax — Federal Payable
liability_current
- 216200
+ 2320
Corporate Income Tax — Provincial Payable
liability_current
- 216300
+ 2330
Corporate Tax Instalments Paid
asset_current
- 221100
+ 2510
Due To Shareholder — Gurpreet (short-term)
liability_current
- 221200
+ 2520
Shareholder Loan — Gurpreet (long-term)
liability_non_current
- 222900
+ 2590
Due To Associated Corporations
liability_current
@@ -195,37 +195,37 @@
- 311100
+ 3010
Share Capital — Common Shares
equity
- 311200
+ 3020
Share Capital — Preferred Shares
equity
- 311300
+ 3030
Contributed Surplus
equity
- 321100
+ 3510
Retained Earnings — Current Year
equity
- 321200
+ 3520
Retained Earnings — Prior Years
equity
- 321900
+ 3590
Dividends Declared
equity
@@ -235,115 +235,115 @@
- 411100
+ 4010
SaaS Subscription Revenue
income
- 411200
+ 4020
Hosting & Infrastructure Revenue
income
- 411300
+ 4030
Support & Maintenance Contracts Revenue
income
- 411400
+ 4040
Domain/SSL/Renewal Pass-through Revenue
income
- 411500
+ 4050
Setup / Onboarding Fees Revenue
income
- 412100
+ 4110
Custom Software Development Revenue
income
- 412200
+ 4120
Custom Web Application Development Revenue
income
- 412300
+ 4130
Custom Website Development Revenue
income
- 412400
+ 4140
ERP Implementation & Customization Revenue
income
- 412500
+ 4150
Mobile App Development Revenue
income
- 412600
+ 4160
Business App / Integration Revenue
income
- 413100
+ 4210
Consulting & Advisory Revenue
income
- 413200
+ 4220
Training & Workshops Revenue
income
- 413300
+ 4230
Technical Support — Per-incident / Hourly Revenue
income
- 414100
+ 4310
Third-party Software Resale Revenue
income
- 414200
+ 4320
Hardware Resale Revenue
income
- 419100
+ 4910
Sales Discounts
income
- 419200
+ 4920
Sales Returns & Refunds
income
- 419300
+ 4930
Bad Debt Recovery
income_other
@@ -357,103 +357,103 @@
Cloud Infrastructure now claims the clean 511100 code. XMLID
acct_511105 preserved from initial install. -->
- 511100
+ 5010
Cloud Infrastructure (AWS, Hetzner, OVH, DigitalOcean, Linode)
expense_direct_cost
- 511110
+ 5020
CDN & Edge Services (Cloudflare, Fastly)
expense_direct_cost
- 511120
+ 5030
Backup & Storage Services
expense_direct_cost
- 511130
+ 5040
Database & Backend Services (Supabase, hosted Postgres, Redis)
expense_direct_cost
- 511140
+ 5050
Monitoring & Observability (customer-facing only)
expense_direct_cost
- 511150
+ 5060
SSL Certificates & Domains (wholesale for resale)
expense_direct_cost
- 511160
+ 5070
DNS & Email Hosting (wholesale for resale)
expense_direct_cost
- 511200
+ 5110
Third-party API Costs (Twilio, SendGrid, OpenAI)
expense_direct_cost
- 511210
+ 5120
Per-customer Licensing & Royalties
expense_direct_cost
- 512100
+ 5210
Subcontracted Labour — Canadian (T4A) — SR&ED-eligible
expense_direct_cost
- 512110
+ 5220
Subcontracted Labour — Foreign — NOT SR&ED-eligible
expense_direct_cost
- 512200
+ 5230
Project-specific Software & Licenses
expense_direct_cost
- 512300
+ 5240
Project Travel & Onsite (rebilled)
expense_direct_cost
- 512400
+ 5250
Project Hardware (passed through)
expense_direct_cost
- 513100
+ 5310
Cost of Software Resold
expense_direct_cost
- 513200
+ 5320
Cost of Hardware Resold
expense_direct_cost
- 519100
+ 5910
COGS Adjustments / Write-offs
expense_direct_cost
@@ -463,349 +463,349 @@
- 611100
+ 6010
Salaries & Wages — Development (SR&ED-eligible)
expense
- 611200
+ 6020
Salaries & Wages — Sales & Marketing
expense
- 611300
+ 6030
Salaries & Wages — Admin & Operations
expense
- 611400
+ 6040
Salary — Shareholder/Officer (Gurpreet)
expense
- 611500
+ 6050
Employer CPP / QPP Contributions
expense
- 611600
+ 6060
Employer EI Premiums
expense
- 611700
+ 6070
Employer Health Tax (EHT/QHST)
expense
- 611800
+ 6080
WCB / WSIB Premiums
expense
- 611900
+ 6090
Employee Benefits (health, dental, group)
expense
- 611950
+ 6091
Bonuses & Incentives
expense
- 611960
+ 6092
Vacation Pay Accrual
expense
- 612100
+ 6110
Contract Labour — Canadian (admin/marketing/freelance)
expense
- 612200
+ 6120
Contract Labour — Foreign
expense
- 621100
+ 6210
Rent — Commercial Office
expense
- 621200
+ 6220
Home Office — Business Portion
expense
- 621300
+ 6230
Utilities — Commercial
expense
- 621400
+ 6240
Internet & Phone — Business
expense
- 621500
+ 6250
Office Supplies & Consumables
expense
- 621600
+ 6260
Cleaning & Maintenance
expense
- 621700
+ 6270
Office Snacks & Refreshments
expense
- 631100
+ 6310
Software — Productivity (M365, Slack, Notion, Linear, GitHub)
expense
- 631200
+ 6320
Software — Development Tools (Cursor, Figma, IDEs)
expense
- 631300
+ 6330
Software — Internal Infrastructure
expense
- 631400
+ 6340
Software — Security & IT
expense
- 631500
+ 6350
Software — Sales & Marketing
expense
- 641100
+ 6410
Advertising — Digital Ads
expense
- 641200
+ 6420
Advertising — Content / SEO
expense
- 641300
+ 6430
Trade Shows & Conferences
expense
- 641400
+ 6440
Promotional Items / Branded Swag
expense
- 641500
+ 6450
Website — Own (nexasystems.ca)
expense
- 651100
+ 6510
Legal Fees — General
expense
- 651200
+ 6520
Accounting & Bookkeeping
expense
- 651300
+ 6530
Tax Preparation (T2, T1, GST/HST)
expense
- 651400
+ 6540
Business Consulting
expense
- 661100
+ 6610
Insurance — Commercial General Liability
expense
- 661200
+ 6620
Insurance — Professional Liability / E&O
expense
- 661300
+ 6630
Insurance — Cyber Liability
expense
- 661400
+ 6640
Insurance — Property
expense
- 661500
+ 6650
Insurance — Directors & Officers
expense
- 671100
+ 6710
Travel — Flights, Hotels, Ground Transport
expense
- 671200
+ 6720
Meals & Entertainment — 50% Deductible
expense
- 671300
+ 6730
Vehicle — Operating (gas, insurance, repairs, parking)
expense
- 671400
+ 6740
Mileage Reimbursement — Personal Vehicle
expense
- 681100
+ 6810
Conferences & Seminars (registration)
expense
- 681200
+ 6820
Courses & Certifications
expense
- 681300
+ 6830
Books & Publications
expense
- 681400
+ 6840
Professional Memberships & Dues
expense
- 691100
+ 6910
Bank Service Charges
expense
- 691200
+ 6920
Merchant Processing Fees (Stripe, PayPal, Square)
expense
- 691300
+ 6930
Wire Transfer & FX Fees
expense
- 691400
+ 6940
Interest Expense — Bank Loans / LOC
expense
- 691500
+ 6950
Interest Expense — Credit Cards
expense
- 691600
+ 6960
Late Payment Penalties — Non-deductible
expense
- 699100
+ 7010
Bad Debt Expense
expense
- 699200
+ 7020
Donations & Sponsorships (deductible)
expense
- 699300
+ 7030
Penalties & Fines — Non-deductible
expense
- 699400
+ 7040
Realized FX Losses
expense
- 699500
+ 7050
Depreciation / CCA Expense
expense
diff --git a/nexa_coa_setup/hooks.py b/nexa_coa_setup/hooks.py
index 7554c885..2a562911 100644
--- a/nexa_coa_setup/hooks.py
+++ b/nexa_coa_setup/hooks.py
@@ -232,18 +232,18 @@ def _delete_unused_accounts(env):
# at the new accounts, so when an invoice creates tax journal items they hit
# 118100 (ITC) and 213100 (HST collected) instead of the archived legacy ones.
_TAX_REPARTITION_REMAP = {
- # ITC / receivable side
- "118100.OLD": "118100",
- "118200.OLD": "118300", # PST/QST receivable → QST refund receivable
- "118300.OLD": "118100",
- "118400": "118100", # 14% HST receivable
- "118500": "118100", # 15% HST receivable
- # Payable / collected side
- "231000": "213100", # GST to pay
- "232000": "213500", # PST/QST to pay
- "233000": "213100", # HST 13% to pay
- "234000": "213100", # HST 14% to pay
- "235000": "213100", # HST 15% to pay
+ # ITC / receivable side → Nexa 1210 HST/GST ITC Receivable (or 1230 QST refund)
+ "118100.OLD": "1210",
+ "118200.OLD": "1230",
+ "118300.OLD": "1210",
+ "118400": "1210",
+ "118500": "1210",
+ # Payable / collected side → Nexa 2110 HST/GST Collected (or 2120 QST collected)
+ "231000": "2110",
+ "232000": "2120",
+ "233000": "2110",
+ "234000": "2110",
+ "235000": "2110",
}
@@ -483,20 +483,20 @@ def _archive_unused_l10n_ca_accounts(env):
# accountant-driven reconciliation.
_LEGACY_RENAMES = [
# (code, new_name, archive_after)
- ("1400", "(LEGACY) Transferred to Gurpreet — re-class to 221100", True),
- ("1505", "(LEGACY) Sent to India — re-class to 612200", True),
+ ("1400", "(LEGACY) Transferred to Gurpreet — re-class to 2510", True),
+ ("1505", "(LEGACY) Sent to India — re-class to 6120", True),
("1580", "(LEGACY) Transferred to Westin — Westin is now a partner", True),
("1590", "(LEGACY) Transferred to Divine — Divine is now a partner", True),
("1600", "(LEGACY) Transferred to Manpreet — non-related; archive", True),
- ("1500", "(LEGACY) Food & Entertainment — re-class to 671200", True),
- ("1501", "(LEGACY) Office Expenses — re-class to 621500", True),
- ("411000", "(LEGACY) Inside Sales — re-class to 412xxx specific lines", True),
+ ("1500", "(LEGACY) Food & Entertainment — re-class to 6720", True),
+ ("1501", "(LEGACY) Office Expenses — re-class to 6250", True),
+ ("411000", "(LEGACY) Inside Sales — re-class to 4xxx specific lines", True),
("412000", "(LEGACY) Harmonized Provinces Sales — handled by tax codes", True),
("413000", "(LEGACY) Non-Harmonized Provinces Sales — handled by tax", True),
("414000", "(LEGACY) International Sales — handled by Zero-rated Export", True),
("12000", "(LEGACY) Abdul & Future Mobility — use partner subledger", True),
("12001", "(LEGACY) MSI Account — use partner subledger", True),
- ("110010", "(LEGACY) Bank Fee — re-class to 691100", True),
+ ("110010", "(LEGACY) Bank Fee — re-class to 6910", True),
]
diff --git a/nexa_coa_setup/scripts/convert_to_4digit.py b/nexa_coa_setup/scripts/convert_to_4digit.py
new file mode 100644
index 00000000..50de14bf
--- /dev/null
+++ b/nexa_coa_setup/scripts/convert_to_4digit.py
@@ -0,0 +1,171 @@
+"""Map current Nexa CoA codes (6-digit) to a clean 4-digit scheme.
+Run on prod via odoo-shell. Updates account_account.code in place."""
+
+# (current_code, new_code, expected_name_substring_for_safety)
+CODE_MAP = [
+ # 1xxx ASSETS
+ ("115200", "1120", "Due From Shareholder"),
+ ("115900", "1130", "Due From Associated Corporations"),
+ ("118100", "1210", "Input Tax Credit"),
+ ("118200", "1220", "Instalments Paid"),
+ ("118300", "1230", "QST Input Tax Refund"),
+ ("151100", "1510", "Computer Hardware"),
+ ("151200", "1520", "Office Furniture"),
+ ("151300", "1530", "Vehicles"),
+ ("151400", "1540", "Leasehold Improvements"),
+ ("151500", "1550", "Acquired Software"),
+ ("151600", "1560", "Tools"),
+ ("154100", "1710", "Acc. Depreciation — Computer"),
+ ("154200", "1720", "Acc. Depreciation — Office"),
+ ("154300", "1730", "Acc. Depreciation — Vehicles"),
+ ("154400", "1740", "Acc. Depreciation — Leasehold"),
+ ("154500", "1750", "Acc. Depreciation — Acquired"),
+
+ # 2xxx LIABILITIES
+ ("213100", "2110", "HST/GST Collected"),
+ ("213500", "2120", "QST Collected"),
+ ("214100", "2130", "Net HST/GST Payable"),
+ ("215100", "2210", "Source Deductions Payable — Federal"),
+ ("215200", "2220", "Source Deductions Payable — CPP"),
+ ("215300", "2230", "Source Deductions Payable — EI"),
+ ("216100", "2310", "Federal Payable"),
+ ("216200", "2320", "Provincial Payable"),
+ ("216300", "2330", "Tax Instalments Paid"),
+ ("221100", "2510", "Due To Shareholder"),
+ ("221200", "2520", "Shareholder Loan"),
+ ("222900", "2590", "Due To Associated Corporations"),
+
+ # 3xxx EQUITY
+ ("311100", "3010", "Common Shares"),
+ ("311200", "3020", "Preferred Shares"),
+ ("311300", "3030", "Contributed Surplus"),
+ ("321100", "3510", "Retained Earnings — Current"),
+ ("321200", "3520", "Retained Earnings — Prior"),
+ ("321900", "3590", "Dividends Declared"),
+
+ # 4xxx REVENUE
+ ("411100", "4010", "SaaS Subscription"),
+ ("411200", "4020", "Hosting"),
+ ("411300", "4030", "Support"),
+ ("411400", "4040", "Domain/SSL"),
+ ("411500", "4050", "Setup"),
+ ("412100", "4110", "Custom Software Development"),
+ ("412200", "4120", "Custom Web Application"),
+ ("412300", "4130", "Custom Website"),
+ ("412400", "4140", "ERP Implementation"),
+ ("412500", "4150", "Mobile App"),
+ ("412600", "4160", "Business App"),
+ ("413100", "4210", "Consulting"),
+ ("413200", "4220", "Training"),
+ ("413300", "4230", "Technical Support — Per-incident"),
+ ("414100", "4310", "Third-party Software Resale"),
+ ("414200", "4320", "Hardware Resale"),
+ ("419100", "4910", "Sales Discounts"),
+ ("419200", "4920", "Sales Returns"),
+ ("419300", "4930", "Bad Debt Recovery"),
+
+ # 5xxx COGS
+ ("511100", "5010", "Cloud Infrastructure"),
+ ("511110", "5020", "CDN"),
+ ("511120", "5030", "Backup"),
+ ("511130", "5040", "Database"),
+ ("511140", "5050", "Monitoring"),
+ ("511150", "5060", "SSL"),
+ ("511160", "5070", "DNS"),
+ ("511200", "5110", "Third-party API"),
+ ("511210", "5120", "Per-customer Licensing"),
+ ("512100", "5210", "Subcontracted Labour — Canadian"),
+ ("512110", "5220", "Subcontracted Labour — Foreign"),
+ ("512200", "5230", "Project-specific Software"),
+ ("512300", "5240", "Project Travel"),
+ ("512400", "5250", "Project Hardware"),
+ ("513100", "5310", "Cost of Software Resold"),
+ ("513200", "5320", "Cost of Hardware Resold"),
+ ("519100", "5910", "COGS Adjustments"),
+
+ # 6xxx OPERATING EXPENSES
+ ("611100", "6010", "Salaries & Wages — Development"),
+ ("611200", "6020", "Salaries & Wages — Sales"),
+ ("611300", "6030", "Salaries & Wages — Admin"),
+ ("611400", "6040", "Salary — Shareholder"),
+ ("611500", "6050", "Employer CPP"),
+ ("611600", "6060", "Employer EI"),
+ ("611700", "6070", "Employer Health Tax"),
+ ("611800", "6080", "WCB"),
+ ("611900", "6090", "Employee Benefits"),
+ ("611950", "6091", "Bonuses"),
+ ("611960", "6092", "Vacation Pay"),
+ ("612100", "6110", "Contract Labour — Canadian"),
+ ("612200", "6120", "Contract Labour — Foreign"),
+ ("621100", "6210", "Rent"),
+ ("621200", "6220", "Home Office"),
+ ("621300", "6230", "Utilities"),
+ ("621400", "6240", "Internet"),
+ ("621500", "6250", "Office Supplies"),
+ ("621600", "6260", "Cleaning"),
+ ("621700", "6270", "Office Snacks"),
+ ("631100", "6310", "Software — Productivity"),
+ ("631200", "6320", "Software — Development Tools"),
+ ("631300", "6330", "Software — Internal Infrastructure"),
+ ("631400", "6340", "Software — Security"),
+ ("631500", "6350", "Software — Sales"),
+ ("641100", "6410", "Advertising — Digital"),
+ ("641200", "6420", "Advertising — Content"),
+ ("641300", "6430", "Trade Shows"),
+ ("641400", "6440", "Promotional"),
+ ("641500", "6450", "Website — Own"),
+ ("651100", "6510", "Legal Fees"),
+ ("651200", "6520", "Accounting"),
+ ("651300", "6530", "Tax Preparation"),
+ ("651400", "6540", "Business Consulting"),
+ ("661100", "6610", "Insurance — Commercial General"),
+ ("661200", "6620", "Insurance — Professional Liability"),
+ ("661300", "6630", "Insurance — Cyber"),
+ ("661400", "6640", "Insurance — Property"),
+ ("661500", "6650", "Insurance — Directors"),
+ ("671100", "6710", "Travel"),
+ ("671200", "6720", "Meals"),
+ ("671300", "6730", "Vehicle — Operating"),
+ ("671400", "6740", "Mileage"),
+ ("681100", "6810", "Conferences"),
+ ("681200", "6820", "Courses"),
+ ("681300", "6830", "Books"),
+ ("681400", "6840", "Professional Memberships"),
+ ("691100", "6910", "Bank Service Charges"),
+ ("691200", "6920", "Merchant Processing"),
+ ("691300", "6930", "Wire Transfer"),
+ ("691400", "6940", "Interest Expense — Bank"),
+ ("691500", "6950", "Interest Expense — Credit Cards"),
+ ("691600", "6960", "Late Payment Penalties"),
+
+ # 7xxx OTHER (was 699xxx)
+ ("699100", "7010", "Bad Debt Expense"),
+ ("699200", "7020", "Donations"),
+ ("699300", "7030", "Penalties & Fines"),
+ ("699400", "7040", "Realized FX Losses"),
+ ("699500", "7050", "Depreciation"),
+]
+
+ok = 0
+skipped = 0
+missing = 0
+for old_code, new_code, expected_name_part in CODE_MAP:
+ acc = env['account.account'].search([('code', '=', old_code)], limit=1)
+ if not acc:
+ print(f"MISS {old_code} → {new_code}: not found")
+ missing += 1
+ continue
+ if expected_name_part.lower() not in (acc.name or '').lower():
+ print(f"SKIP {old_code} → {new_code}: name '{acc.name}' doesn't contain '{expected_name_part}'")
+ skipped += 1
+ continue
+ # Check target code is free
+ conflict = env['account.account'].with_context(active_test=False).search([('code', '=', new_code)], limit=1)
+ if conflict:
+ print(f"SKIP {old_code} → {new_code}: target occupied by {conflict.name}")
+ skipped += 1
+ continue
+ acc.code = new_code
+ ok += 1
+print(f">>> Renumbered {ok}, skipped {skipped}, missing {missing} of {len(CODE_MAP)}")
+env.cr.commit()