2
0
account-financial-tools/account_journal_general_sequence/models/account_move.py
Jairo Llopis 1067d0ea1b
[FIX] account_journal_general_sequence: provide defaults for sorting
Under some weird scenarios where some modules are involved, several invoices are posted at the same time, and no invoice exists, we could get to the case when `one.date` or `one.name` were `False`.

Here I provide a default value to avoid comparing `str` to `bool` in those cases.

Tried a lot but couldn't reproduce the test case in code, sorry 😕. However, the traceback was clear:

```
File "/opt/odoo/auto/addons/account_journal_general_sequence/models/account_move.py", line 64, in _compute_entry_number
  for move in chosen.sorted(lambda one: (one.date, one.name, one.id)):
File "/opt/odoo/custom/src/odoo/odoo/models.py", line 5583, in sorted
  ids = tuple(item.id for item in sorted(self, key=key, reverse=reverse))
TypeError: '<' not supported between instances of 'str' and 'bool'
```

@moduon MT-5559
2024-03-25 10:51:45 +00:00

76 lines
2.6 KiB
Python

# Copyright 2022 Moduon
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
import logging
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
ADDON = "account_journal_general_sequence"
class AccountMove(models.Model):
_inherit = "account.move"
_sql_constraints = [
(
"entry_number_unique",
"UNIQUE(entry_number, journal_id)",
"Entry number must be unique per journal.",
),
]
entry_number = fields.Char(
index=True,
readonly=True,
store=True,
compute="_compute_entry_number",
help="Automatic numbering, based on journal configuration.",
)
@api.depends("state")
def _compute_entry_number(self):
"""Assign an entry number when posting."""
# Skip if installing module, for performance reasons
if self.env.context.get("module") == ADDON:
module = self.env["ir.module.module"].search([("name", "=", ADDON)])
if module.state == "to install":
_logger.info(
"Skipping entry number generation at install for %s.",
self,
)
return
canceled = self.filtered_domain(
[("state", "=", "cancel"), ("entry_number", "!=", False)]
)
canceled.entry_number = False
if canceled:
no_gap_seqs = canceled.mapped(
"journal_id.entry_number_sequence_id"
).filtered_domain([("implementation", "=", "no_gap")])
if no_gap_seqs:
_logger.warning(
"Emptied entry_number for %r after cancellation. "
"This created gaps on %r.",
canceled,
no_gap_seqs,
)
chosen = self.filtered_domain(
[("state", "=", "posted"), ("entry_number", "=", False)]
)
# Cache all the new numbers to avoid wasting recomputations, caused by
# searches done by _next() in the loop below
chosen_map = {}
for move in chosen.sorted(
lambda one: (one.date or "", one.name or "", one.id or 0)
):
chosen_map[move.id] = move.journal_id.entry_number_sequence_id._next(
move.date
)
# Write all the new numbers in the chosen moves
for move_id, new_number in chosen_map.items():
self.browse(move_id).entry_number = new_number
if chosen:
_logger.info("Added entry_number to %d account moves", len(chosen))
_logger.debug("Added entry_number to %r", chosen)