Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
104
date_range/models/date_range_search_mixin.py
Normal file
104
date_range/models/date_range_search_mixin.py
Normal file
@@ -0,0 +1,104 @@
|
||||
# Copyright 2021 Opener B.V. <stefan@opener.amsterdam>
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
from lxml import etree
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.osv.expression import FALSE_DOMAIN, NEGATIVE_TERM_OPERATORS, TRUE_DOMAIN
|
||||
|
||||
|
||||
class DateRangeSearchMixin(models.AbstractModel):
|
||||
_name = "date.range.search.mixin"
|
||||
_description = "Mixin class to add a Many2one style period search field"
|
||||
_date_range_search_field = "date"
|
||||
|
||||
date_range_search_id = fields.Many2one(
|
||||
comodel_name="date.range",
|
||||
string="Filter by period (technical field)",
|
||||
compute="_compute_date_range_search_id",
|
||||
search="_search_date_range_search_id",
|
||||
)
|
||||
|
||||
def _compute_date_range_search_id(self):
|
||||
"""Assign a dummy value for this search field"""
|
||||
for record in self:
|
||||
record.date_range_search_id = False
|
||||
|
||||
@api.model
|
||||
def _search_date_range_search_id(self, operator, value):
|
||||
"""Map the selected date ranges to the model's date field"""
|
||||
# Deal with some bogus values
|
||||
if not value:
|
||||
if operator in NEGATIVE_TERM_OPERATORS:
|
||||
return TRUE_DOMAIN
|
||||
return FALSE_DOMAIN
|
||||
if value is True:
|
||||
if operator in NEGATIVE_TERM_OPERATORS:
|
||||
return FALSE_DOMAIN
|
||||
return TRUE_DOMAIN
|
||||
# Assume from here on that the value is a string,
|
||||
# a single id or a list of ids
|
||||
ranges = self.env["date.range"]
|
||||
if isinstance(value, str):
|
||||
ranges = self.env["date.range"].search([("name", operator, value)])
|
||||
else:
|
||||
if isinstance(value, int):
|
||||
value = [value]
|
||||
sub_op = "not in" if operator in NEGATIVE_TERM_OPERATORS else "in"
|
||||
ranges = self.env["date.range"].search([("id", sub_op, value)])
|
||||
if not ranges:
|
||||
return FALSE_DOMAIN
|
||||
domain = (len(ranges) - 1) * ["|"] + sum(
|
||||
(
|
||||
[
|
||||
"&",
|
||||
(self._date_range_search_field, ">=", date_range.date_start),
|
||||
(self._date_range_search_field, "<=", date_range.date_end),
|
||||
]
|
||||
for date_range in ranges
|
||||
),
|
||||
[],
|
||||
)
|
||||
return domain
|
||||
|
||||
@api.model
|
||||
def get_view(self, view_id=None, view_type="form", **options):
|
||||
"""Inject the dummy Many2one field in the search view"""
|
||||
result = super().get_view(view_id=view_id, view_type=view_type, **options)
|
||||
if view_type != "search":
|
||||
return result
|
||||
root = etree.fromstring(result["arch"])
|
||||
if root.xpath("//field[@name='date_range_search_id']"):
|
||||
# Field was inserted explicitely
|
||||
return result
|
||||
separator = etree.Element("separator")
|
||||
field = etree.Element(
|
||||
"field",
|
||||
attrib={
|
||||
"name": "date_range_search_id",
|
||||
"string": self.env._("Period"),
|
||||
},
|
||||
)
|
||||
groups = root.xpath("/search/group")
|
||||
if groups:
|
||||
groups[0].addprevious(separator)
|
||||
groups[0].addprevious(field)
|
||||
else:
|
||||
search = root.xpath("/search")
|
||||
search[0].append(separator)
|
||||
search[0].append(field)
|
||||
result["arch"] = etree.tostring(root, encoding="unicode")
|
||||
return result
|
||||
|
||||
@api.model
|
||||
def get_views(self, views, options=None):
|
||||
"""Adapt the label of the dummy search field
|
||||
|
||||
Ensure the technical name does not show up in the Custom Filter
|
||||
fields list (while still showing up in the Export widget)
|
||||
"""
|
||||
result = super().get_views(views, options=options)
|
||||
if "date_range_search_id" in result["models"][self._name]["fields"]:
|
||||
result["models"][self._name]["fields"]["date_range_search_id"]["string"] = (
|
||||
self.env._("Period")
|
||||
)
|
||||
return result
|
||||
Reference in New Issue
Block a user