Skip to content

[FIX] pms_api_rest: enforce fiscalyear_lock_date when editing invoices via REST#78

Open
DarioLodeiros wants to merge 1 commit into
16.0from
16.0-fix-invoice-lock-date-check
Open

[FIX] pms_api_rest: enforce fiscalyear_lock_date when editing invoices via REST#78
DarioLodeiros wants to merge 1 commit into
16.0from
16.0-fix-invoice-lock-date-check

Conversation

@DarioLodeiros
Copy link
Copy Markdown
Member

Summary

PmsInvoiceService.update_invoice and delete_invoice browse the move with .sudo() to run the access check explicitly via pms_api_check_access. As a side effect, the standard account.move._check_fiscalyear_lock_date hook fired from write/unlink runs as SUPERUSER, which bypasses the lock date. A TODO was sitting in the code disabling the check pending a "check the access" decision.

Closed-period invoices can therefore be modified or deleted from the mobile / back-office REST clients even when the back-office UI refuses the same edit. In practice this has surfaced as invoices dated before the fiscalyear lock being silently reversed and re-issued (sometimes swapping the simplified-invoice partner for a real one) months after the books were closed.

Fix

  • Re-execute _check_fiscalyear_lock_date on the same move but with_user(self.env.user) right before any modification, so the caller's groups (in particular account.group_account_manager) decide whether the operation is allowed.
  • Standard accounting users hit the same UserError they would get from the UI; managers retain the ability to edit closed periods, matching Odoo's default behaviour.
  • Same guard added to delete_invoice to cover the unlink path.

Test plan

  • Existing API tests on pms_api_rest pass.
  • Manual: as a regular accounting user, PATCH /api/invoices/p/<id> on a posted invoice dated before fiscalyear_lock_date → 4xx with the standard lock-date UserError.
  • Manual: as an account.group_account_manager, same call succeeds (same as today on the back-office).
  • Manual: DELETE /api/invoices/<id> on a draft invoice dated before the lock date → 4xx for regular users, allowed for managers.

Notes

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

Diff Coverage

Diff: origin/16.0...HEAD, staged and unstaged changes

  • pms_api_rest/services/pms_invoice_service.py (0.0%): Missing lines 247,383,452

Summary

  • Total: 3 lines
  • Missing: 3 lines
  • Coverage: 0%

pms_api_rest/services/pms_invoice_service.py

Lines 243-251

  243         # ``.sudo()`` browse above doesn't bypass it. Accounting managers
  244         # (``account.group_account_manager``) can still edit closed periods,
  245         # which is the standard Odoo behaviour; regular users hit the same
  246         # ``UserError`` they would get from the back-office.
! 247         invoice.with_user(self.env.user)._check_fiscalyear_lock_date()
  248         new_vals = {}
  249         if (
  250             pms_invoice_info.partnerId
  251             and pms_invoice_info.partnerId != invoice.partner_id.id

Lines 379-387

  379             if invoice.state != "draft" and invoice.name not in ["/", False]:
  380                 raise UserError(_("Only draft invoices can be deleted"))
  381             # Same lock-date safety net as in ``update_invoice``: prevent
  382             # deletions on closed periods even when called via ``sudo()``.
! 383             invoice.with_user(self.env.user)._check_fiscalyear_lock_date()
  384             invoice.unlink()
  385         else:
  386             raise MissingError(_("Invoice not found"))

Lines 448-456

  448                     if "quantity" in line[2] and move_line.quantity != line[2].get(
  449                         "quantity"
  450                     ):
  451                         return True
! 452                 if (
  453                     line[0] == 0
  454                     and not line[2].get("display_type")
  455                     or line[2].get("display_type") == "product"
  456                 ):

…s via REST

``PmsInvoiceService.update_invoice`` and ``delete_invoice`` ``browse``
the move with ``.sudo()`` to run the access check explicitly via
``pms_api_check_access``. As a side effect, the standard
``account.move._check_fiscalyear_lock_date`` hook fired from ``write``/
``unlink`` runs as SUPERUSER, which bypasses the lock date. The TODO
that disabled the check has been hanging around without anyone owning
the access-context question.

Closed-period invoices can therefore be modified or deleted from the
mobile/back-office REST clients even when the back-office UI refuses
the same edit. In practice this surfaced as invoices dated before the
fiscalyear lock being silently reversed and re-issued (sometimes
swapping the simplified-invoice partner for a real one) months after
the books were closed.

Fix:

- Re-execute ``_check_fiscalyear_lock_date`` on the same move but
  ``with_user(self.env.user)`` right before any modification, so the
  caller's groups (in particular ``account.group_account_manager``)
  decide whether the operation is allowed. Standard accounting users
  hit the same ``UserError`` they would get from the UI; managers
  retain the ability to edit closed periods, matching Odoo's default.
- Same guard added to ``delete_invoice`` to cover the unlink path.

Other lines in the file are ruff-format reformats picked up by the
repo's pre-commit; they are functionally inert.
@DarioLodeiros DarioLodeiros force-pushed the 16.0-fix-invoice-lock-date-check branch from fc74bac to c9bd4bf Compare June 1, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant