docs(nexa_coa_setup): comprehensive operating runbook

Expands README into a full ops guide covering:
- Chart of accounts at a glance (4-digit ranges + examples)
- Standard products catalog with SKUs and income routing
- Fiscal positions with auto-detect rules
- Three analytic plans + their tag conventions
- Install / update / deploy / restore commands
- Yearly close calendar (HST Mar 31, T2 Jun 30, SR&ED prep timeline)
- Common tasks (add account, add product, add analytic, lock FY,
  reclassify invoice, pull SR&ED data)
- Compliance flags (associated-corp SBD sharing, s.15(2) loans,
  transfer pricing, HST cadence triggers, specified-employee SR&ED cap)
- Implementation scripts table (audit reference)
- Open items checklist for future manual follow-ups

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsinghpal
2026-05-12 20:52:18 -04:00
parent 0e595e6129
commit 2737bc481c

View File

@@ -1,26 +1,261 @@
# Nexa Systems — Chart of Accounts Setup # Nexa Systems — Chart of Accounts Setup
Custom Odoo 19 module that configures the chart of accounts, taxes, Odoo 19 module that installs and maintains Nexa Systems Inc's chart of
fiscal positions, analytic plans, and partner records for Nexa Systems Inc. accounts, taxes, fiscal positions, analytic plans, partner records, and
seeded standard products.
## Install - **Design reference**: `docs/superpowers/specs/2026-05-12-nexa-coa-design.md`
- **Implementation plan**: `docs/superpowers/plans/2026-05-12-nexa-coa-setup.md`
- **Target**: odoo-nexa (192.168.1.111), database `nexamain`
``` ---
docker exec odoo-nexa-app odoo -c /etc/odoo/odoo.conf -d nexamain \
-i nexa_coa_setup --no-http --stop-after-init ## Chart of accounts at a glance
| Range | Purpose | Examples |
|---|---|---|
| `1010-1090` | Cash & bank | 1010 Scotia 9309, 1030 BMO, 1040 RBC, 1070 Scotia CC, 1090 Suspense |
| `1100-1130` | Accounts receivable | 1100 Customers, 1120 Due From Shareholder, 1130 Due From Associated Corps |
| `1210-1230` | Tax assets | 1210 HST/GST ITC Receivable, 1220 Instalments, 1230 QST Refund |
| `1510-1750` | Capital assets + accumulated depreciation | 1510 Computers (CCA 50), 1550 Software (CCA 14.1) |
| `2010-2130` | Trade AP + sales tax | 2010 Vendors, 2110 HST Collected, 2120 QST Collected, 2130 Net Payable |
| `2210-2330` | Payroll + corporate tax payable | 2210 Fed Tax W/H, 2220 CPP, 2230 EI |
| `2510-2590` | Shareholder + intercompany | 2510 Due To Shareholder, 2520 Long-term Loan, 2590 Due To Associated |
| `3010-3590` | Equity + retained earnings | 3010 Common Shares, 3510 RE Current Year, 3590 Dividends Declared |
| `4010-4050` | Recurring revenue | 4010 SaaS, 4020 Hosting, 4030 Support, 4040 Domain Pass-through, 4050 Setup |
| `4110-4160` | Project revenue | 4110 Custom Software, 4120 Web App, 4130 Website, 4140 ERP, 4150 Mobile |
| `4210-4230` | Services revenue (hourly) | 4210 Consulting, 4220 Training, 4230 Tech Support |
| `4310-4320` | Reseller revenue | 4310 Software resale, 4320 Hardware resale |
| `4910-4930` | Revenue adjustments | 4910 Discounts, 4920 Returns, 4930 Bad Debt Recovery |
| `5010-5910` | Direct costs (COGS) | 5010 Cloud Infrastructure, 5210 Sub Labour CA (SR&ED-eligible) |
| `6010-6092` | Personnel — T4 employees | 6010 Dev salaries (SR&ED proxy base), 6040 Owner salary |
| `6110-6120` | Contract labour (non-project) | 6110 Canadian, 6120 Foreign |
| `6210-6270` | Office & facilities | 6210 Rent, 6220 Home Office, 6240 Internet & Phone |
| `6310-6350` | Software subs (internal) | 6310 Productivity, 6320 Dev Tools, 6340 Security |
| `6410-6450` | Marketing & sales | 6410 Digital Ads, 6450 Own Website |
| `6510-6540` | Professional fees | 6510 Legal, 6520 Accounting, 6530 Tax Prep |
| `6610-6650` | Insurance | 6620 Professional Liability / E&O, 6630 Cyber |
| `6710-6740` | Travel & entertainment | 6710 Travel, 6720 M&E (50% deductible) |
| `6810-6840` | Training & development | |
| `6910-6960` | Banking & finance | 6910 Bank fees, 6920 Stripe/merchant, 6960 Late penalties (non-deductible) |
| `7010-7050` | Other | 7010 Bad Debt, 7020 Donations, 7030 Fines (non-deductible), 7050 Depreciation |
---
## Standard products (seeded)
All 14 starter products auto-route to the right income account via their
category. Use as-is, duplicate to create variants, or override prices per
customer/quote.
| SKU | Description | Default | Income → |
|---|---|---|---|
| `SAAS-BASIC` | SaaS Subscription — Basic | per-customer | 4010 |
| `HOST-S/M/L` | Hosting Small/Medium/Large | $49/$149/$299 mo | 4020 |
| `SUPPORT-RET` | Support Retainer (4 hrs/mo) | $640 mo | 4030 |
| `SETUP-FEE` | Setup / Onboarding Fee | $500 | 4050 |
| `DEV-SOFTWARE` | Custom Software Dev | $160 / hr | 4110 |
| `DEV-WEBAPP` | Custom Web App Dev | $160 / hr | 4120 |
| `DEV-WEBSITE` | Custom Website Dev | $160 / hr | 4130 |
| `ERP-IMPL` | ERP Implementation | $175 / hr | 4140 |
| `CONSULT` | Consulting & Advisory | $200 / hr | 4210 |
| `TRAINING` | Training & Workshop | $120 / hr | 4220 |
| `TECH-SUPPORT` | Technical Support — Hourly | $160 / hr | 4230 |
| `RESALE-SW` | Software License (template) | per-quote | 4310 |
Product file uses `noupdate=1` so your price/description edits persist
across module updates.
---
## Fiscal positions (automatic tax handling)
Tax routing is determined by customer billing address — you don't pick
the tax manually on invoices.
| Position | Auto-applies to | Sales tax |
|---|---|---|
| CA — Ontario (Default) | ON customers | 13% HST |
| CA — Atlantic | NB, NS, PE, NL | 15% HST |
| CA — Quebec | QC | 5% GST + 9.975% QST |
| CA — BC | BC | 5% GST (PST handled per-product if applicable) |
| CA — Prairies / Territories | AB, MB, SK, YT, NT, NU | 5% GST |
| Export — US | All US customers | 0% (Zero-rated) |
| Export — International | Manual | 0% (Zero-rated) |
| Tax Exempt | Manual (cert-holders) | 0% |
---
## Analytic plans
Three orthogonal tagging plans on every transaction:
| Plan | Tags | Used for |
|---|---|---|
| **Customer Project** | One per engagement (e.g. `PRJ-2026-WESTIN-ERP`) | Project P&L, billable-hour realization, WIP |
| **Department** | DEPT-DEV, DEPT-SALES, DEPT-ADMIN, DEPT-HOSTING | Cost allocation, departmental P&L |
| **SR&ED Tag** | SRED-T4-DEV-SALARY, SRED-SPECIFIED-EMPLOYEE, SRED-CONTRACTOR-CA-ARM-LENGTH, SRED-CONTRACTOR-CA-NON-ARM-LENGTH, SRED-MATERIALS-CONSUMED, SRED-OVERHEAD-PROXY-BASIS, NOT-ELIGIBLE | T661 SR&ED filing |
---
## Install / update
**Always pg_dump first.**
```bash
ssh odoo-nexa "STAMP=\$(date +%Y%m%d_%H%M%S) && \
docker exec odoo-nexa-db pg_dump -U odoo -d nexamain -F c -Z 9 \
> /tmp/nexamain_\${STAMP}.dump"
scp odoo-nexa:/tmp/nexamain_*.dump ~/Backups/odoo-nexa/
``` ```
## Update **Deploy module changes** (Mac → server; rsync isn't available, use tar):
``` ```bash
docker exec odoo-nexa-app odoo -c /etc/odoo/odoo.conf -d nexamain \ cd /Users/gurpreet/Github/Odoo-Modules && \
-u nexa_coa_setup --no-http --stop-after-init tar czf - nexa_coa_setup | \
ssh odoo-nexa "cd /opt/odoo/custom-addons && \
sudo rm -rf nexa_coa_setup && sudo tar xzf - && \
sudo chown -R 1000:1000 nexa_coa_setup"
``` ```
## Design reference **Install (first time on a database)**:
See `docs/superpowers/specs/2026-05-12-nexa-coa-design.md`. ```bash
ssh odoo-nexa "docker exec odoo-nexa-app odoo -c /etc/odoo/odoo.conf \
-d nexamain -i nexa_coa_setup --no-http --stop-after-init"
```
## Safety **Update (after editing XML or hooks)**:
Always take a pg_dump BEFORE running `-i` or `-u`. See `docs/superpowers/plans/2026-05-12-nexa-coa-setup.md` Phase 0. ```bash
ssh odoo-nexa "docker exec odoo-nexa-app odoo -c /etc/odoo/odoo.conf \
-d nexamain -u nexa_coa_setup --no-http --stop-after-init"
```
**Restore from backup** (only if catastrophic):
```bash
DUMP=~/Backups/odoo-nexa/nexamain_<timestamp>.dump
scp "$DUMP" odoo-nexa:/tmp/
ssh odoo-nexa "docker exec odoo-nexa-db psql -U odoo -d postgres -c \
'DROP DATABASE nexamain;' && \
docker exec odoo-nexa-db psql -U odoo -d postgres -c \
'CREATE DATABASE nexamain OWNER odoo;' && \
cat $DUMP | docker exec -i odoo-nexa-db pg_restore -U odoo -d nexamain && \
docker restart odoo-nexa-app"
```
---
## Yearly close calendar
Nexa is an annual HST filer and an annual T2 filer (fiscal year-end Dec 31).
| When | What | Notes |
|---|---|---|
| **Jan** | Confirm asset purchases for the year, assign correct CCA class accounts (1510-1560) | Class 50 hardware @ 55% DB (AccII = 82.5% Y1 through 2027). Class 14.1 software @ 100% Y1. |
| **Jan-Feb** | Pull SR&ED analytic report. Filter on SR&ED Tag analytic plan. Export. | Hand off to accountant for T661 prep. |
| **Mar 31** | **HST/GST annual return due**. Line 105 = sum of 2110, Line 108 = sum of 1210 ITC. | Pay any net tax + first quarterly instalment if prior year > $3k. |
| **Mar 31** | **T2 balance due** (CCPC). | T2 return itself is due June 30. |
| **Mar-Apr** | Set fiscalyear_lock_date to prior Dec 31 via Accounting > Configuration > Settings > Lock Dates. | Prevents accidental back-dating into closed period. |
| **Jun 30** | **T2 corporate income tax return due**. Schedule 23 allocates SBD + SR&ED expenditure limits across Nexa / Westin / Divine. | Associated-group calculation. |
| **Quarterly** | Pay HST instalments (if prior net tax ≥ $3k). | Track via 1220 Instalments Paid. |
| **Sep-Dec** | Yearly review of intercompany pricing (Nexa ↔ Westin / Divine). | Transfer-pricing compliance — must be fair market value. |
---
## Common tasks
### Add a new GL account
1. Append a `<record id="acct_NNNN" model="account.account">` to `data/01_account_account.xml` using the next free 4-digit code in the relevant range.
2. Deploy + `-u` (see Install/Update above).
3. Verify: `psql -d nexamain -c "SELECT code, name FROM ... WHERE code = 'NNNN';"`
### Add a new product
For ad-hoc / per-customer items, just create via UI:
- Sales > Products > New → set name, price, **Product Category** (this drives the income account).
- The fiscal position auto-applies tax when invoicing.
For new standard catalog items, append to `data/11_products.xml` (uses `noupdate=1` so a re-install won't overwrite UI edits).
### Add a new analytic account (project, department, SR&ED tag)
Projects are dynamic — create via UI:
- Accounting > Configuration > Analytic Accounting > Analytic Accounts > New
- Code: `PRJ-{YYYY}-{CUST}-{SHORTNAME}` (e.g. `PRJ-2026-WESTIN-ERP-PHASE2`)
- Plan: **Customer Project**
For departments or new SR&ED tags, edit `data/06_account_analytic_account.xml` + deploy + `-u`.
### Set the fiscal year lock
Accounting > Configuration > Settings > Lock Dates > set `Lock Date` to Dec 31 of the prior fiscal year. Requires:
- All bank statement lines for the period reconciled / cleared / deleted
- Final accountant adjustments posted
The `post_init_hook` attempts this automatically at install but tolerates failure (logs a warning instead) — set it manually once the books are clean.
### Reclassify a wrongly-categorized historical invoice line
Two ways:
- **In place (no PDF change)**: SQL `UPDATE account_move_line SET account_id = <new_id> WHERE id = <line_id>;`. Used in `scripts/fix_invoice_1127.py` and `scripts/reclass_historical_411000.py` as references.
- **Proper way (audit-trail clean)**: Reset invoice to draft, edit, re-post. Requires admin permissions + un-reconciling any payment first.
### Pull SR&ED data at year-end
```sql
-- Eligible salaries summary
SELECT aa.code, aa.name, ROUND(SUM(aml.debit - aml.credit)::numeric, 2) AS amount
FROM account_move_line aml
JOIN account_analytic_line aal ON aal.move_line_id = aml.id
JOIN account_analytic_account aa ON aa.id = aal.account_id
JOIN account_analytic_plan ap ON ap.id = aa.plan_id
WHERE ap.name = 'SR&ED Tag'
AND aml.date BETWEEN '2026-01-01' AND '2026-12-31'
AND aa.code <> 'NOT-ELIGIBLE'
GROUP BY aa.code, aa.name
ORDER BY aa.code;
```
Plus pull eligible contractor invoices: customer = Nexa, vendor in Canada (arm's length), tagged `SRED-CONTRACTOR-CA-ARM-LENGTH`.
---
## Compliance flags (do not forget)
- **Associated corporations**: Westin Healthcare Inc + Divine Mobility Inc share Nexa's $500k SBD limit and $3M SR&ED expenditure limit. **Annual Schedule 23 filing** allocates these across the group.
- **Subsection 15(2)**: Shareholder loans outstanding > 1 year past fiscal year-end become **taxable to Gurpreet personally**. Track 2510 (short-term) vs 2520 (long-term commercial loan).
- **Transfer pricing (s.247)**: Nexa invoicing Westin / Divine must be at fair market value. Document the methodology; penalty is 10% of any adjustment.
- **GST/HST cadence**: currently annual. Once Nexa-only revenue clears **$1.5M**, CRA auto-moves you to quarterly filing.
- **QC QST registration**: required if Nexa has any QC customers and revenue > $30k. Separate from federal CRA registration.
- **Quick Method GST/HST**: **likely unavailable** — the $400k threshold is checked against the associated-group total (Nexa + Westin + Divine combined).
- **Specified employee SR&ED cap**: Gurpreet's SR&ED-eligible salary is capped at 75% of basic salary (no bonuses), and only counts if paid via T4 payroll.
---
## Implementation scripts (one-shot, idempotent)
All under `scripts/` — preserved for audit reference; not run by the module
itself. Already executed against prod.
| Script | What it did |
|---|---|
| `fix_gl_codes.py` | Renumbered 119100/119900 → 115200/115900 and 511105 → 511100 |
| `convert_to_4digit.py` | Renumbered 128 Nexa accounts from 6-digit l10n_ca style to clean 4-digit |
| `convert_l10nca_to_4digit.py` | Renumbered 12 retained l10n_ca legacy accounts (Bank/AR/AP/HST) to 4-digit |
| `fix_invoice_1127.py` | Reclassified Entech invoice 1127's 17 lines + reassigned 14 product templates to proper categories |
| `reclass_historical_411000.py` | Batch-reclassified 200 historical invoice lines from legacy 411000 by keyword rules |
| `test_invoices.py` | End-to-end invoice tests (ON HST, US zero-rated, QC GST+QST, intercompany) |
---
## Open items (manual follow-ups)
- [ ] Set fiscal year lock at 2025-12-31 once unreconciled bank statement lines are cleared
- [ ] Verify HST# format display on customer invoice PDFs (stored as `741224877RT0001`; some Canadian accountants prefer `741224877 RT0001` with space — change via UI if needed)
- [ ] When first T4 employee is hired: configure payroll (Wagepoint / ADP / Odoo Payroll), set up source deduction journal automation, decide on payroll cadence
- [ ] When first USD invoice arrives: add USD bank account (1020 reserved), enable currency_rate_live cron, configure multi-currency on company
- [ ] When asset count grows: install custom CCA module OR keep maintaining CCA schedule via accountant's spreadsheet