diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index eb30002db..f75d8f21b 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -1,6 +1,8 @@ -# © 2017 Akretion (http://www.akretion.com) +# Copyright 2017 Akretion (http://www.akretion.com) # Sébastien BEAU # Raphaël Reverdy +# Copyright 2020 Camptocamp SA (http://www.camptocamp.com) +# Simone Orsi # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models @@ -33,6 +35,8 @@ class Base(models.AbstractModel): 'number', 'create_date', ('partner_id', ['id', 'display_name', 'ref']) + ('shipping_id', callable) + ('delivery_id', "record_method") ('line_id', ['id', ('product_id', ['name']), 'price_unit']) ] @@ -64,6 +68,7 @@ class Base(models.AbstractModel): def _jsonify_value(self, field_name): field_type = self._fields[field_name].type value = self[field_name] + # TODO: we should get default by field (eg: char field -> "") if value is False and field_type != "boolean": value = None elif field_type == "date": @@ -79,15 +84,26 @@ class Base(models.AbstractModel): return value def _jsonify_value_subparser(self, field_name, subparser): - field_type = self._fields[field_name].type - if field_type in ("one2many", "many2many"): - value = self[field_name].jsonify(subparser) - elif field_type in ("many2one", "reference"): - if self[field_name]: - value = self[field_name].jsonify(subparser)[0] + value = None + if callable(subparser): + # a simple function + value = subparser(self, field_name) + elif isinstance(subparser, str): + # a method on the record itself + method = getattr(self, subparser, None) + if method: + value = method(field_name) else: - # TODO: we should get this by field (eg: char field -> "") - value = None + self._jsonify_bad_parser_error(field_name) else: - raise UserError(_("Wrong parser configuration")) + field = self._fields[field_name] + if not (field.relational or field.type == "reference"): + self._jsonify_bad_parser_error(field_name) + rec_value = self[field_name] + value = rec_value.jsonify(subparser) if rec_value else [] + if field.type in ("many2one", "reference"): + value = value[0] if value else None return value + + def _jsonify_bad_parser_error(self, field_name): + raise UserError(_("Wrong parser configuration for field: `%s`") % field_name) diff --git a/base_jsonify/readme/DESCRIPTION.rst b/base_jsonify/readme/DESCRIPTION.rst index 115e75c0d..93012ac1c 100644 --- a/base_jsonify/readme/DESCRIPTION.rst +++ b/base_jsonify/readme/DESCRIPTION.rst @@ -39,5 +39,15 @@ can define your mapping as follow into the parser definition: ('line_id:lines', ['id', ('product_id', ['name']), 'price_unit']) ] +If you need to parse the value of a field in a custom way, +you can pass a callable or the name of a method on the model: + +.. code-block:: python + + parser = [ + ('name', "jsonify_name") # method name + ('number', lambda rec, field_name: rec[field_name] * 2)) # callable + ] + Also the module provide a method "get_json_parser" on the ir.exports object that generate a parser from an ir.exports configuration. diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index 9c9b79a32..9e616025d 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -5,6 +5,10 @@ from odoo import fields from odoo.tests.common import TransactionCase +def jsonify_custom(self, field_name): + return "yeah!" + + class TestParser(TransactionCase): def test_getting_parser(self): expected_parser = [ @@ -114,10 +118,6 @@ class TestParser(TransactionCase): self.assertDictEqual(json_partner[0], expected_json) - json_partner = partner.jsonify(parser) - - self.assertDictEqual(json_partner[0], expected_json) - # Check that only boolean fields have boolean values into json # By default if a field is not set into Odoo, the value is always False # This value is not the expected one into the json @@ -127,3 +127,38 @@ class TestParser(TransactionCase): expected_json["lang"] = None expected_json["children"] = [] self.assertDictEqual(json_partner[0], expected_json) + + def test_json_export_callable_parser(self): + # Enforces TZ to validate the serialization result of a Datetime + partner = self.env["res.partner"].create( + { + "name": "Akretion", + "country_id": self.env.ref("base.fr").id, + "lang": "en_US", # default + "category_id": [(0, 0, {"name": "Inovator"})], + "child_ids": [ + ( + 0, + 0, + { + "name": "Sebatien Beau", + "country_id": self.env.ref("base.fr").id, + }, + ) + ], + "date": fields.Date.from_string("2019-10-31"), + } + ) + partner.__class__.jsonify_custom = jsonify_custom + parser = [ + # callable subparser + ("name", lambda rec, fname: rec[fname] + " rocks!"), + ("name:custom", "jsonify_custom"), + ] + expected_json = { + "name": "Akretion rocks!", + "custom": "yeah!", + } + json_partner = partner.jsonify(parser) + self.assertDictEqual(json_partner[0], expected_json) + del partner.__class__.jsonify_custom