Files
pms/multi_pms_properties/models.py
2022-03-28 10:06:02 +02:00

193 lines
8.0 KiB
Python

# Copyright 2021 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, models
from odoo.exceptions import UserError
class BaseModel(models.AbstractModel):
_inherit = "base"
_check_pms_properties_auto = False
"""On write and create, call ``_check_pms_properties_auto`` to ensure properties
consistency on the relational fields having ``check_pms_properties=True``
as attribute.
"""
def _valid_field_parameter(self, field, name):
"""Make new field attribute valid for Odoo."""
return name == "check_pms_properties" or super()._valid_field_parameter(
field, name
)
@api.model_create_multi
def create(self, vals_list):
records = super(BaseModel, self).create(vals_list)
if self._check_pms_properties_auto:
records._check_pms_properties()
return records
def write(self, vals):
res = super(BaseModel, self).write(vals)
check_pms_properties = False
for fname in vals:
field = self._fields.get(fname)
if (
fname == "pms_property_id"
or fname == "pms_property_ids"
or fname == "company_id"
or (field.relational and getattr(field, "check_pms_properties", False))
):
check_pms_properties = True
if res and check_pms_properties and self._check_pms_properties_auto:
self._check_pms_properties()
return res
def _check_pms_properties(self, fnames=None):
"""Check the properties of the values of the given field names.
:param list fnames: names of relational fields to check
:raises UserError: if the `pms_properties` of the value of any field is not
in `[False, self.pms_property_id]` (or `self` if
:class:`~odoo.addons.base.models.pms_property`).
For :class:`~odoo.addons.base.models.res_users` relational fields,
verifies record company is in `company_ids` fields.
User with main pms property A, having access to pms property A and B, could be
assigned or linked to records in property B.
"""
if fnames is None:
fnames = self._fields
regular_fields = self._get_regular_fields(fnames)
if not regular_fields:
return
inconsistencies = self._check_inconsistencies(regular_fields)
if inconsistencies:
lines = [_("Incompatible properties on records:")]
property_msg = _(
"""- Record is properties %(pms_properties)r and %(field)r
(%(fname)s: %(values)s) belongs to another properties."""
)
record_msg = _(
"""- %(record)r belongs to properties %(pms_properties)r and
%(field)r (%(fname)s: %(values)s) belongs to another properties."""
)
for record, name, corecords in inconsistencies[:5]:
if record._name == "pms.property":
msg, pms_properties = property_msg, record
else:
msg, pms_properties = (
record_msg,
record.pms_property_id.name
if "pms_property_id" in record
else ", ".join(repr(p.name) for p in record.pms_property_ids),
)
field = self.env["ir.model.fields"]._get(self._name, name)
lines.append(
msg
% {
"record": record.display_name,
"pms_properties": pms_properties,
"field": field.field_description,
"fname": field.name,
"values": ", ".join(
repr(rec.display_name) for rec in corecords
),
}
)
raise UserError("\n".join(lines))
def _get_regular_fields(self, fnames):
regular_fields = []
for name in fnames:
field = self._fields[name]
if (
field.relational
and getattr(field, "check_pms_properties", False)
and (
"pms_property_id" in self.env[field.comodel_name]
or "pms_property_ids" in self.env[field.comodel_name]
)
):
regular_fields.append(name)
return regular_fields
def _check_inconsistencies(self, regular_fields):
inconsistencies = []
for record in self:
pms_properties = False
if record._name == "pms.property":
pms_properties = record
if "pms_property_id" in record:
pms_properties = record.pms_property_id
if "pms_property_ids" in record:
pms_properties = record.pms_property_ids
# Check the property & company consistence
if "company_id" in self._fields:
if record.company_id and pms_properties:
property_companies = pms_properties.mapped("company_id.id")
if (
len(property_companies) > 1
or record.company_id.id != property_companies[0]
):
raise UserError(
_(
"You cannot establish a company other than "
"the one with the established properties"
)
)
# Check verifies that all
# records linked via relation fields are compatible
# with the properties of the origin document,
for name in regular_fields:
field = self._fields[name]
co_pms_properties = False
corecord = record.sudo()[name]
# TODO:res.users management properties
if "pms_property_id" in corecord:
co_pms_properties = corecord.pms_property_id
if "pms_property_ids" in corecord:
co_pms_properties = corecord.pms_property_ids
if (
# There is an inconsistency if:
#
# - Record has properties and corecord too and
# there's no match between them:
# X Pms_room_class with Property1 cannot contain
# Pms_room with property2 X
#
# - Record has a relation one2many with corecord and
# corecord properties aren't included in record properties
# or what is the same, subtraction between corecord properties
# and record properties must be False:
# X Pricelist with Prop1 and Prop2 cannot contain
# Pricelist_item with Prop1 and Prop3 X
# X Pricelist with Prop1 and Prop2 cannot contain
# Pricelist_item with Prop1, Prop2 and Prop3 X
# -In case that record has a relation many2one
# with corecord the condition is the same as avobe
(
pms_properties
and co_pms_properties
and (not pms_properties & co_pms_properties)
)
or (
corecord
and field.type == "one2many"
and pms_properties
and (co_pms_properties - pms_properties)
)
or (
field.type == "many2one"
and co_pms_properties
and ((pms_properties - co_pms_properties) or not pms_properties)
)
):
inconsistencies.append((record, name, corecord))
return inconsistencies