# © 2017 Akretion (http://www.akretion.com) # Sébastien BEAU # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). from collections import OrderedDict from odoo import fields, models from odoo.tools import ormcache def partition(line, accessor): """Partition a recordset according to an accessor (e.g. a lambda). Returns a dictionary whose keys are the values obtained from accessor, and values are the items that have this value. Example: partition([{"name": "ax"}, {"name": "by"}], lambda x: "x" in x["name"]) => {True: [{"name": "ax"}], False: [{"name": "by"}]} """ result = {} for item in line: key = accessor(item) if key not in result: result[key] = [] result[key].append(item) return result def update_dict(data, fields, options): """Contruct a tree of fields. Example: { "name": True, "resource": True, } Order of keys is important. """ field = fields[0] if len(fields) == 1: if field == ".id": field = "id" data[field] = (True, options) else: if field not in data: data[field] = (False, OrderedDict()) update_dict(data[field][1], fields[1:], options) def convert_dict(dict_parser): """Convert dict returned by update_dict to list consistent w/ Odoo API. The list is composed of strings (field names or targets) or tuples. """ parser = [] for field, value in dict_parser.items(): if value[0] is True: # is a leaf parser.append(field_dict(field, value[1])) else: parser.append((field_dict(field), convert_dict(value[1]))) return parser def field_dict(field, options=None): """Create a parser dict for the field field.""" result = {"name": field.split(":")[0]} if len(field.split(":")) > 1: result["target"] = field.split(":")[1] for option in options or {}: if options[option]: result[option] = options[option] return result class IrExports(models.Model): _inherit = "ir.exports" language_agnostic = fields.Boolean( default=False, help="If set, will set the lang to False when exporting lines without lang," " otherwise it uses the lang in the given context to export these fields", ) global_resolver_id = fields.Many2one( comodel_name="ir.exports.resolver", string="Custom global resolver", domain="[('type', '=', 'global')]", help="If set, will apply the global resolver to the result", ) @ormcache( "self.language_agnostic", "self.global_resolver_id.id", "tuple(self.export_fields.mapped('write_date'))", ) def get_json_parser(self): """Creates a parser from ir.exports record and return it. The final parser can be used to "jsonify" records of ir.export's model. """ self.ensure_one() parser = {} lang_to_lines = partition(self.export_fields, lambda l: l.lang_id.code) lang_parsers = {} for lang in lang_to_lines: dict_parser = OrderedDict() for line in lang_to_lines[lang]: names = line.name.split("/") if line.target: names = line.target.split("/") function = line.instance_method_name options = {"resolver": line.resolver_id, "function": function} update_dict(dict_parser, names, options) lang_parsers[lang] = convert_dict(dict_parser) if list(lang_parsers.keys()) == [False]: parser["fields"] = lang_parsers[False] else: parser["langs"] = lang_parsers if self.global_resolver_id: parser["resolver"] = self.global_resolver_id if self.language_agnostic: parser["language_agnostic"] = self.language_agnostic return parser