86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
# Copyright 2020 Sunflower IT (<https://sunflowerweb.nl>)
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
import logging
|
|
import random
|
|
import string
|
|
import uuid
|
|
from inspect import getmembers, isclass, isfunction
|
|
|
|
from odoo import fields, models
|
|
from odoo.tools.safe_eval import safe_eval, wrap_module
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
DEFAULT_PYTHON_CODE = "number_padded"
|
|
|
|
|
|
class IrSequence(models.Model):
|
|
"""
|
|
Inherit standard ir.sequence to let the possibility of using a Python formula
|
|
to calculate the sequence from input variables such as the sequence number.
|
|
This allows obfuscation of the order in which sequences are given out,
|
|
but can also be used for any other purpose.
|
|
"""
|
|
|
|
_inherit = "ir.sequence"
|
|
|
|
# Python code
|
|
use_python_code = fields.Boolean(string="Use Python", default=False)
|
|
python_code = fields.Text(
|
|
string="Python expression",
|
|
default=DEFAULT_PYTHON_CODE,
|
|
help="Write Python code that generates the sequence body.",
|
|
)
|
|
python_code_preview = fields.Char("Preview", compute="_compute_python_code_preview")
|
|
|
|
def _get_python_eval_context(self, number_next):
|
|
"""
|
|
Get the eval context to evaluate the Python code with.
|
|
The format is (variable name, description, value)
|
|
You can inherit this in your custom module.
|
|
:return: tuple
|
|
"""
|
|
wrap_random = wrap_module(random, random.__all__)
|
|
uuid_elements = [e[0] for e in getmembers(uuid, isfunction)] + [
|
|
e[0] for e in getmembers(uuid, isclass)
|
|
]
|
|
wrap_uuid = wrap_module(uuid, uuid_elements)
|
|
wrap_string = wrap_module(string, string.__all__)
|
|
return {
|
|
"number": number_next[0] if isinstance(number_next, tuple) else number_next,
|
|
"number_padded": "%%0%sd" % self.padding % number_next,
|
|
"sequence": self,
|
|
"random": wrap_random,
|
|
"uuid": wrap_uuid,
|
|
"string": wrap_string,
|
|
}
|
|
|
|
def _get_python_value(self, number_next):
|
|
"""
|
|
Use the python formula to get the value.
|
|
:return: string
|
|
"""
|
|
eval_context = self._get_python_eval_context(number_next)
|
|
return safe_eval(self.python_code.strip(), eval_context)
|
|
|
|
def _compute_python_code_preview(self):
|
|
for this in self:
|
|
try:
|
|
this.python_code_preview = self.get_next_char(
|
|
(self.number_next_actual,)
|
|
)
|
|
except Exception as e: # noqa
|
|
this.python_code_preview = str(e)
|
|
|
|
def get_next_char(self, number_next):
|
|
if self.use_python_code:
|
|
interpolated_prefix, interpolated_suffix = self._get_prefix_suffix()
|
|
return (
|
|
interpolated_prefix
|
|
+ self._get_python_value(number_next)
|
|
+ interpolated_suffix
|
|
)
|
|
else:
|
|
return super(IrSequence, self).get_next_char(number_next)
|