base_jsonify: support callable parser
parent
f947336f62
commit
e2e9bee9dc
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue