Browse Source

base_jsonify: Allow fields aliasing in jsonify

13.0
Laurent Mignon (ACSONE) 8 years ago
committed by laurent.corron
parent
commit
dd2a3b9a1f
  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. 116
      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 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 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 Also the module provide a method "get_json_parser" on the ir.exports object
that generate a parser from an ir.exports configuration that generate a parser from an ir.exports configuration
Installation Installation
============ ============
@ -76,6 +98,7 @@ Contributors
------------ ------------
* BEAU Sébastien <sebastien.beau@akretion.com> * BEAU Sébastien <sebastien.beau@akretion.com>
* Laurent Mignon <laurent.mignon@acsone.eu>
Maintainer Maintainer
---------- ----------

1
base_jsonify/models/__init__.py

@ -6,3 +6,4 @@
from . import models from . import models
from . import ir_export 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> # Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from collections import OrderedDict
from openerp import api, models from openerp import api, models
@ -14,7 +15,7 @@ def update_dict(data, fields):
data[field] = True data[field] = True
else: else:
if field not in data: if field not in data:
data[field] = {}
data[field] = OrderedDict()
update_dict(data[field], fields[1:]) update_dict(data[field], fields[1:])
@ -34,7 +35,10 @@ class IrExport(models.Model):
@api.multi @api.multi
def get_json_parser(self): def get_json_parser(self):
self.ensure_one() self.ensure_one()
dict_parser = {}
dict_parser = OrderedDict()
for line in self.export_fields: 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) 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 _ 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 @api.multi
def jsonify(self, parser): def jsonify(self, parser):
""" Convert the record according to the parser given """ 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 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 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 = [] result = []
for rec in self: for rec in self:
res = {} res = {}
for field in parser: 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 field_type = rec._fields[field_name].type
if field_type in ('one2many', 'many2many'): 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': elif field_type == 'many2one':
data = rec[field_name].jsonify(subparser) data = rec[field_name].jsonify(subparser)
if data: if data:
res[field_name] = data[0]
res[json_key] = data[0]
else: else:
res[field_name] = None
res[json_key] = None
else: else:
raise UserError(_('Wrong parser configuration')) raise UserError(_('Wrong parser configuration'))
else: else:
res[field] = rec[field]
res[json_key] = rec[field_name]
result.append(res) result.append(res)
return result 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). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_get_parser from . import test_get_parser
from . import test_ir_exports_line

116
base_jsonify/tests/test_get_parser.py

@ -7,72 +7,88 @@ from openerp.tests.common import TransactionCase
class TestParser(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'lang',
u'comment', u'comment',
u'credit_limit', u'credit_limit',
u'name', u'name',
u'color', u'color',
(u'child_ids', [
(u'child_ids', [u'name']),
(u'child_ids:children', [
(u'child_ids:children', [u'name']),
u'email', u'email',
(u'country_id', [u'code', u'name']),
(u'country_id:country', [u'code', u'name']),
u'name', u'name',
u'id', u'id',
]),
(u'country_id', [u'code', u'name']),
]),
(u'country_id:country', [u'code', u'name']),
u'active', u'active',
(u'category_id', [u'name']) (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 = [{ expected_json = [{
u'lang': False, u'lang': False,
u'comment': False, u'comment': False,
u'credit_limit': 0.0, u'credit_limit': 0.0,
u'name': u'Camptocamp',
u'name': u'Akretion',
u'color': 0, u'color': 0,
u'country_id': {u'code': u'FR', u'name': u'France'},
u'child_ids': [{
u'id': 29,
u'country_id': {
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'country': {
u'code': u'FR',
u'name': u'France'
},
u'active': True, u'active': True,
u'category_id': [ 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