Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
from . import ir_qweb
from . import qweb_field_options

View File

@@ -0,0 +1,33 @@
# Copyright 2024-2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, models
class IrQweb(models.AbstractModel):
_inherit = "ir.qweb"
@api.model
def _get_field(
self, record, field_name, expression, tagName, field_options, values
):
if values.get("report_type") == "pdf":
company = getattr(record, "company_id", False) or self.env.company
options_recs = self.env["qweb.field.options"].search(
[
("res_model_name", "=", record._name),
("field_name", "=", field_name),
"|",
("company_id", "=", company.id),
("company_id", "=", False),
]
)
options_recs = [r for r in options_recs if r._get_score(record) > 0]
if options_recs:
options_rec = max(
options_recs, default=None, key=lambda r: r._get_score(record)
)
field_options = options_rec._update_field_options(record, field_options)
return super()._get_field(
record, field_name, expression, tagName, field_options, values
)

View File

@@ -0,0 +1,116 @@
# Copyright 2024-2025 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import ast
import logging
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__)
class QwebFieldOptions(models.Model):
_name = "qweb.field.options"
_description = "Qweb Field Options"
_order = "res_model_id, field_id"
res_model_id = fields.Many2one(
"ir.model", string="Model", ondelete="cascade", required=True
)
res_model_name = fields.Char("Model Name", related="res_model_id.model", store=True)
field_id = fields.Many2one(
"ir.model.fields",
domain="[('model_id', '=', res_model_id)]",
string="Field",
ondelete="cascade",
required=True,
)
field_type = fields.Selection(related="field_id.ttype")
field_name = fields.Char("Field Name", related="field_id.name", store=True)
uom_id = fields.Many2one("uom.uom", string="UoM", ondelete="cascade")
uom_field_id = fields.Many2one(
"ir.model.fields",
domain="[('model_id', '=', res_model_id), ('relation', '=', 'uom.uom')]",
string="UoM Field",
ondelete="cascade",
)
currency_id = fields.Many2one("res.currency", string="Currency", ondelete="cascade")
currency_field_id = fields.Many2one(
"ir.model.fields",
domain="[('model_id', '=', res_model_id), ('relation', '=', 'res.currency')]",
string="Currency Field",
ondelete="cascade",
)
field_options = fields.Char(
"Options",
help="A string representation of a dictionary to specify field formatting "
"options. Examples:\n"
"{'widget': 'date'}\n"
"{'widget': 'monetary'}\n"
"{'widget': 'contact', 'fields': ['name', 'phone']}",
)
digits = fields.Integer()
company_id = fields.Many2one("res.company", string="Company")
@api.constrains("field_options")
def _check_field_options_format(self):
for rec in self:
if not rec.field_options:
continue
field_options = False
try:
field_options = ast.literal_eval(rec.field_options)
except Exception as e:
raise ValidationError(
_(
"Invalid string for the Options field: %(field_options)s.\n"
"Error: %(error)s"
)
% {"field_options": rec.field_options, "error": e}
) from e
if not isinstance(field_options, dict):
raise ValidationError(
_("Options must be a dictionary, but got %s") % type(field_options)
)
def _get_score(self, record):
self.ensure_one()
score = 1
# Just increment the score as the record already matches the company_id,
# which has been filtered prior to calling this method.
if self.company_id:
score += 1
if self.uom_id:
if record[self.uom_field_id.sudo().name] == self.uom_id:
score += 1
else:
return -1
if self.currency_id:
if record[self.currency_field_id.sudo().name] == self.currency_id:
score += 1
else:
return -1
return score
def _update_field_options(self, record, field_options):
self.ensure_one()
if self.field_options:
try:
extra_options = ast.literal_eval(self.field_options)
if extra_options.get("widget") == "monetary":
extra_options["display_currency"] = (
self.currency_id
or hasattr(record, "company_id")
and record.company_id.currency_id
or self.env.company.currency_id
)
field_options.update(extra_options)
except Exception as e:
_logger.error(
"Failed to parse field options as a dictionary: "
f"{self.field_options}. Error: {e}"
)
elif self.field_type == "float":
field_options["precision"] = self.digits
return field_options