mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-19 10:32:05 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
|
|
@ -0,0 +1,2 @@
|
|||
from . import base_substate
|
||||
from . import base_substate_mixin
|
||||
|
|
@ -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",
|
||||
)
|
||||
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue