base_jsonify: support callable parser

pull/2418/head
Simone Orsi 2020-05-08 13:22:33 +02:00 committed by Sébastien BEAU
parent f947336f62
commit e2e9bee9dc
3 changed files with 75 additions and 14 deletions

View File

@ -1,6 +1,8 @@
# © 2017 Akretion (http://www.akretion.com)
# Copyright 2017 Akretion (http://www.akretion.com)
# Sébastien BEAU <sebastien.beau@akretion.com>
# Raphaël Reverdy <raphael.reverdy@akretion.com>
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com)
# Simone Orsi <simahawk@gmail.com>
# 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)

View File

@ -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.

View File

@ -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