fix(nexa_coa_setup): clean GL codes — 119100/119900->115200/115900, 511105->511100
Three odd code positions that were chosen to dodge l10n_ca collisions are
now cleaned up:
- Due From Shareholder 119100 -> 115200 (115xxx is where receivables belong)
- Due From Associated Corps 119900 -> 115900
- Cloud Infrastructure 511105 -> 511100 (legacy 'Inside Purchases'
renamed to 511100.OLD)
Applied to prod via scripts/fix_gl_codes.py (now committed).
Module XML updated: <field name='code'> values match new codes; XMLIDs
(acct_119100, acct_119900, acct_511105) preserved so existing
ir.model.data rows on prod still map to the right records.
pre_init_hook augmented with _L10N_CA_FORCE_CLEAR_CODES set so a fresh
install on a new DB also force-clears 511100 (which would otherwise be
blocked by the postings-exist guard).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,16 +8,20 @@
|
|||||||
|
|
||||||
<!-- NOTE: 115100 is l10n_ca "Customers Account" (240 postings — AR control) — kept as l10n_ca.
|
<!-- NOTE: 115100 is l10n_ca "Customers Account" (240 postings — AR control) — kept as l10n_ca.
|
||||||
115110 is l10n_ca "Customers Account (PoS)" — kept.
|
115110 is l10n_ca "Customers Account (PoS)" — kept.
|
||||||
Nexa intercompany receivables live in the 119xxx range to avoid all collisions. -->
|
Nexa intercompany receivables sit at 115200 / 115900 (freed when their
|
||||||
|
unused l10n_ca defaults — Mortgage Loans — were deleted during install).
|
||||||
|
XMLIDs (acct_119100, acct_119900) preserved from initial install where
|
||||||
|
these accounts were at codes 119100/119900 — codes updated in-place via
|
||||||
|
scripts/fix_gl_codes.py without rewriting ir.model.data. -->
|
||||||
<record id="acct_119100" model="account.account">
|
<record id="acct_119100" model="account.account">
|
||||||
<field name="code">119100</field>
|
<field name="code">115200</field>
|
||||||
<field name="name">Due From Shareholder — Gurpreet</field>
|
<field name="name">Due From Shareholder — Gurpreet</field>
|
||||||
<field name="account_type">asset_current</field>
|
<field name="account_type">asset_current</field>
|
||||||
<field name="reconcile" eval="True"/>
|
<field name="reconcile" eval="True"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="acct_119900" model="account.account">
|
<record id="acct_119900" model="account.account">
|
||||||
<field name="code">119900</field>
|
<field name="code">115900</field>
|
||||||
<field name="name">Due From Associated Corporations</field>
|
<field name="name">Due From Associated Corporations</field>
|
||||||
<field name="account_type">asset_current</field>
|
<field name="account_type">asset_current</field>
|
||||||
<field name="reconcile" eval="True"/>
|
<field name="reconcile" eval="True"/>
|
||||||
@@ -348,10 +352,12 @@
|
|||||||
<!-- 5xxxxx — DIRECT COSTS (COGS) -->
|
<!-- 5xxxxx — DIRECT COSTS (COGS) -->
|
||||||
<!-- ============================================================ -->
|
<!-- ============================================================ -->
|
||||||
|
|
||||||
<!-- NOTE: 511100 was "Inside Purchases" in l10n_ca (1 posting from legacy bookkeeping) — kept as l10n_ca.
|
<!-- NOTE: legacy l10n_ca "Inside Purchases" at 511100 (had 1 historical
|
||||||
Cloud Infrastructure sits at 511105 to avoid collision. -->
|
posting) was renamed to 511100.OLD via scripts/fix_gl_codes.py —
|
||||||
|
Cloud Infrastructure now claims the clean 511100 code. XMLID
|
||||||
|
acct_511105 preserved from initial install. -->
|
||||||
<record id="acct_511105" model="account.account">
|
<record id="acct_511105" model="account.account">
|
||||||
<field name="code">511105</field>
|
<field name="code">511100</field>
|
||||||
<field name="name">Cloud Infrastructure (AWS, Hetzner, OVH, DigitalOcean, Linode)</field>
|
<field name="name">Cloud Infrastructure (AWS, Hetzner, OVH, DigitalOcean, Linode)</field>
|
||||||
<field name="account_type">expense_direct_cost</field>
|
<field name="account_type">expense_direct_cost</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -4,14 +4,12 @@ import logging
|
|||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# l10n_ca account codes that collide with the Nexa CoA design and that
|
# l10n_ca account codes that collide with the Nexa CoA design. Each is
|
||||||
# l10n_ca pre-loads with 'income_other'/'expense'/etc. types we don't want.
|
# checked at pre_init: if it has zero postings we suffix its code with
|
||||||
# Each of these is checked at pre_init: if it has zero postings we suffix
|
# '.OLD' and archive it so our XML can claim the code.
|
||||||
# its code with '.OLD' and archive it so our XML can claim the code.
|
# Codes with postings are LEFT ALONE — we renumbered the Nexa account.
|
||||||
# Codes with postings are LEFT ALONE — we renumbered the Nexa code instead
|
# Currently 115100 stays as l10n_ca 'Customers Account' (240 postings, AR
|
||||||
# (115100 stays as l10n_ca 'Customers Account' AR; Nexa shareholder receivable
|
# control) — Nexa shareholder receivable sits at 115200 instead.
|
||||||
# moved to 119100. 511100 stays as l10n_ca 'Inside Purchases'; Nexa Cloud
|
|
||||||
# Infrastructure moved to 511105).
|
|
||||||
_L10N_CA_COLLISION_CODES = [
|
_L10N_CA_COLLISION_CODES = [
|
||||||
"118100", "118200", "118300",
|
"118100", "118200", "118300",
|
||||||
"213100", "214100",
|
"213100", "214100",
|
||||||
@@ -19,12 +17,18 @@ _L10N_CA_COLLISION_CODES = [
|
|||||||
"311100", "311200", "311300",
|
"311100", "311200", "311300",
|
||||||
"411100", "411200", "411300",
|
"411100", "411200", "411300",
|
||||||
"413100", "413200", "413300",
|
"413100", "413200", "413300",
|
||||||
"511110", "511120", "511130", "511140", "511200", "511210",
|
"511100", "511110", "511120", "511130", "511140", "511200", "511210",
|
||||||
"512100", "512110", "512200",
|
"512100", "512110", "512200",
|
||||||
"611100", "611200", "611300",
|
"611100", "611200", "611300",
|
||||||
"612100", "612200",
|
"612100", "612200",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Codes that MUST be cleared even if they have postings (force-suffix to .OLD).
|
||||||
|
# Use sparingly — historical reports lose the original name. Only for codes
|
||||||
|
# where the Nexa account at that code is the canonical one going forward and
|
||||||
|
# any prior posting is a misclassification the user will re-class later.
|
||||||
|
_L10N_CA_FORCE_CLEAR_CODES = {"511100"}
|
||||||
|
|
||||||
|
|
||||||
def pre_init_hook(env):
|
def pre_init_hook(env):
|
||||||
"""Run BEFORE XML data is loaded. Clear l10n_ca account codes that would
|
"""Run BEFORE XML data is loaded. Clear l10n_ca account codes that would
|
||||||
@@ -47,7 +51,8 @@ def _clear_l10n_ca_collisions(env):
|
|||||||
not_found += 1
|
not_found += 1
|
||||||
continue
|
continue
|
||||||
usage = env["account.move.line"].search_count([("account_id", "=", acc.id)])
|
usage = env["account.move.line"].search_count([("account_id", "=", acc.id)])
|
||||||
if usage > 0:
|
force = code in _L10N_CA_FORCE_CLEAR_CODES
|
||||||
|
if usage > 0 and not force:
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"nexa_coa_setup: keeping l10n_ca account %s (%s) — %d postings exist",
|
"nexa_coa_setup: keeping l10n_ca account %s (%s) — %d postings exist",
|
||||||
code, acc.name, usage,
|
code, acc.name, usage,
|
||||||
@@ -64,6 +69,11 @@ def _clear_l10n_ca_collisions(env):
|
|||||||
"active": False,
|
"active": False,
|
||||||
})
|
})
|
||||||
cleared += 1
|
cleared += 1
|
||||||
|
if force and usage > 0:
|
||||||
|
_logger.info(
|
||||||
|
"nexa_coa_setup: force-cleared %s despite %d postings (in FORCE_CLEAR set)",
|
||||||
|
code, usage,
|
||||||
|
)
|
||||||
_logger.info(
|
_logger.info(
|
||||||
"nexa_coa_setup: collision sweep — cleared %d, kept-with-postings %d, not-found %d",
|
"nexa_coa_setup: collision sweep — cleared %d, kept-with-postings %d, not-found %d",
|
||||||
cleared, kept_with_postings, not_found,
|
cleared, kept_with_postings, not_found,
|
||||||
|
|||||||
40
nexa_coa_setup/scripts/fix_gl_codes.py
Normal file
40
nexa_coa_setup/scripts/fix_gl_codes.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""Renumber a few oddly-coded accounts to cleaner positions.
|
||||||
|
Idempotent — checks before each move."""
|
||||||
|
moves = [
|
||||||
|
# (current_code, target_code, expected_name_substr)
|
||||||
|
('119100', '115200', 'Due From Shareholder'),
|
||||||
|
('119900', '115900', 'Due From Associated Corporations'),
|
||||||
|
]
|
||||||
|
print(">>> Easy renames (no postings)")
|
||||||
|
for old, new, name_hint in moves:
|
||||||
|
acc = env['account.account'].search([('code', '=', old)], limit=1)
|
||||||
|
if not acc:
|
||||||
|
print(f"SKIP {old}: not found")
|
||||||
|
continue
|
||||||
|
if name_hint.lower() not in (acc.name or '').lower():
|
||||||
|
print(f"SKIP {old}: name doesn't match expected '{name_hint}' (got '{acc.name}')")
|
||||||
|
continue
|
||||||
|
conflict = env['account.account'].with_context(active_test=False).search([('code', '=', new)], limit=1)
|
||||||
|
if conflict:
|
||||||
|
print(f"SKIP {old}->{new}: target code occupied by {conflict.name}")
|
||||||
|
continue
|
||||||
|
acc.code = new
|
||||||
|
print(f"OK {old} -> {new}: {acc.name}")
|
||||||
|
|
||||||
|
# The 511100 swap — rename legacy first, then renumber ours
|
||||||
|
print(">>> 511105 -> 511100 swap")
|
||||||
|
legacy = env['account.account'].with_context(active_test=False).search([('code', '=', '511100'), ('name', 'ilike', 'inside purchases')], limit=1)
|
||||||
|
ours = env['account.account'].search([('code', '=', '511105'), ('name', 'ilike', 'cloud infrastructure')], limit=1)
|
||||||
|
if not legacy:
|
||||||
|
print("legacy 511100 not found (already moved?)")
|
||||||
|
elif not ours:
|
||||||
|
print("our 511105 not found (already renamed?)")
|
||||||
|
else:
|
||||||
|
# Rename legacy first to free the code
|
||||||
|
legacy.write({'code': '511100.OLD', 'name': f"(l10n_ca LEGACY) {legacy.name}", 'active': False})
|
||||||
|
ours.code = '511100'
|
||||||
|
print(f"OK legacy 511100 -> 511100.OLD ({legacy.name})")
|
||||||
|
print(f"OK 511105 -> 511100 ({ours.name})")
|
||||||
|
|
||||||
|
env.cr.commit()
|
||||||
|
print(">>> done <<<")
|
||||||
Reference in New Issue
Block a user