Files
Odoo-Modules/fusion_plating/docs/superpowers/specs/2026-05-29-manager-invoice-permission-design.md
gsinghpal 1e9ffccd6b feat(invoicing): managers (+QM+Owner) can create customer invoices
Grant Odoo Billing (account.group_account_invoice) to group_fp_manager via
implied_ids; Quality Manager + Owner inherit it. Billing only (not Accountant);
the SO-origin workflow gate in fusion_plating_jobs is unchanged, so managers
invoice from the Sale Order's Create Invoice action. Tests assert Manager/Owner
get Billing and Shop Manager does not.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 20:33:40 -04:00

3.5 KiB

Managers Can Create Invoices (grant Billing group)

Date: 2026-05-29 Status: Approved — implementing directly (single security record; no separate plan) Module: fusion_plating_invoicing

Goal

Let the plating Manager role (and Quality Manager + Owner, who inherit it) create customer invoices from a confirmed Sale Order.

Background — why managers can't invoice today (verified 2026-05-29)

  • Creating an account.move of a customer type requires one of Odoo's accounting groups (minimum: Billing = account.group_account_invoice).
  • No plating role grants any Odoo accounting group. A repo-wide grep for account.group_account* in fusion_plating*/security/ returns nothing.
  • group_fp_manager implies only the legacy plating-internal group_fp_accounting (fusion_plating_invoicing/security/fp_invoicing_security.xml:18-20), which itself chains to the deprecated group_fusion_plating_supervisornot to any Odoo accounting group. So it grants no account.move rights.
  • Result: when a Manager opens a confirmed SO and clicks Create Invoice, Odoo's _create_invoices() tries to create an account.move and the Manager hits an AccessError for lacking Billing.
  • Separately, fusion_plating_jobs/models/account_move.py::_fp_validate_customer_invoice blocks off-SO customer-invoice creation for all users (parent-number audit trail). This is a workflow gate, not a permission gate — it is not the manager blocker and stays unchanged.

Decision

Grant account.group_account_invoice (Billing) to group_fp_manager via implied_ids.

  • Cascade: Quality Manager → implies Manager, Owner → implies Quality Manager, so QM and Owner inherit Billing automatically. Shop Manager, Sales Manager, Technician, Operator, and below are unaffected.
  • Level — Billing only: create/edit/post customer invoices + credit notes. Explicitly not Accountant (account.group_account_user): no vendor bills, manual journal entries, bank reconciliation, accounting reports, or period close.
  • Path unchanged: managers invoice from the SO (Create Invoice action), which the _fp_validate_customer_invoice workflow gate already permits via fp_from_so_invoice. Standalone off-SO invoices remain blocked for everyone.

Implementation

Extend the existing additive implied_ids write on group_fp_manager in fusion_plating_invoicing/security/fp_invoicing_security.xml:

<record id="fusion_plating.group_fp_manager" model="res.groups">
    <field name="implied_ids" eval="[(4, ref('fusion_plating_invoicing.group_fp_accounting')),
                                      (4, ref('account.group_account_invoice'))]"/>
</record>

(4, id) (Command.link) is additive + idempotent across install/-u. fusion_plating_invoicing already depends transitively on account (it overrides account.move), so ref('account.…') resolves. Bump the module version.

Testing

TransactionCase in fusion_plating_invoicing/tests/: create a user holding only group_fp_manager, assert user.has_group('account.group_account_invoice') is True (proves the implication landed). Then a live entech check: a Manager creates an invoice from a confirmed SO without an AccessError.

Out of scope

  • Relaxing the SO-origin workflow gate (intentional; preserves the parent-number audit trail).
  • Accountant-level access (vendor bills, journals, reconciliation, reports).
  • Granting invoicing to Shop Manager / Sales Manager / below.