Skip to content
Snippets Groups Projects
switch.py 5.67 KiB
Newer Older
##############################################################################
#
#    Converter Odoo module
#    Copyright © 2020, 2024, 2025 XCG Consulting <https://xcg-consulting.fr>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
from collections.abc import Callable
Axel Prel's avatar
Axel Prel committed
from typing import Any
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
from odoo import api, models  # type: ignore[import-untyped]
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
from .base import Context, ContextBuilder, Converter, NewinstanceType, Skip, SkipType
from .validate import Validation, Validator
Florent Aide's avatar
Florent Aide committed


class Switch(Converter):
    """A converter to handle switch cases.
    A list of converters are provided with a function. The first function to
    match is used, any function that is None will be used.
    The function argument is the model instance.

    Example usage:

    .. code-block:: python

                  lambda record: record.is_xxx,
                  lambda message_value: "wave_code" in message_value,
                  Model("__wave__", {}),
              ),
              (None, None, Model("__event__", {})),
            ]
        )
Florent Aide's avatar
Florent Aide committed
    def __init__(
        self,
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
                Callable[[models.BaseModel], bool] | None,
                Callable[[Any], bool] | None,
                Converter | SkipType,
Axel Prel's avatar
Axel Prel committed
        validator: Validator | None = None,
        validation: Validation = Validation.SKIP,
Axel Prel's avatar
Axel Prel committed
        context: ContextBuilder | None = None,
Florent Aide's avatar
Florent Aide committed
    ):
        """
        :param converters: is a 3 tuple composed of:
        out condition, in condition, and chosen converter
        :param validator:
        :param context:
        """
Florent Aide's avatar
Florent Aide committed
        super()
        self._converters = converters
        self.context = context
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        self.validator = validator
        self.validation = validation
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    def odoo_to_message(self, instance: models.BaseModel, ctx: Context = None) -> Any:
        for out_cond, _in_cond, converter in self._converters:
            if out_cond is None or out_cond(instance):
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
                if isinstance(converter, SkipType):
                    return converter
                else:
                    return converter.odoo_to_message(instance, ctx)
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        return Skip
    def message_to_odoo(
        self,
        odoo_env: api.Environment,
        phase: str,
        message_value: Any,
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        instance: models.BaseModel,
        value_present: bool = True,
szeka.wong's avatar
szeka.wong committed
    ) -> dict | SkipType:
        for _out_cond, in_cond, converter in self._converters:
            if not isinstance(converter, SkipType) and (
                in_cond is None or in_cond(message_value)
            ):
                return converter.message_to_odoo(
                    odoo_env,
                    phase,
                    message_value,
                    instance,
                    value_present=value_present,
                )

Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    @property
    def is_instance_getter(self) -> bool:
        for _out_cond, _in_cond, converter in self._converters:
            if not isinstance(converter, SkipType) and converter.is_instance_getter:
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    def get_instance(
        self, odoo_env: api.Environment, message_data
    ) -> models.BaseModel | NewinstanceType | None:
        for _out_cond, in_cond, converter in self._converters:
            if (
                not isinstance(converter, SkipType)
                and converter.is_instance_getter
                and (in_cond is None or in_cond(message_data))
                return converter.get_instance(odoo_env, message_data)
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        return super().get_instance(odoo_env, message_data)
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
    def _set_validator(self, value: Validator | None) -> None:
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        # also set validator on any converters in our switch, in case they care
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        super()._set_validator(value)
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        for _out_cond, _in_cond, converter in self._converters:
            if not isinstance(converter, SkipType):
                converter.validator = value
    def _set_validation(self, value: Validation) -> None:
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        # also set validation on any converters in our switch
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        super()._set_validation(value)
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        for _out_cond, _in_cond, converter in self._converters:
            if not isinstance(converter, SkipType):
                converter.validation = value
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        for _out_cond, _in_cond, converter in self._converters:
            types.update(converter.get__type__())
Vincent Hatakeyama's avatar
Vincent Hatakeyama committed
        return types

    @property
    def possible_datatypes(self) -> set[str]:
        result = super().possible_datatypes
        for _out_cond, _in_cond, converter in self._converters:
            result.update(converter.possible_datatypes)
        return result

    def odoo_datatype(self, instance: models.BaseModel) -> str | None:
        for out_cond, _in_cond, converter in self._converters:
            if out_cond is None or out_cond(instance):
                return converter.odoo_datatype(instance)
        return super().odoo_datatype(instance)