Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,2 @@
from . import base_substate
from . import base_substate_mixin

View file

@ -0,0 +1,103 @@
# Copyright 2020 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class BaseSubstateType(models.Model):
"""This model defines technical data which precises
for each target model concerned by substate,
the technical "state" field name.
Data in this model should be created by import as technical data
in the specific module. For example in sale_substate we can define:
base.substate.type:
- name: Sale order Substate
- model: sale.order
- target_state_field: state
"""
_name = "base.substate.type"
_description = "Base Substate Type"
_order = "name asc, model asc"
name = fields.Char(required=True, translate=True)
model = fields.Selection(selection=[], string="Apply on", required=True)
target_state_field = fields.Char(
required=True,
help="Technical target state field name."
' Ex for sale order "state" for other "status" ... ',
)
class TargetStateValue(models.Model):
"""This model define technical data that precise the translatable name
of the target model state (ex:Quotation for 'draft' State)
Data in this model should be created by import as technical data
in specific module ex : sale_subsatate
"""
_name = "target.state.value"
_description = "Target State Value"
_order = "name asc"
name = fields.Char(
"Target state Name",
required=True,
translate=True,
help="Target state translateble name.\n"
'Ex: for sale order "Quotation", "Sale order", "Locked"...',
)
base_substate_type_id = fields.Many2one(
"base.substate.type",
string="Substate Type",
ondelete="restrict",
)
target_state_value = fields.Char(
required=True,
help="Technical target state value.\n"
'Ex: for sale order "draft", "sale", "done", ...',
)
model = fields.Selection(
related="base_substate_type_id.model",
store=True,
readonly=True,
help="Model for technical use",
)
class BaseSubstate(models.Model):
"""This model define substates that will be applied on the target model.
for each state we can define one or more substate.
ex:
for the quotation state of a sale order we can define
3 substates "In negotiation",
"Won" and "Lost".
We can also send mail when the susbstate is reached.
"""
_name = "base.substate"
_description = "Base Substate"
_order = "active desc, sequence asc"
name = fields.Char("Substate Name", required=True, translate=True)
description = fields.Text(translate=True)
sequence = fields.Integer(
index=True,
help="Gives the sequence order when applying the default substate",
)
target_state_value_id = fields.Many2one(
"target.state.value", string="Target State Value", ondelete="restrict"
)
active = fields.Boolean(default=True)
mail_template_id = fields.Many2one(
"mail.template",
string="Email Template",
help="If set, an email will be sent to the partner "
"when the object reaches this substate.",
)
model = fields.Selection(
related="target_state_value_id.model",
store=True,
readonly=True,
help="Model for technical use",
)

View file

@ -0,0 +1,127 @@
# Copyright 2020 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class BaseSubstateMixin(models.AbstractModel):
_name = "base.substate.mixin"
_description = "BaseSubstate Mixin"
_state_field = "state"
@api.constrains("substate_id", _state_field)
def check_substate_id_value(self):
rec_states = dict(self._fields[self._state_field].selection)
for rec in self:
target_state = rec.substate_id.target_state_value_id.target_state_value
if rec.substate_id and rec.state != target_state:
raise ValidationError(
_(
"The substate %(name)s is not defined for the state"
" %(state)s but for %(target_state)s "
)
% {
"name": rec.substate_id.name,
"state": _(rec_states[rec.state]),
"target_state": _(rec_states[target_state]),
}
)
def _get_default_substate_id(self, state_val=False):
"""Gives default substate_id"""
search_domain = self._get_default_substate_domain(state_val)
# perform search, return the first found
return (
self.env["base.substate"]
.search(search_domain, order="sequence", limit=1)
.id
)
def _get_default_substate_domain(self, state_val=False):
"""Override this method
to change domain values
"""
if not state_val:
state_val = self._get_default_state_value()
substate_type = self._get_substate_type()
state_field = substate_type.target_state_field
if self and not state_val and state_field in self._fields:
state_val = self[state_field]
domain = [("target_state_value_id.target_state_value", "=", state_val)]
domain += [
("target_state_value_id.base_substate_type_id", "=", substate_type.id)
]
return domain
def _get_default_state_value(
self,
):
"""Override this method
to change state_value
"""
return "draft"
def _get_substate_type(
self,
):
"""Override this method
to change substate_type (get by xml id for example)
"""
return self.env["base.substate.type"].search(
[("model", "=", self._name)], limit=1
)
substate_id = fields.Many2one(
"base.substate",
string="Sub State",
ondelete="restrict",
default=lambda self: self._get_default_substate_id(),
tracking=5,
index=True,
domain=lambda self: [("model", "=", self._name)],
copy=False,
)
@api.constrains("substate_id")
def check_substate_id_consistency(self):
for mixin_obj in self:
if mixin_obj.substate_id and mixin_obj.substate_id.model != self._name:
raise ValidationError(
_("This substate is not define for this object but for %s")
% mixin_obj.substate_id.model
)
def _update_before_write_create(self, values):
substate_type = self._get_substate_type()
state_field = substate_type.target_state_field
if values.get(state_field) and not values.get("substate_id"):
state_val = values.get(state_field)
values["substate_id"] = self._get_default_substate_id(state_val)
# Send mail if substate has mail template
if values.get("substate_id"):
substate = self.env["base.substate"].browse(values["substate_id"])
if (
hasattr(self, "message_post_with_template")
and substate.mail_template_id
):
self.message_post_with_template(
substate.mail_template_id.id,
subtype_id=self.env["ir.model.data"]._xmlid_to_res_id(
"mail.mt_note"
),
)
return values
def write(self, values):
values = self._update_before_write_create(values)
res = super().write(values)
return res
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
vals = self._update_before_write_create(vals)
res = super().create(vals_list)
return res