Browse Source

base_jsonify: Allow fields aliasing in jsonify

pull/1472/head
Laurent Mignon (ACSONE) 8 years ago
committed by Simone Orsi
parent
commit
32dfb8efe5
  1. 23
      base_jsonify/README.rst
  2. 1
      base_jsonify/models/__init__.py
  3. 10
      base_jsonify/models/ir_export.py
  4. 35
      base_jsonify/models/ir_exports_line.py
  5. 32
      base_jsonify/models/models.py
  6. 1
      base_jsonify/tests/__init__.py
  7. 108
      base_jsonify/tests/test_get_parser.py
  8. 45
      base_jsonify/tests/test_ir_exports_line.py

23
base_jsonify/README.rst

@ -25,10 +25,32 @@ Example of parser:
In order to be consitent with the odoo api the jsonify method always
return a list of object even if there is only one element in input
By default the key into the json is the name of the field extracted
from the model. If you need to specify an alternate name to use as key, you
can definne your mapping as follow into the parser definition:
.. code-block:: python
parser = [
'field_name:json_key'
]
.. code-block:: python
parser = [
'name',
'number',
'create_date:creationDate',
('partner_id:partners', ['id', 'display_name', 'ref'])
('line_id:lines', ['id', ('product_id', ['name']), 'price_unit'])
]
Also the module provide a method "get_json_parser" on the ir.exports object
that generate a parser from an ir.exports configuration
Installation
============
@ -76,6 +98,7 @@ Contributors
------------
* BEAU Sébastien <sebastien.beau@akretion.com>
* Laurent Mignon <laurent.mignon@acsone.eu>
Maintainer
----------

1
base_jsonify/models/__init__.py

@ -6,3 +6,4 @@
from . import models
from . import ir_export
from . import ir_exports_line

10
base_jsonify/models/ir_export.py

@ -3,6 +3,7 @@
# Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from collections import OrderedDict
from openerp import api, models
@ -14,7 +15,7 @@ def update_dict(data, fields):
data[field] = True
else:
if field not in data:
data[field] = {}
data[field] = OrderedDict()
update_dict(data[field], fields[1:])
@ -34,7 +35,10 @@ class IrExport(models.Model):
@api.multi
def get_json_parser(self):
self.ensure_one()
dict_parser = {}
dict_parser = OrderedDict()
for line in self.export_fields:
update_dict(dict_parser, line.name.split('/'))
names = line.name.split('/')
if line.alias:
names = line.alias.split('/')
update_dict(dict_parser, names)
return convert_dict(dict_parser)

35
base_jsonify/models/ir_exports_line.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Copyright 2017 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.exceptions import ValidationError
from openerp import api, fields, models, _
class IrExportsLine(models.Model):
_inherit = 'ir.exports.line'
_order = 'name'
alias = fields.Char(
'Alias',
help=_('The complete path to the field where you can specify an '
'alias on the a step as field:alias')
)
@api.constrains('alias', 'name')
def _check_alias(self):
for rec in self:
if not rec.alias:
continue
names = rec.name.split('/')
names_with_alias = rec.alias.split('/')
if len(names) != len(names_with_alias):
raise ValidationError(
_("Name and Alias must have the same hierarchy depth"))
for name, name_with_alias in zip(names, names_with_alias):
field_name = name_with_alias.split(':')[0]
if name != field_name:
raise ValidationError(
_("The alias must reference the same field as in "
"name '%s' not in '%s'") % (name, name_with_alias)
)

32
base_jsonify/models/models.py

@ -8,6 +8,17 @@ from openerp.exceptions import Warning as UserError
from openerp.tools.translate import _
def __parse_field(parser_field):
field_name = parser_field
subparser = None
if isinstance(parser_field, tuple):
field_name, subparser = parser_field
json_key = field_name
if ':' in field_name:
field_name, json_key = field_name.split(':')
return field_name, json_key, subparser
@api.multi
def jsonify(self, parser):
""" Convert the record according to the parser given
@ -22,26 +33,35 @@ def jsonify(self, parser):
In order to be consitent with the odoo api the jsonify method always
return a list of object even if there is only one element in input
By default the key into the json is the name of the field extracted
from the model. If you need to specify an alternate name to use as key, you
can definne your mapping as follow into the parser definition:
parser = [
'field_name:json_key'
]
"""
result = []
for rec in self:
res = {}
for field in parser:
if isinstance(field, tuple):
field_name, subparser = field
field_name, json_key, subparser = __parse_field(field)
if subparser:
field_type = rec._fields[field_name].type
if field_type in ('one2many', 'many2many'):
res[field_name] = rec[field_name].jsonify(subparser)
res[json_key] = rec[field_name].jsonify(subparser)
elif field_type == 'many2one':
data = rec[field_name].jsonify(subparser)
if data:
res[field_name] = data[0]
res[json_key] = data[0]
else:
res[field_name] = None
res[json_key] = None
else:
raise UserError(_('Wrong parser configuration'))
else:
res[field] = rec[field]
res[json_key] = rec[field_name]
result.append(res)
return result

1
base_jsonify/tests/__init__.py

@ -4,3 +4,4 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_get_parser
from . import test_ir_exports_line

108
base_jsonify/tests/test_get_parser.py

@ -7,72 +7,88 @@ from openerp.tests.common import TransactionCase
class TestParser(TransactionCase):
def setUp(self):
super(TestParser, self).setUp()
self.expected_parser = [
def test_getting_parser(self):
expected_parser = [
u'active',
(u'category_id', [u'name']),
(u'child_ids', [(
u'child_ids', [u'name']),
(u'country_id', [u'code', u'name']),
u'email', u'id',
u'name'
]),
u'color',
u'comment',
(u'country_id', [u'code', u'name']),
u'credit_limit',
u'lang',
u'name']
exporter = self.env.ref('base_jsonify.ir_exp_partner')
parser = exporter.get_json_parser()
self.assertEqual(parser, expected_parser)
# modify an ir.exports_line to put an alias for a field
self.env.ref('base_jsonify.category_id_name').write({
'alias': 'category_id:category/name'
})
expected_parser[1] = (u'category_id:category', [u'name'])
parser = exporter.get_json_parser()
self.assertEqual(parser, expected_parser)
def test_json_export(self):
parser = [
u'lang',
u'comment',
u'credit_limit',
u'name',
u'color',
(u'child_ids', [
(u'child_ids', [u'name']),
(u'child_ids:children', [
(u'child_ids:children', [u'name']),
u'email',
(u'country_id', [u'code', u'name']),
(u'country_id:country', [u'code', u'name']),
u'name',
u'id',
]),
(u'country_id', [u'code', u'name']),
(u'country_id:country', [u'code', u'name']),
u'active',
(u'category_id', [u'name'])
]
# TODO adapt data for 8.0
def fixme_test_getting_parser(self):
exporter = self.env.ref('base_jsonify.ir_exp_partner')
parser = exporter.get_json_parser()
self.assertEqual(parser, self.expected_parser)
def fixme_test_json_export(self):
partner = self.env['res.partner'].create({
'name': 'Akretion',
'country_id': self.env.ref('base.fr').id,
'category_id': [(0, 0, {'name': 'Inovator'})],
'child_ids': [
(0, 0, {
'name': 'Sebatien Beau',
'country_id': self.env.ref('base.fr').id
})
]
})
expected_json = [{
u'lang': False,
u'comment': False,
u'credit_limit': 0.0,
u'name': u'Camptocamp',
u'name': u'Akretion',
u'color': 0,
u'country_id': {u'code': u'FR', u'name': u'France'},
u'child_ids': [{
u'id': 29,
u'country_id': {
u'country': {
u'code': u'FR',
u'name': u'France'
},
u'child_ids': [],
u'email': u'ayaan.agarwal@bestdesigners.example.com',
u'name': u'Ayaan Agarwal'
}, {
u'id': 35,
u'country_id': {
u'code': u'FR',
u'name': u'France'},
u'child_ids': [],
u'email': u'benjamin.flores@nebula.example.com',
u'name': u'Benjamin Flores'
}, {
u'id': 28,
u'country_id': {
u'code': u'FR',
u'name': u'France'},
u'child_ids': [],
u'email': u'phillipp.miller@mediapole.example.com',
u'name': u'Phillipp Miller'
}],
u'active': True,
u'category_id': [
{u'name': u'Gold'},
{u'name': u'Services'}
]
{u'name': u'Inovator'}
],
u'children': [{
u'id': partner.child_ids.id,
u'country': {
u'code': u'FR',
u'name': u'France'
},
u'children': [],
u'name': u'Sebatien Beau',
u'email': False
}]
}]
partner = self.env.ref('base.res_partner_12')
json_partner = partner.jsonify(self.expected_parser)
self.assertEqual(json_partner, expected_json)
json_partner = partner.jsonify(parser)
self.assertDictEqual(json_partner[0], expected_json[0])

45
base_jsonify/tests/test_ir_exports_line.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
# © 2017 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp.exceptions import ValidationError
from openerp.tests.common import TransactionCase
class TestIrExportsLine(TransactionCase):
def setUp(self):
super(TestIrExportsLine, self).setUp()
self.ir_export = self.env.ref('base_jsonify.ir_exp_partner')
def test_alias_contrains(self):
ir_export_lines_model = self.env['ir.exports.line']
with self.assertRaises(ValidationError):
# The field into the name must be also into the alias
ir_export_lines_model.create({
'export_id': self.ir_export.id,
'name': 'name',
'alias': 'toto:my_alias'
})
with self.assertRaises(ValidationError):
# The hierarchy into the alias must be the same as the one into
# the name
ir_export_lines_model.create({
'export_id': self.ir_export.id,
'name': 'child_ids/child_ids/name',
'alias': 'child_ids:children/name'
})
with self.assertRaises(ValidationError):
# The hierarchy into the alias must be the same as the one into
# the name and must contains the same fields as into the name
ir_export_lines_model.create({
'export_id': self.ir_export.id,
'name': 'child_ids/child_ids/name',
'alias': 'child_ids:children/category_id:category/name'
})
line = ir_export_lines_model.create({
'export_id': self.ir_export.id,
'name': 'child_ids/child_ids/name',
'alias': 'child_ids:children/child_ids:children/name'
})
self.assertTrue(line)
Loading…
Cancel
Save