From 5b2678e6b7ea067de28db0d578360b63166fb1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Thu, 19 May 2016 08:57:22 +0200 Subject: [PATCH 01/18] add base_jsonify module --- base_jsonify/README.rst | 89 +++++++++++++++++++++++++++ base_jsonify/__init__.py | 7 +++ base_jsonify/__openerp__.py | 29 +++++++++ base_jsonify/demo/export_demo.xml | 11 ++++ base_jsonify/demo/ir.exports.line.csv | 16 +++++ base_jsonify/models/__init__.py | 8 +++ base_jsonify/models/ir_export.py | 38 ++++++++++++ base_jsonify/models/models.py | 44 +++++++++++++ base_jsonify/tests/__init__.py | 6 ++ base_jsonify/tests/test_get_parser.py | 77 +++++++++++++++++++++++ 10 files changed, 325 insertions(+) create mode 100644 base_jsonify/README.rst create mode 100644 base_jsonify/__init__.py create mode 100644 base_jsonify/__openerp__.py create mode 100644 base_jsonify/demo/export_demo.xml create mode 100644 base_jsonify/demo/ir.exports.line.csv create mode 100644 base_jsonify/models/__init__.py create mode 100644 base_jsonify/models/ir_export.py create mode 100644 base_jsonify/models/models.py create mode 100644 base_jsonify/tests/__init__.py create mode 100644 base_jsonify/tests/test_get_parser.py diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst new file mode 100644 index 000000000..d0942f7e5 --- /dev/null +++ b/base_jsonify/README.rst @@ -0,0 +1,89 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +============== +Base Jsonify +============== + +This module add the jsonify method to the ORM. This method take as argument +the browse record and the "parser" that specify the field to extract. + +Example of parser: + parser = [ + 'name', + 'number', + 'create_date', + ('partner_id', ['id', 'display_name', 'ref']) + ('line_id', ['id', ('product_id', ['name']), 'price_unit']) + ] + +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 + +Also the module provide a method "get_json_parser" on the ir.exports object +that generate a parser from an ir.exports configuration + + +Installation +============ + +To install this module, you need to install it + +Configuration +============= + +No configuration required + +Usage +===== + +This is a technical module not function feature is added + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch} + +.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt +.. branch is "8.0" for example + +Known issues / Roadmap +====================== + +Nothing yet + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed feedback. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* BEAU Sébastien + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/base_jsonify/__init__.py b/base_jsonify/__init__.py new file mode 100644 index 000000000..d34d08cb1 --- /dev/null +++ b/base_jsonify/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from . import models diff --git a/base_jsonify/__openerp__.py b/base_jsonify/__openerp__.py new file mode 100644 index 000000000..85335e22d --- /dev/null +++ b/base_jsonify/__openerp__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Base Jsonify", + "summary": "Base module that provide the jsonify method on all object", + "version": "9.0.1.0.0", + "category": "Uncategorized", + "website": "https://odoo-community.org/", + "author": "Akretion, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "external_dependencies": { + "python": [], + "bin": [], + }, + "depends": [ + "base", + ], + "data": [ + ], + "demo": [ + 'demo/export_demo.xml', + 'demo/ir.exports.line.csv', + ], +} diff --git a/base_jsonify/demo/export_demo.xml b/base_jsonify/demo/export_demo.xml new file mode 100644 index 000000000..4501b77d3 --- /dev/null +++ b/base_jsonify/demo/export_demo.xml @@ -0,0 +1,11 @@ + + + + + + Partner Export + res.partner + + + + diff --git a/base_jsonify/demo/ir.exports.line.csv b/base_jsonify/demo/ir.exports.line.csv new file mode 100644 index 000000000..476de3937 --- /dev/null +++ b/base_jsonify/demo/ir.exports.line.csv @@ -0,0 +1,16 @@ +id,export_id/id,name +name,ir_exp_partner,name +active,ir_exp_partner,active +credit_limit,ir_exp_partner,credit_limit +color,ir_exp_partner,color +category_id_name,ir_exp_partner,category_id/name +country_id_name,ir_exp_partner,country_id/name +country_id_code,ir_exp_partner,country_id/code +child_ids_name,ir_exp_partner,child_ids/name +child_ids_id,ir_exp_partner,child_ids/id +child_ids_email,ir_exp_partner,child_ids/email +child_ids_country_id_name,ir_exp_partner,child_ids/country_id/name +child_ids_country_id_code,ir_exp_partner,child_ids/country_id/code +child_ids_child_ids_name,ir_exp_partner,child_ids/child_ids/name +lang,ir_exp_partner,lang +comment,ir_exp_partner,comment diff --git a/base_jsonify/models/__init__.py b/base_jsonify/models/__init__.py new file mode 100644 index 000000000..15dcb2f3d --- /dev/null +++ b/base_jsonify/models/__init__.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from . import models +from . import ir_export diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py new file mode 100644 index 000000000..472c765d8 --- /dev/null +++ b/base_jsonify/models/ir_export.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import api, models + + +def update_dict(data, fields): + field = fields[0] + if len(fields) == 1: + data[field] = True + else: + if field not in data: + data[field] = {} + update_dict(data[field], fields[1:]) + + +def convert_dict(dict_parser): + parser = [] + for field, value in dict_parser.iteritems(): + if value is True: + parser.append(field) + else: + parser.append((field, convert_dict(value))) + return parser + + +class IrExport(models.Model): + _inherit = 'ir.exports' + + @api.multi + def get_json_parser(self): + self.ensure_one() + dict_parser = {} + for line in self.export_fields: + update_dict(dict_parser, line.name.split('/')) + return convert_dict(dict_parser) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py new file mode 100644 index 000000000..fa815a33a --- /dev/null +++ b/base_jsonify/models/models.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import api, models +from openerp.exceptions import UserError + + +@api.multi +def jsonify(self, parser): + """ Convert the record according to the parser given + Example of parser: + parser = [ + 'name', + 'number', + 'create_date', + ('partner_id', ['id', 'display_name', 'ref']) + ('line_id', ['id', ('product_id', ['name']), 'price_unit']) + ] + + 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 + """ + result = [] + for rec in self: + res = {} + for field in parser: + if isinstance(field, tuple): + field_name, subparser = field + field_type = rec._fields[field_name].type + if field_type in ('one2many', 'many2many'): + res[field_name] = rec[field_name].jsonify(subparser) + elif field_type == 'many2one': + res[field_name] = rec[field_name].jsonify(subparser)[0] + else: + raise UserError('Wrong parser configuration') + else: + res[field] = rec[field] + result.append(res) + return result + + +models.Model.jsonify = jsonify diff --git a/base_jsonify/tests/__init__.py b/base_jsonify/tests/__init__.py new file mode 100644 index 000000000..8ed730c5e --- /dev/null +++ b/base_jsonify/tests/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (http://www.akretion.com) +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_get_parser diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py new file mode 100644 index 000000000..67c607fc5 --- /dev/null +++ b/base_jsonify/tests/test_get_parser.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# © +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from openerp.tests.common import TransactionCase + + +class TestParser(TransactionCase): + + def setUp(self): + super(TestParser, self).setUp() + self.expected_parser = [ + u'lang', + u'comment', + u'credit_limit', + u'name', + u'color', + (u'child_ids', [ + (u'child_ids', [u'name']), + u'email', + (u'country_id', [u'code', u'name']), + u'name', + u'id', + ]), + (u'country_id', [u'code', u'name']), + u'active', + (u'category_id', [u'name']) + ] + + def 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 test_json_export(self): + expected_json = [{ + u'lang': False, + u'comment': False, + u'credit_limit': 0.0, + u'name': u'Camptocamp', + 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'active': True, + u'category_id': [ + {u'name': u'Gold'}, + {u'name': u'Services'} + ] + }] + partner = self.env.ref('base.res_partner_12') + json_partner = partner.jsonify(self.expected_parser) + self.assertEqual(json_partner, expected_json) From b677325127adf8b0a168d93bf180b7838c75b2ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Thu, 19 May 2016 09:16:47 +0200 Subject: [PATCH 02/18] if '.id' is used replaced it by id --- base_jsonify/models/ir_export.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py index 472c765d8..e1ac0ccc4 100644 --- a/base_jsonify/models/ir_export.py +++ b/base_jsonify/models/ir_export.py @@ -9,6 +9,8 @@ from openerp import api, models def update_dict(data, fields): field = fields[0] if len(fields) == 1: + if field == '.id': + field = 'id' data[field] = True else: if field not in data: From d4222b883717260ae84ef39b51ecbc119f357dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Wed, 21 Dec 2016 16:12:29 +0100 Subject: [PATCH 03/18] fix getting value of many2one if the value is None --- base_jsonify/models/models.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index fa815a33a..1bbbda166 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -32,7 +32,11 @@ def jsonify(self, parser): if field_type in ('one2many', 'many2many'): res[field_name] = rec[field_name].jsonify(subparser) elif field_type == 'many2one': - res[field_name] = rec[field_name].jsonify(subparser)[0] + data = rec[field_name].jsonify(subparser) + if data: + res[field_name] = data[0] + else: + res[field_name] = None else: raise UserError('Wrong parser configuration') else: From b135375dfa581cb1b5dd93d2aad9ae7603c13b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Wed, 21 Dec 2016 16:14:22 +0100 Subject: [PATCH 04/18] fix complatibility with 8 --- base_jsonify/models/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 1bbbda166..bf92be980 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import api, models -from openerp.exceptions import UserError +from openerp.exceptions import Warning as UserError @api.multi From 16d7dc6608bad72d06c15214d3155177b4cf5943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Thu, 23 Mar 2017 15:35:11 +0100 Subject: [PATCH 05/18] fix travis --- base_jsonify/README.rst | 4 ++++ base_jsonify/__openerp__.py | 2 +- base_jsonify/models/models.py | 3 ++- base_jsonify/tests/test_get_parser.py | 5 +++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst index d0942f7e5..dc0b04ad1 100644 --- a/base_jsonify/README.rst +++ b/base_jsonify/README.rst @@ -10,6 +10,10 @@ This module add the jsonify method to the ORM. This method take as argument the browse record and the "parser" that specify the field to extract. Example of parser: + + +.. code-block:: python + parser = [ 'name', 'number', diff --git a/base_jsonify/__openerp__.py b/base_jsonify/__openerp__.py index 85335e22d..ad47b797d 100644 --- a/base_jsonify/__openerp__.py +++ b/base_jsonify/__openerp__.py @@ -6,7 +6,7 @@ { "name": "Base Jsonify", "summary": "Base module that provide the jsonify method on all object", - "version": "9.0.1.0.0", + "version": "8.0.1.0.0", "category": "Uncategorized", "website": "https://odoo-community.org/", "author": "Akretion, Odoo Community Association (OCA)", diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index bf92be980..3c9834d0b 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -5,6 +5,7 @@ from openerp import api, models from openerp.exceptions import Warning as UserError +from openerp.tools.translate import _ @api.multi @@ -38,7 +39,7 @@ def jsonify(self, parser): else: res[field_name] = None else: - raise UserError('Wrong parser configuration') + raise UserError(_('Wrong parser configuration')) else: res[field] = rec[field] result.append(res) diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index 67c607fc5..a99eb6e7a 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -27,12 +27,13 @@ class TestParser(TransactionCase): (u'category_id', [u'name']) ] - def test_getting_parser(self): + # 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 test_json_export(self): + def fixme_test_json_export(self): expected_json = [{ u'lang': False, u'comment': False, From cee3f012bb8ad8a121574fa19a1b38f93e0f98f4 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Wed, 31 May 2017 21:45:10 +0200 Subject: [PATCH 06/18] base_jsonify: Allow fields aliasing in jsonify --- base_jsonify/README.rst | 23 ++++ base_jsonify/models/__init__.py | 1 + base_jsonify/models/ir_export.py | 10 +- base_jsonify/models/ir_exports_line.py | 35 +++++++ base_jsonify/models/models.py | 32 ++++-- base_jsonify/tests/__init__.py | 1 + base_jsonify/tests/test_get_parser.py | 116 ++++++++++++--------- base_jsonify/tests/test_ir_exports_line.py | 45 ++++++++ 8 files changed, 204 insertions(+), 59 deletions(-) create mode 100644 base_jsonify/models/ir_exports_line.py create mode 100644 base_jsonify/tests/test_ir_exports_line.py diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst index dc0b04ad1..654d627e6 100644 --- a/base_jsonify/README.rst +++ b/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 +* Laurent Mignon Maintainer ---------- diff --git a/base_jsonify/models/__init__.py b/base_jsonify/models/__init__.py index 15dcb2f3d..c6621497b 100644 --- a/base_jsonify/models/__init__.py +++ b/base_jsonify/models/__init__.py @@ -6,3 +6,4 @@ from . import models from . import ir_export +from . import ir_exports_line diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py index e1ac0ccc4..810c79087 100644 --- a/base_jsonify/models/ir_export.py +++ b/base_jsonify/models/ir_export.py @@ -3,6 +3,7 @@ # Sébastien BEAU # 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) diff --git a/base_jsonify/models/ir_exports_line.py b/base_jsonify/models/ir_exports_line.py new file mode 100644 index 000000000..a1e2cd6c3 --- /dev/null +++ b/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) + ) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 3c9834d0b..bcee877dc 100644 --- a/base_jsonify/models/models.py +++ b/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 diff --git a/base_jsonify/tests/__init__.py b/base_jsonify/tests/__init__.py index 8ed730c5e..837c1145d 100644 --- a/base_jsonify/tests/__init__.py +++ b/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 diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index a99eb6e7a..76db9f3dc 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/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'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'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]) diff --git a/base_jsonify/tests/test_ir_exports_line.py b/base_jsonify/tests/test_ir_exports_line.py new file mode 100644 index 000000000..3622ced8c --- /dev/null +++ b/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) From c5cfd522e3a9a5d66f3eec5d64635c3592fe6d99 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Fri, 2 Jun 2017 10:21:22 +0200 Subject: [PATCH 07/18] base_jsonify: typo --- base_jsonify/README.rst | 2 +- base_jsonify/models/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst index 654d627e6..55e0e61db 100644 --- a/base_jsonify/README.rst +++ b/base_jsonify/README.rst @@ -27,7 +27,7 @@ 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: +can define your mapping as follow into the parser definition: .. code-block:: python diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index bcee877dc..08ba30a4a 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -36,7 +36,7 @@ def jsonify(self, parser): 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: + can define your mapping as follow into the parser definition: parser = [ 'field_name:json_key' From 7a87739adb5cdad3b5f2ce64bb98d88eab4733c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Thu, 22 Jun 2017 12:46:43 +0200 Subject: [PATCH 08/18] add support of reference fields --- base_jsonify/models/models.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 08ba30a4a..e6d651e02 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -52,10 +52,9 @@ def jsonify(self, parser): field_type = rec._fields[field_name].type if field_type in ('one2many', 'many2many'): res[json_key] = rec[field_name].jsonify(subparser) - elif field_type == 'many2one': - data = rec[field_name].jsonify(subparser) - if data: - res[json_key] = data[0] + elif field_type in ('many2one', 'reference'): + if rec[field_name]: + res[json_key] = rec[field_name].jsonify(subparser)[0] else: res[json_key] = None else: From 6b47e49a7cf3fd9d387d8a9c6780d3f59306cc5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20BEAU?= Date: Fri, 23 Jun 2017 15:46:44 +0200 Subject: [PATCH 09/18] remove False for int, float, string --- base_jsonify/models/models.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index e6d651e02..60b41ccb2 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -44,12 +44,18 @@ def jsonify(self, parser): """ result = [] + empty_value = { + 'char': '', + 'int': 0, + 'float': 0, + } + for rec in self: res = {} for field in parser: field_name, json_key, subparser = __parse_field(field) + field_type = rec._fields[field_name].type if subparser: - field_type = rec._fields[field_name].type if field_type in ('one2many', 'many2many'): res[json_key] = rec[field_name].jsonify(subparser) elif field_type in ('many2one', 'reference'): @@ -61,6 +67,8 @@ def jsonify(self, parser): raise UserError(_('Wrong parser configuration')) else: res[json_key] = rec[field_name] + if not res[json_key] and field_type in empty_value: + res[json_key] = empty_value[field_type] result.append(res) return result From 18f3b207c9a00ef6a116f2840dffee5f74539022 Mon Sep 17 00:00:00 2001 From: hpar Date: Mon, 2 Oct 2017 12:08:12 +0200 Subject: [PATCH 10/18] Remove copyrights from init and update copyrights --- base_jsonify/README.rst | 7 ++++--- base_jsonify/__init__.py | 5 ----- base_jsonify/__openerp__.py | 5 +++-- base_jsonify/demo/export_demo.xml | 16 ++++++---------- base_jsonify/models/__init__.py | 5 ----- base_jsonify/models/ir_export.py | 2 +- base_jsonify/models/models.py | 3 ++- base_jsonify/tests/__init__.py | 4 ---- 8 files changed, 16 insertions(+), 31 deletions(-) diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst index 55e0e61db..d50eb10ba 100644 --- a/base_jsonify/README.rst +++ b/base_jsonify/README.rst @@ -2,9 +2,9 @@ :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 -============== +============ Base Jsonify -============== +============ This module add the jsonify method to the ORM. This method take as argument the browse record and the "parser" that specify the field to extract. @@ -76,7 +76,7 @@ This is a technical module not function feature is added Known issues / Roadmap ====================== -Nothing yet +No distinction between float 0.0L and no value Bug Tracker =========== @@ -98,6 +98,7 @@ Contributors ------------ * BEAU Sébastien +* Raphaël Reverdy * Laurent Mignon Maintainer diff --git a/base_jsonify/__init__.py b/base_jsonify/__init__.py index d34d08cb1..a0fdc10fe 100644 --- a/base_jsonify/__init__.py +++ b/base_jsonify/__init__.py @@ -1,7 +1,2 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) -# Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - from . import models diff --git a/base_jsonify/__openerp__.py b/base_jsonify/__openerp__.py index ad47b797d..c0d746be7 100644 --- a/base_jsonify/__openerp__.py +++ b/base_jsonify/__openerp__.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) +# © 2017 Akretion (http://www.akretion.com) # Sébastien BEAU +# Raphaël Reverdy # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Base Jsonify", "summary": "Base module that provide the jsonify method on all object", - "version": "8.0.1.0.0", + "version": "10.0.1.0.0", "category": "Uncategorized", "website": "https://odoo-community.org/", "author": "Akretion, Odoo Community Association (OCA)", diff --git a/base_jsonify/demo/export_demo.xml b/base_jsonify/demo/export_demo.xml index 4501b77d3..a9030c6de 100644 --- a/base_jsonify/demo/export_demo.xml +++ b/base_jsonify/demo/export_demo.xml @@ -1,11 +1,7 @@ - - - - - Partner Export - res.partner - - - - + + + Partner Export + res.partner + + \ No newline at end of file diff --git a/base_jsonify/models/__init__.py b/base_jsonify/models/__init__.py index c6621497b..635654e95 100644 --- a/base_jsonify/models/__init__.py +++ b/base_jsonify/models/__init__.py @@ -1,9 +1,4 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) -# Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - - from . import models from . import ir_export from . import ir_exports_line diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py index 810c79087..f52616ec1 100644 --- a/base_jsonify/models/ir_export.py +++ b/base_jsonify/models/ir_export.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) +# © 2017 Akretion (http://www.akretion.com) # Sébastien BEAU # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 60b41ccb2..5144813e4 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) +# © 2017 Akretion (http://www.akretion.com) # Sébastien BEAU +# Raphaël Reverdy # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import api, models diff --git a/base_jsonify/tests/__init__.py b/base_jsonify/tests/__init__.py index 837c1145d..bf58ee4e9 100644 --- a/base_jsonify/tests/__init__.py +++ b/base_jsonify/tests/__init__.py @@ -1,7 +1,3 @@ # -*- coding: utf-8 -*- -# © 2016 Akretion (http://www.akretion.com) -# Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - from . import test_get_parser from . import test_ir_exports_line From d41e39f030e49ceb0d1b5c22e72f70ce5df14609 Mon Sep 17 00:00:00 2001 From: hpar Date: Mon, 2 Oct 2017 12:08:56 +0200 Subject: [PATCH 11/18] Fix tests and add fix nullable fields --- base_jsonify/models/models.py | 7 ++++--- base_jsonify/tests/test_get_parser.py | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 5144813e4..c0e60e60d 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -46,9 +46,10 @@ def jsonify(self, parser): """ result = [] empty_value = { - 'char': '', - 'int': 0, - 'float': 0, + 'char': None, + 'int': None, + # 'float': None, TODO: 0.0 != False + 'text': None, } for rec in self: diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index 76db9f3dc..4bf0eb65a 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -57,17 +57,18 @@ class TestParser(TransactionCase): 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 }) - ] + ], }) expected_json = [{ - u'lang': False, - u'comment': False, + u'lang': u'en_US', + u'comment': None, u'credit_limit': 0.0, u'name': u'Akretion', u'color': 0, @@ -87,8 +88,9 @@ class TestParser(TransactionCase): }, u'children': [], u'name': u'Sebatien Beau', - u'email': False + u'email': None }] }] json_partner = partner.jsonify(parser) + self.assertDictEqual(json_partner[0], expected_json[0]) From e0df00d494588cb58c797a17bd790a7f5762d551 Mon Sep 17 00:00:00 2001 From: hpar Date: Mon, 2 Oct 2017 14:29:51 +0200 Subject: [PATCH 12/18] from openerp -> from odoo< --- base_jsonify/{__openerp__.py => __manifest__.py} | 0 base_jsonify/models/ir_export.py | 2 +- base_jsonify/models/ir_exports_line.py | 4 ++-- base_jsonify/models/models.py | 6 +++--- base_jsonify/tests/test_get_parser.py | 2 +- base_jsonify/tests/test_ir_exports_line.py | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) rename base_jsonify/{__openerp__.py => __manifest__.py} (100%) diff --git a/base_jsonify/__openerp__.py b/base_jsonify/__manifest__.py similarity index 100% rename from base_jsonify/__openerp__.py rename to base_jsonify/__manifest__.py diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py index f52616ec1..feae5cddf 100644 --- a/base_jsonify/models/ir_export.py +++ b/base_jsonify/models/ir_export.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from collections import OrderedDict -from openerp import api, models +from odoo import api, models def update_dict(data, fields): diff --git a/base_jsonify/models/ir_exports_line.py b/base_jsonify/models/ir_exports_line.py index a1e2cd6c3..6e27a844a 100644 --- a/base_jsonify/models/ir_exports_line.py +++ b/base_jsonify/models/ir_exports_line.py @@ -2,8 +2,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, _ +from odoo.exceptions import ValidationError +from odoo import api, fields, models, _ class IrExportsLine(models.Model): diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index c0e60e60d..85af44877 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -4,9 +4,9 @@ # Raphaël Reverdy # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from openerp import api, models -from openerp.exceptions import Warning as UserError -from openerp.tools.translate import _ +from odoo import api, models +from odoo.exceptions import Warning as UserError +from odoo.tools.translate import _ def __parse_field(parser_field): diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index 4bf0eb65a..e73267fb2 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -2,7 +2,7 @@ # © # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from openerp.tests.common import TransactionCase +from odoo.tests.common import TransactionCase class TestParser(TransactionCase): diff --git a/base_jsonify/tests/test_ir_exports_line.py b/base_jsonify/tests/test_ir_exports_line.py index 3622ced8c..020f9b25c 100644 --- a/base_jsonify/tests/test_ir_exports_line.py +++ b/base_jsonify/tests/test_ir_exports_line.py @@ -2,8 +2,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 +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase class TestIrExportsLine(TransactionCase): From bbff9dc62001fd0f77d35bac8130d7480108df3e Mon Sep 17 00:00:00 2001 From: hpar Date: Tue, 3 Oct 2017 10:27:36 +0200 Subject: [PATCH 13/18] Fix monkey patchin --- base_jsonify/models/models.py | 120 +++++++++++++++++----------------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 85af44877..5a6afc7a2 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -5,74 +5,76 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import api, models -from odoo.exceptions import Warning as UserError +from odoo.exceptions import UserError from odoo.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 +class Base(models.AbstractModel): + _inherit = 'base' -@api.multi -def jsonify(self, parser): - """ Convert the record according to the parser given - Example of parser: - parser = [ - 'name', - 'number', - 'create_date', - ('partner_id', ['id', 'display_name', 'ref']) - ('line_id', ['id', ('product_id', ['name']), 'price_unit']) - ] + @api.model + def __parse_field(self, 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 - 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 define your mapping as follow into the parser definition: + @api.multi + def jsonify(self, parser): + """ Convert the record according to the parser given + Example of parser: + parser = [ + 'name', + 'number', + 'create_date', + ('partner_id', ['id', 'display_name', 'ref']) + ('line_id', ['id', ('product_id', ['name']), 'price_unit']) + ] - parser = [ - 'field_name:json_key' - ] + 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 - """ - result = [] - empty_value = { - 'char': None, - 'int': None, - # 'float': None, TODO: 0.0 != False - 'text': None, - } + 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 define your mapping as follow into the parser definition: - for rec in self: - res = {} - for field in parser: - field_name, json_key, subparser = __parse_field(field) - field_type = rec._fields[field_name].type - if subparser: - if field_type in ('one2many', 'many2many'): - res[json_key] = rec[field_name].jsonify(subparser) - elif field_type in ('many2one', 'reference'): - if rec[field_name]: - res[json_key] = rec[field_name].jsonify(subparser)[0] - else: - res[json_key] = None - else: - raise UserError(_('Wrong parser configuration')) - else: - res[json_key] = rec[field_name] - if not res[json_key] and field_type in empty_value: - res[json_key] = empty_value[field_type] - result.append(res) - return result + parser = [ + 'field_name:json_key' + ] + """ + result = [] + empty_value = { + 'char': None, + 'int': None, + # 'float': None, TODO: 0.0 != False + 'text': None, + } -models.Model.jsonify = jsonify + for rec in self: + res = {} + for field in parser: + field_name, json_key, subparser = self.__parse_field(field) + field_type = rec._fields[field_name].type + if subparser: + if field_type in ('one2many', 'many2many'): + res[json_key] = rec[field_name].jsonify(subparser) + elif field_type in ('many2one', 'reference'): + if rec[field_name]: + res[json_key] = rec[field_name].jsonify(subparser)[0] + else: + res[json_key] = None + else: + raise UserError(_('Wrong parser configuration')) + else: + res[json_key] = rec[field_name] + if not res[json_key] and field_type in empty_value: + res[json_key] = empty_value[field_type] + result.append(res) + return result From 3ca15ceada6c48ac9e6a87f41c41719dcfe4ca89 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Wed, 22 Aug 2018 12:02:35 +0200 Subject: [PATCH 14/18] base_jsonify: Output 'false' into json only for boolean fields --- base_jsonify/models/models.py | 13 ++++--------- base_jsonify/tests/test_get_parser.py | 22 +++++++++++++++++++--- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 5a6afc7a2..d4b9b678d 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -50,12 +50,6 @@ class Base(models.AbstractModel): """ result = [] - empty_value = { - 'char': None, - 'int': None, - # 'float': None, TODO: 0.0 != False - 'text': None, - } for rec in self: res = {} @@ -73,8 +67,9 @@ class Base(models.AbstractModel): else: raise UserError(_('Wrong parser configuration')) else: - res[json_key] = rec[field_name] - if not res[json_key] and field_type in empty_value: - res[json_key] = empty_value[field_type] + value = rec[field_name] + if value is False and field_type != 'boolean': + value = None + res[json_key] = value result.append(res) return result diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index e73267fb2..80d5b354a 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -66,7 +66,7 @@ class TestParser(TransactionCase): }) ], }) - expected_json = [{ + expected_json = { u'lang': u'en_US', u'comment': None, u'credit_limit': 0.0, @@ -90,7 +90,23 @@ class TestParser(TransactionCase): u'name': u'Sebatien Beau', u'email': None }] - }] + } json_partner = partner.jsonify(parser) - self.assertDictEqual(json_partner[0], expected_json[0]) + 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 + partner.write({'child_ids': [(6, 0, [])], + 'active': False, + 'lang': False}) + json_partner = partner.jsonify(parser) + expected_json['active'] = False + expected_json['lang'] = None + expected_json['children'] = [] + self.assertDictEqual(json_partner[0], expected_json) From 5f1e3f90e09262008330e85e0c1143547e470e98 Mon Sep 17 00:00:00 2001 From: beau sebastien Date: Mon, 27 Aug 2018 18:31:57 +0200 Subject: [PATCH 15/18] restore travis configuration (#112) * [ADD] restore travis configuration * [PEP] fix pep8 * [REF] exclude product_categ_available_pos of testing due to issue https://github.com/odoo/odoo/pull/23749 * [PEP] fix pep8 --- base_jsonify/demo/export_demo.xml | 2 +- base_jsonify/models/ir_exports_line.py | 4 ++-- base_jsonify/models/models.py | 8 ++++---- base_jsonify/tests/test_get_parser.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/base_jsonify/demo/export_demo.xml b/base_jsonify/demo/export_demo.xml index a9030c6de..de8566b76 100644 --- a/base_jsonify/demo/export_demo.xml +++ b/base_jsonify/demo/export_demo.xml @@ -4,4 +4,4 @@ Partner Export res.partner - \ No newline at end of file + diff --git a/base_jsonify/models/ir_exports_line.py b/base_jsonify/models/ir_exports_line.py index 6e27a844a..3d4b047ca 100644 --- a/base_jsonify/models/ir_exports_line.py +++ b/base_jsonify/models/ir_exports_line.py @@ -12,8 +12,8 @@ class IrExportsLine(models.Model): alias = fields.Char( 'Alias', - help=_('The complete path to the field where you can specify an ' - 'alias on the a step as field: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') diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index d4b9b678d..7a2df40cb 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -24,7 +24,6 @@ class Base(models.AbstractModel): 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 @@ -41,8 +40,8 @@ class Base(models.AbstractModel): 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 define your mapping as follow into the parser definition: + from the model. If you need to specify an alternate name to use as + key, you can define your mapping as follow into the parser definition: parser = [ 'field_name:json_key' @@ -61,7 +60,8 @@ class Base(models.AbstractModel): res[json_key] = rec[field_name].jsonify(subparser) elif field_type in ('many2one', 'reference'): if rec[field_name]: - res[json_key] = rec[field_name].jsonify(subparser)[0] + res[json_key] =\ + rec[field_name].jsonify(subparser)[0] else: res[json_key] = None else: diff --git a/base_jsonify/tests/test_get_parser.py b/base_jsonify/tests/test_get_parser.py index 80d5b354a..2527d7be0 100644 --- a/base_jsonify/tests/test_get_parser.py +++ b/base_jsonify/tests/test_get_parser.py @@ -57,7 +57,7 @@ class TestParser(TransactionCase): partner = self.env['res.partner'].create({ 'name': 'Akretion', 'country_id': self.env.ref('base.fr').id, - 'lang': 'en_US', # default + 'lang': 'en_US', # default 'category_id': [(0, 0, {'name': 'Inovator'})], 'child_ids': [ (0, 0, { From 0949dd50d28dbcdc648046948d152b7ae4686ce4 Mon Sep 17 00:00:00 2001 From: Pierrick Brun Date: Mon, 8 Oct 2018 10:57:51 +0200 Subject: [PATCH 16/18] Use readme fragment mechanism --- base_jsonify/README.rst | 87 ++--- base_jsonify/readme/CONTRIBUTORS.rst | 3 + base_jsonify/readme/DESCRIPTION.rst | 42 ++ base_jsonify/static/description/index.html | 431 +++++++++++++++++++++ 4 files changed, 519 insertions(+), 44 deletions(-) create mode 100644 base_jsonify/readme/CONTRIBUTORS.rst create mode 100644 base_jsonify/readme/DESCRIPTION.rst create mode 100644 base_jsonify/static/description/index.html diff --git a/base_jsonify/README.rst b/base_jsonify/README.rst index d50eb10ba..65ffe69ef 100644 --- a/base_jsonify/README.rst +++ b/base_jsonify/README.rst @@ -1,11 +1,30 @@ -.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg - :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html - :alt: License: AGPL-3 - ============ Base Jsonify ============ +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github + :target: https://github.com/OCA/server-tools/tree/10.0/base_jsonify + :alt: OCA/server-tools +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/server-tools-10-0/server-tools-10-0-base_jsonify + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/149/10.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + This module add the jsonify method to the ORM. This method take as argument the browse record and the "parser" that specify the field to extract. @@ -49,69 +68,49 @@ can define your mapping as follow into the parser definition: Also the module provide a method "get_json_parser" on the ir.exports object that generate a parser from an ir.exports configuration +**Table of contents** - -Installation -============ - -To install this module, you need to install it - -Configuration -============= - -No configuration required - -Usage -===== - -This is a technical module not function feature is added - -.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas - :alt: Try me on Runbot - :target: https://runbot.odoo-community.org/runbot/{repo_id}/{branch} - -.. repo_id is available in https://github.com/OCA/maintainer-tools/blob/master/tools/repos_with_ids.txt -.. branch is "8.0" for example - -Known issues / Roadmap -====================== - -No distinction between float 0.0L and no value +.. contents:: + :local: Bug Tracker =========== -Bugs are tracked on `GitHub Issues -`_. In case of trouble, please -check there if your issue has already been reported. If you spotted it first, -help us smashing it by providing a detailed and welcomed feedback. +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. Credits ======= -Images ------- +Authors +~~~~~~~ -* Odoo Community Association: `Icon `_. +* Akretion Contributors ------------- +~~~~~~~~~~~~ * BEAU Sébastien * Raphaël Reverdy * Laurent Mignon -Maintainer ----------- +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. .. image:: https://odoo-community.org/logo.png :alt: Odoo Community Association :target: https://odoo-community.org -This module is maintained by the OCA. - OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -To contribute to this module, please visit https://odoo-community.org. +This module is part of the `OCA/server-tools `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/base_jsonify/readme/CONTRIBUTORS.rst b/base_jsonify/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..717c76041 --- /dev/null +++ b/base_jsonify/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* BEAU Sébastien +* Raphaël Reverdy +* Laurent Mignon diff --git a/base_jsonify/readme/DESCRIPTION.rst b/base_jsonify/readme/DESCRIPTION.rst new file mode 100644 index 000000000..25c62fbb3 --- /dev/null +++ b/base_jsonify/readme/DESCRIPTION.rst @@ -0,0 +1,42 @@ +This module add the jsonify method to the ORM. This method take as argument +the browse record and the "parser" that specify the field to extract. + +Example of parser: + + +.. code-block:: python + + parser = [ + 'name', + 'number', + 'create_date', + ('partner_id', ['id', 'display_name', 'ref']) + ('line_id', ['id', ('product_id', ['name']), 'price_unit']) + ] + +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 define 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 diff --git a/base_jsonify/static/description/index.html b/base_jsonify/static/description/index.html new file mode 100644 index 000000000..a4065b092 --- /dev/null +++ b/base_jsonify/static/description/index.html @@ -0,0 +1,431 @@ + + + + + + +Base Jsonify + + + +
+

Base Jsonify

+ + +

Beta License: AGPL-3 OCA/server-tools Translate me on Weblate Try me on Runbot

+

This module add the jsonify method to the ORM. This method take as argument +the browse record and the “parser” that specify the field to extract.

+

Example of parser:

+
+parser = [
+    'name',
+    'number',
+    'create_date',
+    ('partner_id', ['id', 'display_name', 'ref'])
+    ('line_id', ['id', ('product_id', ['name']), 'price_unit'])
+]
+
+

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 define your mapping as follow into the parser definition:

+
+parser = [
+     'field_name:json_key'
+]
+
+
+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

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Akretion
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/server-tools project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + From 71ab8cc710f221792d3bbda8a377afb709d46a12 Mon Sep 17 00:00:00 2001 From: Sylvain Le Gal Date: Mon, 10 Dec 2018 19:14:01 +0100 Subject: [PATCH 17/18] IMP add view for ir.exports --- base_jsonify/__manifest__.py | 1 + base_jsonify/views/ir_exports_view.xml | 38 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 base_jsonify/views/ir_exports_view.xml diff --git a/base_jsonify/__manifest__.py b/base_jsonify/__manifest__.py index c0d746be7..c3cbcec87 100644 --- a/base_jsonify/__manifest__.py +++ b/base_jsonify/__manifest__.py @@ -22,6 +22,7 @@ "base", ], "data": [ + 'views/ir_exports_view.xml', ], "demo": [ 'demo/export_demo.xml', diff --git a/base_jsonify/views/ir_exports_view.xml b/base_jsonify/views/ir_exports_view.xml new file mode 100644 index 000000000..1762eff08 --- /dev/null +++ b/base_jsonify/views/ir_exports_view.xml @@ -0,0 +1,38 @@ + + + + + ir.exports + 50 + +
+ + + + + + + + + + + + + + + + +
+
+
+ + + Export Fields + ir.exports + tree,form + + + + +
From 5fd0a0350b49969d99c7590b33cff2f7cd7d77f7 Mon Sep 17 00:00:00 2001 From: Pierrick brun Date: Tue, 11 Dec 2018 16:51:46 +0100 Subject: [PATCH 18/18] [FIX] misc. fixes in the comments/docstrings --- base_jsonify/__manifest__.py | 10 +++------- base_jsonify/models/ir_export.py | 18 ++++++++++++++++++ base_jsonify/models/models.py | 5 ++++- base_jsonify/readme/DESCRIPTION.rst | 5 +++-- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/base_jsonify/__manifest__.py b/base_jsonify/__manifest__.py index c3cbcec87..33c626d4c 100644 --- a/base_jsonify/__manifest__.py +++ b/base_jsonify/__manifest__.py @@ -1,23 +1,19 @@ # -*- coding: utf-8 -*- -# © 2017 Akretion (http://www.akretion.com) +# Copyright 2017-2018 Akretion (http://www.akretion.com) # Sébastien BEAU # Raphaël Reverdy # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Base Jsonify", - "summary": "Base module that provide the jsonify method on all object", + "summary": "Base module that provide the jsonify method on all models", "version": "10.0.1.0.0", "category": "Uncategorized", - "website": "https://odoo-community.org/", + "website": "https://github.com/OCA/server-tools", "author": "Akretion, Odoo Community Association (OCA)", "license": "AGPL-3", "application": False, "installable": True, - "external_dependencies": { - "python": [], - "bin": [], - }, "depends": [ "base", ], diff --git a/base_jsonify/models/ir_export.py b/base_jsonify/models/ir_export.py index feae5cddf..4e71c1d7c 100644 --- a/base_jsonify/models/ir_export.py +++ b/base_jsonify/models/ir_export.py @@ -8,6 +8,14 @@ from odoo import api, models def update_dict(data, fields): + """ + Contruct a tree of fields. + ie: { + "name": True, + "resource": True, + } + Order of keys is important. + """ field = fields[0] if len(fields) == 1: if field == '.id': @@ -20,6 +28,11 @@ def update_dict(data, fields): def convert_dict(dict_parser): + """ + Converts the dict returned by update_dict to a list consistent with the + Odoo API. The list is composed of strings (field names or aliases) or + tuples. + """ parser = [] for field, value in dict_parser.iteritems(): if value is True: @@ -34,6 +47,10 @@ class IrExport(models.Model): @api.multi def get_json_parser(self): + """ + Creates a parser from a ir_exports record and returns it. This parser + can then be used to "jsonify" records of the ir_export's model. + """ self.ensure_one() dict_parser = OrderedDict() for line in self.export_fields: @@ -41,4 +58,5 @@ class IrExport(models.Model): if line.alias: names = line.alias.split('/') update_dict(dict_parser, names) + return convert_dict(dict_parser) diff --git a/base_jsonify/models/models.py b/base_jsonify/models/models.py index 7a2df40cb..3fd8b9815 100644 --- a/base_jsonify/models/models.py +++ b/base_jsonify/models/models.py @@ -15,6 +15,9 @@ class Base(models.AbstractModel): @api.model def __parse_field(self, parser_field): + """ + Deducts how to handle a field from its parser + """ field_name = parser_field subparser = None if isinstance(parser_field, tuple): @@ -36,7 +39,7 @@ class Base(models.AbstractModel): ('line_id', ['id', ('product_id', ['name']), 'price_unit']) ] - In order to be consitent with the odoo api the jsonify method always + In order to be consistent 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 diff --git a/base_jsonify/readme/DESCRIPTION.rst b/base_jsonify/readme/DESCRIPTION.rst index 25c62fbb3..ff92efef6 100644 --- a/base_jsonify/readme/DESCRIPTION.rst +++ b/base_jsonify/readme/DESCRIPTION.rst @@ -1,5 +1,6 @@ -This module add the jsonify method to the ORM. This method take as argument -the browse record and the "parser" that specify the field to extract. +This module adds a 'jsonify' method to every model of the ORM. +It works on the current recordset and requires a single argument 'parser' +that specify the field to extract. Example of parser: