From ee0a983531503aa8f5950d42190618aa7d09b07c Mon Sep 17 00:00:00 2001 From: Jordi Riera Date: Mon, 13 Oct 2014 14:51:01 -0400 Subject: [PATCH] [IMP] prototype: implementation of jinja syntax. [IMP] prototype: Switched to v8 api. [IMP] prototype: renamed the templates to avoid confusion with pep8 tests. [IMP] prototype: renamed some fields in prototype.py. [IMP] prototype: implemented the process to create the zip file to export. [IMP] prototype: worked on the generation of __openerp__.py and __init__.py files from the prototype. [IMP] prototype: pep8 [IMP] prototype: added more comments. [IMP] prototype: worked on fields. [IMP] prototype: implemented the generation of files from models/model_name.py.template and models/init.py.template [IMP] prototype: first work on implementation of generations of views. [IMP] prototype: improved the arch section in model_view.xml.template [IMP] prototype: Reviewed the names of many2many from plurials to name_ids. [IMP] prototype: added menus. [IMP] prototype: typo in templates/8.0/views/model_view.xml.template [IMP] prototype: improved template with adding extension to header.template to ease management of file with licence header. [IMP] prototype: prototype.prototype demo data [IMP] prototype: worked to get the views and menus properly generated. Added actions to model_menus.xml.template. [IMP] prototype: should fix pep8 in model_name.py.template. --- prototype/__openerp__.py | 8 +- prototype/demo/prototype.prototype.csv | 2 + prototype/i18n/fr.po | 4 +- prototype/i18n/prototype.pot | 4 +- prototype/models/ir_model_fields.py | 8 +- prototype/models/prototype.py | 358 +++++++++++++++--- prototype/templates/7.0/__openerp__.py | 50 --- prototype/templates/7.0/data/model_name.xml | 8 - prototype/templates/7.0/demo/model_name.xml | 8 - prototype/templates/7.0/models/__init__.py | 24 -- prototype/templates/7.0/models/model_name.py | 36 -- .../7.0/security/ir.model.access.csv | 1 - prototype/templates/8.0/__init__.py.template | 6 + prototype/templates/8.0/__openerp__.py | 50 --- .../templates/8.0/__openerp__.py.template | 38 ++ ...model_name.xml => model_name.xml.template} | 2 +- prototype/templates/8.0/demo/model_name.xml | 8 - .../demo/model_name.xml.template} | 2 +- .../{7.0/__init__.py => 8.0/header.template} | 6 +- prototype/templates/8.0/models/__init__.py | 24 -- .../templates/8.0/models/__init__.py.template | 6 + prototype/templates/8.0/models/model_name.py | 34 -- .../8.0/models/model_name.py.template | 21 + .../8.0/security/ir.model.access.csv | 1 - .../8.0/security/ir.model.access.csv.template | 4 + .../templates/8.0/security/model_name.xml | 10 - .../security/model_name.xml.template} | 4 +- .../8.0/views/model_menus.xml.template | 24 ++ prototype/templates/8.0/views/model_view.xml | 8 - .../8.0/views/model_views.xml.template | 23 ++ .../{templates/8.0 => tests}/__init__.py | 14 +- prototype/tests/test_prototype.py | 83 ++++ .../tests/test_prototype_module_export.py | 83 ++++ prototype/views/prototype_view.xml | 184 ++++----- prototype/wizard/prototype_module_export.py | 120 ++++-- .../wizard/prototype_module_export_view.xml | 2 +- 36 files changed, 815 insertions(+), 453 deletions(-) create mode 100644 prototype/demo/prototype.prototype.csv delete mode 100644 prototype/templates/7.0/__openerp__.py delete mode 100644 prototype/templates/7.0/data/model_name.xml delete mode 100644 prototype/templates/7.0/demo/model_name.xml delete mode 100644 prototype/templates/7.0/models/__init__.py delete mode 100644 prototype/templates/7.0/models/model_name.py delete mode 100644 prototype/templates/7.0/security/ir.model.access.csv create mode 100644 prototype/templates/8.0/__init__.py.template delete mode 100644 prototype/templates/8.0/__openerp__.py create mode 100644 prototype/templates/8.0/__openerp__.py.template rename prototype/templates/8.0/data/{model_name.xml => model_name.xml.template} (79%) delete mode 100644 prototype/templates/8.0/demo/model_name.xml rename prototype/templates/{7.0/views/model_name_view.xml => 8.0/demo/model_name.xml.template} (79%) rename prototype/templates/{7.0/__init__.py => 8.0/header.template} (88%) delete mode 100644 prototype/templates/8.0/models/__init__.py create mode 100644 prototype/templates/8.0/models/__init__.py.template delete mode 100644 prototype/templates/8.0/models/model_name.py create mode 100644 prototype/templates/8.0/models/model_name.py.template delete mode 100644 prototype/templates/8.0/security/ir.model.access.csv create mode 100644 prototype/templates/8.0/security/ir.model.access.csv.template delete mode 100644 prototype/templates/8.0/security/model_name.xml rename prototype/templates/{7.0/security/model_name.xml => 8.0/security/model_name.xml.template} (63%) create mode 100644 prototype/templates/8.0/views/model_menus.xml.template delete mode 100644 prototype/templates/8.0/views/model_view.xml create mode 100644 prototype/templates/8.0/views/model_views.xml.template rename prototype/{templates/8.0 => tests}/__init__.py (75%) create mode 100644 prototype/tests/test_prototype.py create mode 100644 prototype/tests/test_prototype_module_export.py diff --git a/prototype/__openerp__.py b/prototype/__openerp__.py index 264624e6c..bba600c49 100644 --- a/prototype/__openerp__.py +++ b/prototype/__openerp__.py @@ -45,10 +45,10 @@ Contributors * Maxime Chambreuil * Savoir-faire Linux -More informations ------------------ -* Module developped and tested with Odoo version 8.0 -* For questions, please contact our support services \ +More information +---------------- +* Module developed and tested with Odoo version 8.0 +* For questions, please contact our support services (support@savoirfairelinux.com) """, 'depends': [ diff --git a/prototype/demo/prototype.prototype.csv b/prototype/demo/prototype.prototype.csv new file mode 100644 index 000000000..c4ffea3ec --- /dev/null +++ b/prototype/demo/prototype.prototype.csv @@ -0,0 +1,2 @@ +"id","right_ids/id","application","author","auto_install","category_id/id","create_uid/id","create_date","data_ids/id","demo_ids/id","dependency_ids/id","description","field_ids/id","group_ids/id","icon_image","write_uid/id","write_date","licence","maintainer","menu_ids/id","human_name","rule_ids/id","summary","name","version","view_ids/id","website" +"__export__.prototype_22","__export__.ir_model_access_144","False","Savoir-faire Linux","False","base.module_category_uncategorized","base.user_root","2014-12-15 21:07:09","__export__.ir_filters_31","","base.module_crm,base.module_mail,base.module_l10n_et,base.module_l10n_mx","This module is used to test the export of prototype. It uses all the features.","__export__.ir_model_fields_1238","__export__.res_groups_13","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itq3ieGdl/0awInkPbf/AAL9c/N/wH3rF0fRb/Xr4Wmnw72z+8kb7kQ9WP8ATqa9w8P6Da+HdKSxtssc7pZWHzSOerH/AA7CqqSUI8qNsRVjRp+zjuY3jzTWn0+LUI1y1sSJMf3G6n8Dg1wEUslvNHNC+yWNg6MOxHSva3RZEZHUMjAhlYZBHoa8y8R+F59Hle4tkaWwJyGHJi9m9vQ/n78p5B22g+IrXW7cAMsd2o/eQE8g+o9RWzXh4JBV1JBHKspwR9CK0U1/WETYup3WPd8n8zQB6ve39rp1s1xdzLFEvdj19gO5rjm+IZF0caaTag9fN/eY9cYxn2z+NcZPcT3cvm3M8s8nZpHLEVY0zS7vV7oW9nHuP8ch+7GPUn+nWgR6P4gs11/w0zWv7x9q3Fvj+IgZx+IJH415Xwy+xr2mxtEsLC3tIySkMaxgnvgYri/FfhSRZpNS02MujndNAo5B7so7j1H40DNHwr4oivbaOxvZQl4g2qznAmHYg/3vUV1deHcMPUVoQa3qtsgSHUblUAwFL7gPzoA9dmnit4WlmkWONRlnc4AH1rzPxT4hGtXaRW+RZQElCRjzG6bsemOB+NY11e3d8Qbu6mnx0EjkgfQdKZFbzTrK0MTyLEpeRlGQgHqe1Ahg6ivXvD//ACLel/8AXnF/6AK8gHUV6/4f/wCRb0v/AK9Iv/QBQBo0UUUDCiiigArl9W8AaBqsjTfZ3tJ25aS1bZk+64Kn8q6iimm1sVCcoO8XY84f4TRb/wB3rUoX0e3Un8wR/Kr1j8LdHgcPeXN3eEfwFhGh/BQD+tdzRVe1n3NniqzVuYr2dja6dbLbWdvHBCv3UjUKBViiioOdu+rCggEYIyKKKAOfv/BmkXztIsT2sjclrdtoP/ASCP0rJb4dpu+XVJAvo0IJ/mK7aigDlbTwFpkLBrma4uSP4WYIv5Lg/rXSW1rb2cCw20KQxL0RFwKmooAKKKKAMfU/DGlaq5lmt9k56zQnYx+vY/iDWFJ8PIS37rU5lX0kiVj+mK7WigDkrTwBp8TBrq5uLnH8GQin8uf1rpI9Ps4rFrKO3jS2ZSpjUYBBGDVmigDjl+HtmLncb2drbP8Aqto3Y9N3p+GfeuvRFijWNFCooCqo6ACnUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAH//Z","base.user_root","2014-12-26 16:11:10","AGPL-3","OCA","__export__.ir_ui_menu_96","Demo Module","__export__.ir_rule_20","Demo module for prototype","demo_module","0.1","__export__.ir_ui_view_334,__export__.ir_ui_view_333","http://www.savoirfairelinux.com" \ No newline at end of file diff --git a/prototype/i18n/fr.po b/prototype/i18n/fr.po index 37c27a4f6..a8f862289 100644 --- a/prototype/i18n/fr.po +++ b/prototype/i18n/fr.po @@ -87,7 +87,7 @@ msgid "Demo filters" msgstr "Filtres pour les données de démo" #. module: prototype -#: view:prototype:prototype.view_prototype_form field:prototype,depends:0 +#: view:prototype:prototype.view_prototype_form field:prototype,dependencies:0 msgid "Dependencies" msgstr "Dépendances" @@ -190,7 +190,7 @@ msgid "Module" msgstr "" #. module: prototype -#: field:prototype,shortdesc:0 +#: field:prototype,human_name:0 msgid "Module Name" msgstr "Nom du module" diff --git a/prototype/i18n/prototype.pot b/prototype/i18n/prototype.pot index 027657e2c..de7c40cea 100644 --- a/prototype/i18n/prototype.pot +++ b/prototype/i18n/prototype.pot @@ -87,7 +87,7 @@ msgid "Demo filters" msgstr "" #. module: prototype -#: view:prototype:prototype.view_prototype_form field:prototype,depends:0 +#: view:prototype:prototype.view_prototype_form field:prototype,dependencies:0 msgid "Dependencies" msgstr "" @@ -190,7 +190,7 @@ msgid "Module" msgstr "" #. module: prototype -#: field:prototype,shortdesc:0 +#: field:prototype,human_name:0 msgid "Module Name" msgstr "" diff --git a/prototype/models/ir_model_fields.py b/prototype/models/ir_model_fields.py index c70dc4a7c..0330a058e 100644 --- a/prototype/models/ir_model_fields.py +++ b/prototype/models/ir_model_fields.py @@ -19,12 +19,10 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import fields, osv +from openerp import fields, models -class ir_model_fields(osv.osv): +class ir_model_fields(models.Model): _inherit = "ir.model.fields" - _columns = { - 'notes': fields.text('Notes'), - } + notes = fields.Text('Notes') diff --git a/prototype/models/prototype.py b/prototype/models/prototype.py index 39a94fb84..daea937a0 100644 --- a/prototype/models/prototype.py +++ b/prototype/models/prototype.py @@ -1,5 +1,5 @@ # -*- encoding: utf-8 -*- -############################################################################## +# ############################################################################# # # OpenERP, Open Source Management Solution # This module copyright (C) 2010 - 2014 Savoir-faire Linux @@ -19,51 +19,321 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import fields, osv +import os +import re +import base64 +from datetime import date +YEAR = date.today().year + +from collections import namedtuple +from jinja2 import Environment, FileSystemLoader +from openerp import models, api, fields -class prototype(osv.osv): +class Prototype(models.Model): _name = "prototype" _description = "Prototype" - _columns = { - 'name': fields.char('Technical Name', required=True), - 'category_id': fields.many2one('ir.module.category', 'Category'), - 'shortdesc': fields.char('Module Name', required=True), - 'summary': fields.char('Summary', required=True), - 'description': fields.html('Description', required=True), - 'author': fields.char('Author', required=True), - 'maintainer': fields.char('Maintainer'), - 'website': fields.char('Website'), - 'icon_image': fields.binary('Icon'), - 'version': fields.char('Version', size=3), - 'auto_install': fields.boolean('Auto Install'), - # Relations - 'depends': fields.many2many('ir.module.module', 'prototype_module_rel', - 'prototype_id', 'module_id', - 'Dependencies'), - 'data': fields.many2many('ir.filters', 'prototype_data_rel', - 'prototype_id', 'filter_id', - 'Data filters', help="The records matching the filters will be added as data."), - 'demo': fields.many2many('ir.filters', 'prototype_demo_rel', - 'prototype_id', 'filter_id', - 'Demo filters', help="The records matching the filters will be added as demo data."), - 'fields': fields.many2many('ir.model.fields', 'prototype_fields_rel', - 'prototype_id', 'field_id', 'Fields'), - 'menu': fields.many2many('ir.ui.menu', 'prototype_menu_rel', - 'prototype_id', 'menu_id', 'Menu Items'), - 'views': fields.many2many('ir.ui.view', 'prototype_view_rel', - 'prototype_id', 'view_id', 'Views'), - 'groups': fields.many2many('res.groups', 'prototype_groups_rel', - 'prototype_id', 'group_id', 'Groups'), - 'rights': fields.many2many('ir.model.access', 'prototype_rights_rel', - 'prototype_id', 'right_id', - 'Access Rights'), - 'rules': fields.many2many('ir.rule', 'prototype_rule_rel', - 'prototype_id', 'rule_id', 'Record Rules'), - } - - _defaults = { - 'auto_install': False, - 'version': '0.1', - } + licence = fields.Char( + 'Licence', + default='AGPL-3', + ) + name = fields.Char( + 'Technical Name', required=True, + help=('The technical name will be used to define the name of ' + 'the exported module, the name of the model.') + ) + category_id = fields.Many2one('ir.module.category', 'Category') + human_name = fields.Char( + 'Module Name', required=True, + help=('The Module Name will be used as the displayed name of the ' + 'exported module.') + ) + summary = fields.Char('Summary', required=True) + description = fields.Text('Description', required=True) + author = fields.Char('Author', required=True) + maintainer = fields.Char('Maintainer') + website = fields.Char('Website') + icon_image = fields.Binary( + 'Icon', + help=('The icon set up here will be used as the icon ' + 'for the exported module also') + ) + version = fields.Char('Version', size=3, default='0.1') + auto_install = fields.Boolean( + 'Auto Install', + default=False, + help='Check if the module should be install by default.' + ) + application = fields.Boolean( + 'Application', + default=False, + help='Check if the module is an Odoo application.' + ) + # Relations + dependency_ids = fields.Many2many( + 'ir.module.module', 'prototype_module_rel', + 'prototype_id', 'module_id', + 'Dependencies' + ) + data_ids = fields.Many2many( + 'ir.filters', + 'prototype_data_rel', + 'prototype_id', 'filter_id', + 'Data filters', + help="The records matching the filters will be added as data." + ) + demo_ids = fields.Many2many( + 'ir.filters', + 'prototype_demo_rel', + 'prototype_id', 'filter_id', + 'Demo filters', + help="The records matching the filters will be added as demo data." + ) + field_ids = fields.Many2many( + 'ir.model.fields', 'prototype_fields_rel', + 'prototype_id', 'field_id', 'Fields' + ) + menu_ids = fields.Many2many( + 'ir.ui.menu', 'prototype_menu_rel', + 'prototype_id', 'menu_id', 'Menu Items' + ) + view_ids = fields.Many2many( + 'ir.ui.view', 'prototype_view_rel', + 'prototype_id', 'view_id', 'Views' + ) + group_ids = fields.Many2many( + 'res.groups', 'prototype_groups_rel', + 'prototype_id', 'group_id', 'Groups' + ) + right_ids = fields.Many2many( + 'ir.model.access', 'prototype_rights_rel', + 'prototype_id', 'right_id', + 'Access Rights' + ) + rule_ids = fields.Many2many( + 'ir.rule', 'prototype_rule_rel', + 'prototype_id', 'rule_id', 'Record Rules' + ) + + __data_files = [] + __field_descriptions = {} + _env = None + File_details = namedtuple('file_details', ['filename', 'filecontent']) + template_path = '{}/../templates/'.format(os.path.dirname(__file__)) + + @api.model + def set_jinja_env(self, api_version): + """Set the Jinja2 environment. + The environment will helps the system to find the templates to render. + :param api_version: string, odoo api + :return: jinja2.Environment instance. + """ + if self._env is None: + self._env = Environment( + loader=FileSystemLoader( + os.path.join(self.template_path, api_version) + ) + ) + return self._env + + def set_field_descriptions(self): + """Mock the list of fields into dictionary. + It allows us to add or change attributes of the fields. + + :return: None + """ + for field in self.field_ids: + field_description = {} + # This will mock a field record. + # the mock will allow us to add data or modify the data + # of the field (like for the name) with keeping all the + # attributes of the record. + field_description.update({ + attr_name: getattr(field, attr_name) + for attr_name in dir(field) + if not attr_name[0] == '_' + }) + # custom fields start with the prefix x_. + # it has to be removed. + field_description['name'] = re.sub(r'^x_', '', field.name) + self.__field_descriptions[field] = field_description + + @api.model + def generate_files(self): + """ Generates the files from the details of the prototype. + :return: tuple + """ + assert self._env is not None, \ + 'Run set_env(api_version) before to generate files.' + + self.set_field_descriptions() + file_details = [] + file_details.extend(self.generate_models_details()) + file_details.extend(self.generate_views_details()) + file_details.extend(self.generate_menus_details()) + file_details.append(self.generate_module_init_file_details()) + # must be the last as the other generations might add information + # to put in the __openerp__: additional dependencies, views files, etc. + file_details.append(self.generate_module_openerp_file_details()) + file_details.append(self.save_icon()) + + return file_details + + @api.model + def save_icon(self): + return self.File_details( + os.path.join('static', 'description', 'icon.jpg'), + base64.b64decode(self.icon_image) + ) + + @api.model + def generate_module_openerp_file_details(self): + """Wrapper to generate the __openerp__.py file of the module.""" + return self.generate_file_details( + '__openerp__.py', + '__openerp__.py.template', + prototype=self, + data_files=self.__data_files, + ) + + @api.model + def generate_module_init_file_details(self): + """Wrapper to generate the __init__.py file of the module.""" + return self.generate_file_details( + '__init__.py', + '__init__.py.template', + # no import models if no work of fields in + # the prototype + models=bool(self.field_ids) + ) + + @api.model + def generate_models_details(self): + """Finds the models from the list of fields and generates + the __init__ file and each models files (one by class). + """ + files = [] + # TODO: doesn't work as need to find the module to import + # and it is not necessary the name of the model the fields + # belongs to. + # ie. field.cell_phone is defined in a model inheriting from + # res.partner. + # How do we find the module the field was defined in? + # dependencies = set([dep.id for dep in self.dependencies]) + + relations = {} + for field in self.__field_descriptions.itervalues(): + model = field.get('model_id') + relations.setdefault(model, []).append(field) + # dependencies.add(model.id) + + # blind update of dependencies. + # self.write({ + # 'dependencies': [(6, 0, [id_ for id_ in dependencies])] + # }) + + files.append(self.generate_models_init_details(relations.keys())) + for model, fields in relations.iteritems(): + files.append(self.generate_model_details(model, fields)) + + return files + + @api.model + def generate_models_init_details(self, ir_models): + """Wrapper to generate the __init__.py file in models folder.""" + return self.generate_file_details( + 'models/__init__.py', + 'models/__init__.py.template', + models=[ + self.friendly_name(ir_model.model) + for ir_model in ir_models + ] + ) + + @api.model + def generate_views_details(self): + """Wrapper to generate the views files.""" + relations = {} + for view in self.view_ids: + relations.setdefault(view.model, []).append(view) + + views_details = [] + for model, views in relations.iteritems(): + filepath = 'views/{}_view.xml'.format( + self.friendly_name(model) + ) + views_details.append( + self.generate_file_details( + filepath, + 'views/model_views.xml.template', + views=views + ) + ) + self.__data_files.append(filepath) + + return views_details + + @api.model + def generate_menus_details(self): + """Wrapper to generate the menus files.""" + relations = {} + for menu in self.menu_ids: + relations.setdefault(menu.action.res_model, []).append(menu) + + menus_details = [] + for model_name, menus in relations.iteritems(): + filepath = 'views/{}_menus.xml'.format( + self.friendly_name(model_name) + ) + menus_details.append( + self.generate_file_details( + filepath, + 'views/model_menus.xml.template', + menus=menus, + ) + ) + self.__data_files.append(filepath) + + return menus_details + + @api.model + def generate_model_details(self, model, field_descriptions): + """Wrapper to generate the python file for the model. + + :param model: ir.model record. + :param field_descriptions: list of ir.model.fields records. + :return: FileDetails instance. + """ + python_friendly_name = self.friendly_name(model.model) + return self.generate_file_details( + 'models/{}.py'.format(python_friendly_name), + 'models/model_name.py.template', + name=python_friendly_name, + inherit=model.model, + fields=field_descriptions, + ) + + @staticmethod + def friendly_name(name): + return name.replace('.', '_') + + @api.model + def generate_file_details(self, filename, template, **kwargs): + """ generate file details from jinja2 template. + :param filename: name of the file the content is related to + :param template: path to the file to render the content + :param kwargs: arguments of the template + :return: File_details instance + """ + template = self._env.get_template(template) + # keywords used in several templates. + kwargs.update( + { + 'export_year': YEAR, + 'author': self.author, + 'website': self.website, + 'cr': self._cr, + } + ) + return self.File_details(filename, template.render(kwargs)) diff --git a/prototype/templates/7.0/__openerp__.py b/prototype/templates/7.0/__openerp__.py deleted file mode 100644 index b8fbb1760..000000000 --- a/prototype/templates/7.0/__openerp__.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $export_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': '$name', - 'version': '$version', - 'author': '$author', - 'maintainer': '$maintainer', - 'website': '$website', - 'license': 'AGPL-3', - 'category': '$category', - 'summary': '$summary', - 'description': """ -$description - -* Module exported by the prototype module for version 7.0. -* If you have any questions, please contact Savoir-faire Linux \ -(support@savoirfairelinux.com) -""", - 'depends': [ - $depends - ], - 'external_dependencies': { - 'python': [], - }, - 'data': [ - $data - ], - 'installable': True, - 'auto_install': $auto_install, -} diff --git a/prototype/templates/7.0/data/model_name.xml b/prototype/templates/7.0/data/model_name.xml deleted file mode 100644 index baf4b950c..000000000 --- a/prototype/templates/7.0/data/model_name.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - $data - - - diff --git a/prototype/templates/7.0/demo/model_name.xml b/prototype/templates/7.0/demo/model_name.xml deleted file mode 100644 index 45605019c..000000000 --- a/prototype/templates/7.0/demo/model_name.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - $demo - - - diff --git a/prototype/templates/7.0/models/__init__.py b/prototype/templates/7.0/models/__init__.py deleted file mode 100644 index 8d436f907..000000000 --- a/prototype/templates/7.0/models/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from . import ( - $models.py -) diff --git a/prototype/templates/7.0/models/model_name.py b/prototype/templates/7.0/models/model_name.py deleted file mode 100644 index e5d9d0cb8..000000000 --- a/prototype/templates/7.0/models/model_name.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp.osv import fields, osv - - -class $model_name(osv.osv): - _name = "$model_name" - _inherit = "$model_name" - _description = "$model_description" - - _columns = { - $model_fields - } - - _defaults = { - - } diff --git a/prototype/templates/7.0/security/ir.model.access.csv b/prototype/templates/7.0/security/ir.model.access.csv deleted file mode 100644 index 97dd8b917..000000000 --- a/prototype/templates/7.0/security/ir.model.access.csv +++ /dev/null @@ -1 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink diff --git a/prototype/templates/8.0/__init__.py.template b/prototype/templates/8.0/__init__.py.template new file mode 100644 index 000000000..82452828d --- /dev/null +++ b/prototype/templates/8.0/__init__.py.template @@ -0,0 +1,6 @@ +{% extends "header.template" %} +{% block body %} +{% if models -%} +from . import models +{% endif %} +{% endblock %} diff --git a/prototype/templates/8.0/__openerp__.py b/prototype/templates/8.0/__openerp__.py deleted file mode 100644 index e39d87e5e..000000000 --- a/prototype/templates/8.0/__openerp__.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $export_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -{ - 'name': '$name', - 'version': '$version', - 'author': '$author', - 'maintainer': '$maintainer', - 'website': '$website', - 'license': 'AGPL-3', - 'category': '$category', - 'summary': '$summary', - 'description': """ -$description - -* Module exported by the prototype module for version 8.0. -* If you have any questions, please contact Savoir-faire Linux \ -(support@savoirfairelinux.com) -""", - 'depends': [ - $depends - ], - 'external_dependencies': { - 'python': [], - }, - 'data': [ - $data - ], - 'installable': True, - 'auto_install': $auto_install, -} diff --git a/prototype/templates/8.0/__openerp__.py.template b/prototype/templates/8.0/__openerp__.py.template new file mode 100644 index 000000000..1bf10ccfb --- /dev/null +++ b/prototype/templates/8.0/__openerp__.py.template @@ -0,0 +1,38 @@ +{% extends "header.template" %} +{% block body %} +{ + 'name': '{{ prototype.name }}', + 'version': '{{ prototype.version }}', + 'author': '{{ prototype.author }}', + 'maintainer': '{{ prototype.maintainer }}', + 'website': '{{ prototype.website }}', + 'license': '{{ prototype.licence }}', + 'category': '{{ prototype.category_id.name }}', + 'summary': '{{ prototype.summary }}', + 'description': """ +{{ prototype.description }} + +* Module exported by the prototype module for version 8.0. +* If you have any questions, please contact Savoir-faire Linux \ +(support@savoirfairelinux.com) +""", + 'depends': [ + {% for dependency in prototype.dependency_ids -%} + '{{ dependency.name }}', + {% endfor -%}], + 'external_dependencies': { + 'python': [], + }, + 'data': [ + {% for data_file in data_files -%} + '{{ data_file }}', + {% endfor -%}], + 'demo': [ + {% for demo_file in prototype.demo_ids -%} + '{{ demo_file.name }}', + {% endfor -%}], + 'installable': True, + 'auto_install': {{ prototype.auto_install }}, + 'application': {{ prototype.application }}, +} +{% endblock %} diff --git a/prototype/templates/8.0/data/model_name.xml b/prototype/templates/8.0/data/model_name.xml.template similarity index 79% rename from prototype/templates/8.0/data/model_name.xml rename to prototype/templates/8.0/data/model_name.xml.template index baf4b950c..7b25f11f8 100644 --- a/prototype/templates/8.0/data/model_name.xml +++ b/prototype/templates/8.0/data/model_name.xml.template @@ -2,7 +2,7 @@ - $data + {{ data }} diff --git a/prototype/templates/8.0/demo/model_name.xml b/prototype/templates/8.0/demo/model_name.xml deleted file mode 100644 index 45605019c..000000000 --- a/prototype/templates/8.0/demo/model_name.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - $demo - - - diff --git a/prototype/templates/7.0/views/model_name_view.xml b/prototype/templates/8.0/demo/model_name.xml.template similarity index 79% rename from prototype/templates/7.0/views/model_name_view.xml rename to prototype/templates/8.0/demo/model_name.xml.template index 45fa4957e..097c294f1 100644 --- a/prototype/templates/7.0/views/model_name_view.xml +++ b/prototype/templates/8.0/demo/model_name.xml.template @@ -2,7 +2,7 @@ - $views + {{ demo }} diff --git a/prototype/templates/7.0/__init__.py b/prototype/templates/8.0/header.template similarity index 88% rename from prototype/templates/7.0/__init__.py rename to prototype/templates/8.0/header.template index 2a599284e..59f0f4bfd 100644 --- a/prototype/templates/7.0/__init__.py +++ b/prototype/templates/8.0/header.template @@ -2,8 +2,8 @@ ############################################################################## # # Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). +# This module copyright (C) {{ export_year }} {{ author }} +# ({{ website }}). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,4 +19,4 @@ # along with this program. If not, see . # ############################################################################## -from . import models +{% block body %}{% endblock %} \ No newline at end of file diff --git a/prototype/templates/8.0/models/__init__.py b/prototype/templates/8.0/models/__init__.py deleted file mode 100644 index 8d436f907..000000000 --- a/prototype/templates/8.0/models/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from . import ( - $models.py -) diff --git a/prototype/templates/8.0/models/__init__.py.template b/prototype/templates/8.0/models/__init__.py.template new file mode 100644 index 000000000..caf9d7c74 --- /dev/null +++ b/prototype/templates/8.0/models/__init__.py.template @@ -0,0 +1,6 @@ +{% extends "header.template" %} +{% block body %} +{% for model in models -%} +from . import {{ model }} +{% endfor %} +{% endblock %} diff --git a/prototype/templates/8.0/models/model_name.py b/prototype/templates/8.0/models/model_name.py deleted file mode 100644 index 2c94e2f20..000000000 --- a/prototype/templates/8.0/models/model_name.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## -from openerp.osv import fields, osv - - -class $model_name(osv.osv): - _name = "$model_name" - _inherit = "$model_name" - _description = "$model_description" - - $model_fields - - _defaults = { - - } diff --git a/prototype/templates/8.0/models/model_name.py.template b/prototype/templates/8.0/models/model_name.py.template new file mode 100644 index 000000000..503df048f --- /dev/null +++ b/prototype/templates/8.0/models/model_name.py.template @@ -0,0 +1,21 @@ +{% extends "header.template" %} +{% block body %} +from openerp import models, fields +from openerp.tools.translate import _ + + +class {{ name }}(models.Model): + _inherit = "{{ inherit }}" + {% if description %}_description = "{{ description }}"{% endif %} + + {% for field in fields -%} + {{ field.name }} = fields.{{ field.ttype|capitalize }}( + string=_("{{ field.field_description }}"), + required={{ field.required }}, + translate={{ field.translate }}, + readonly={{ field.readonly }}, + help=_('{{ field.notes }}'), + ) + {% endfor %} + +{% endblock %} diff --git a/prototype/templates/8.0/security/ir.model.access.csv b/prototype/templates/8.0/security/ir.model.access.csv deleted file mode 100644 index 97dd8b917..000000000 --- a/prototype/templates/8.0/security/ir.model.access.csv +++ /dev/null @@ -1 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink diff --git a/prototype/templates/8.0/security/ir.model.access.csv.template b/prototype/templates/8.0/security/ir.model.access.csv.template new file mode 100644 index 000000000..0d2111f9d --- /dev/null +++ b/prototype/templates/8.0/security/ir.model.access.csv.template @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +{% for rule in access_rules %} +{{ rule.id }},{{ rule.name }},{{ rule.model_id.id }},{{ rule.group_id.id }},{{ rule.perm_write }},{{ rule.perm_write }},{{ rule.perm_create }},{{ rule.perm_unlink }} +{% endfor %} diff --git a/prototype/templates/8.0/security/model_name.xml b/prototype/templates/8.0/security/model_name.xml deleted file mode 100644 index 8cd0f5749..000000000 --- a/prototype/templates/8.0/security/model_name.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - $groups - - $rules - - - diff --git a/prototype/templates/7.0/security/model_name.xml b/prototype/templates/8.0/security/model_name.xml.template similarity index 63% rename from prototype/templates/7.0/security/model_name.xml rename to prototype/templates/8.0/security/model_name.xml.template index 8cd0f5749..6f2d4e508 100644 --- a/prototype/templates/7.0/security/model_name.xml +++ b/prototype/templates/8.0/security/model_name.xml.template @@ -2,9 +2,9 @@ - $groups + {{ groups }} - $rules + {{ rules }} diff --git a/prototype/templates/8.0/views/model_menus.xml.template b/prototype/templates/8.0/views/model_menus.xml.template new file mode 100644 index 000000000..642a682d8 --- /dev/null +++ b/prototype/templates/8.0/views/model_menus.xml.template @@ -0,0 +1,24 @@ + + + + {% for menu in menus -%} + + {{ menu.action.name }} + {{ menu.action.type }} + {{ menu.action.res_model }} + {{ menu.action.view_type }} + {{ menu.action.view_mode }} + {% if menu.action.help %}{{ menu.action.help }} + {% endif %} + + + + {% endfor -%} + + diff --git a/prototype/templates/8.0/views/model_view.xml b/prototype/templates/8.0/views/model_view.xml deleted file mode 100644 index 45fa4957e..000000000 --- a/prototype/templates/8.0/views/model_view.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - $views - - - diff --git a/prototype/templates/8.0/views/model_views.xml.template b/prototype/templates/8.0/views/model_views.xml.template new file mode 100644 index 000000000..4eba907ba --- /dev/null +++ b/prototype/templates/8.0/views/model_views.xml.template @@ -0,0 +1,23 @@ + + + + + + {% for view in views %} + + {{ view.name }}.view + {{ view.model }} + {{ view.type }} + + + {# the arch given by odoo start with an xml tag that + will break the xml tree we build. + Be careful, custom field have a x_ prefix that has to be + removed + #} + {{ view.arch|replace('', '')|replace('"x_', '"') }} + + + {% endfor %} + + diff --git a/prototype/templates/8.0/__init__.py b/prototype/tests/__init__.py similarity index 75% rename from prototype/templates/8.0/__init__.py rename to prototype/tests/__init__.py index 2a599284e..cb0e34aff 100644 --- a/prototype/templates/8.0/__init__.py +++ b/prototype/tests/__init__.py @@ -1,9 +1,9 @@ # -*- encoding: utf-8 -*- ############################################################################## # -# Odoo, Open Source Management Solution -# This module copyright (C) $generation_date $author -# (<$website>). +# OpenERP, Open Source Management Solution +# This module copyright (C) 2010 - 2014 Savoir-faire Linux +# (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,4 +19,10 @@ # along with this program. If not, see . # ############################################################################## -from . import models +from . import test_prototype_module_export +from . import test_prototype + +checks = [ + test_prototype_module_export, + test_prototype, +] diff --git a/prototype/tests/test_prototype.py b/prototype/tests/test_prototype.py new file mode 100644 index 000000000..2d082cf9e --- /dev/null +++ b/prototype/tests/test_prototype.py @@ -0,0 +1,83 @@ +# -*- encoding: utf-8 -*- # +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Savoir-faire Linux +# (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# + +from jinja2 import Environment +from jinja2.exceptions import TemplateNotFound +from openerp.tests import common + + +class test_prototype(common.TransactionCase): + def setUp(self): + super(test_prototype, self).setUp() + self.main_model = self.env['prototype'] + self.module_category_model = self.env['ir.module.category'] + self.module_module_model = self.env['ir.module.module'] + + self.prototype = self.main_model.create({ + 'name': 't_name', + 'category_id': self.module_category_model.browse(1).id, + 'human_name': 't_human_name', + 'summary': 't_summary', + 'description': 't_description', + 'author': 't_author', + 'maintainer': 't_maintainer', + 'website': 't_website', + 'dependencies': [(6, 0, [1, 2, 3, 4])], + }) + self.api_version = '8.0' + + def test_generate_files_assert_if_no_env(self): + self.assertRaises( + AssertionError, + self.prototype.generate_files + ) + + def test_generate_files(self): + """Test generate_files returns a tuple.""" + self.prototype.set_jinja_env(self.api_version) + details = self.prototype.generate_files() + self.assertIsInstance(details, list) + # namedtuples in tuple + for file_details in details: + self.assertIsInstance(file_details, tuple) + self.assertIsInstance(file_details.filename, basestring) + self.assertIsInstance(file_details.filecontent, basestring) + + def test_generate_files_raise_templatenotfound_if_not_found(self): + self.prototype.set_jinja_env('t_api_version') + self.assertRaises( + TemplateNotFound, + self.prototype.generate_files + ) + + def test_set_env(self): + """test the jinja2 environment is set.""" + self.assertIsNone(self.prototype._env) + self.prototype.set_jinja_env(self.api_version) + self.assertIsInstance( + self.prototype._env, Environment + ) + + def test_friendly_name_return(self): + """Test if the returns match the pattern.""" + name = 'res.partner' + self.assertEqual( + self.prototype.friendly_name(name), + name.replace('.', '_') + ) diff --git a/prototype/tests/test_prototype_module_export.py b/prototype/tests/test_prototype_module_export.py new file mode 100644 index 000000000..87ef77e40 --- /dev/null +++ b/prototype/tests/test_prototype_module_export.py @@ -0,0 +1,83 @@ +# -*- encoding: utf-8 -*- +# ############################################################################# +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2010 - 2014 Savoir-faire Linux +# (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +from openerp.tests import common +import zipfile +import StringIO + + +class test_prototype_module_export(common.TransactionCase): + def setUp(self): + super(test_prototype_module_export, self).setUp() + self.main_model = self.env['prototype.module.export'] + self.prototype_model = self.env['prototype'] + self.module_category_model = self.env[ + 'ir.module.category' + ] + + self.prototype = self.prototype_model.create({ + 'name': 't_name', + 'category_id': self.module_category_model.browse(1).id, + 'human_name': 't_human_name', + 'summary': 't_summary', + 'description': 't_description', + 'author': 't_author', + 'maintainer': 't_maintainer', + 'website': 't_website', + }) + + self.exporter = self.main_model.create({'name': 't_name'}) + + def test_action_export_assert_for_wrong_active_model(self): + """Test if the assertion raises.""" + exporter = self.main_model.with_context( + active_model='t_active_model' + ).create({}) + self.assertRaises( + AssertionError, + exporter.action_export, + [exporter.id], + ) + + def test_action_export_update_wizard(self): + """Test if the wizard is updated during the process.""" + exporter = self.main_model.with_context( + active_model=self.prototype_model._name, + active_id=self.prototype.id + ).create({}) + exporter.action_export(exporter.id) + self.assertEqual(exporter.state, 'get') + self.assertEqual(exporter.name, '{}.zip'.format(self.prototype.name)) + + def test_zip_files_returns_tuple(self): + """Test the method return of the method that generate the zip file.""" + file_details = ( + ('test.txt', 'generated'), + ) + ret = self.main_model.zip_files(file_details) + self.assertIsInstance(ret, tuple) + self.assertIsInstance( + ret.zip_file, zipfile.ZipFile + ) + + self.assertIsInstance( + ret.stringIO, StringIO.StringIO + ) diff --git a/prototype/views/prototype_view.xml b/prototype/views/prototype_view.xml index 3573c33fe..c68396331 100644 --- a/prototype/views/prototype_view.xml +++ b/prototype/views/prototype_view.xml @@ -1,97 +1,103 @@ - + - - prototype.tree - prototype - - - - - - - - + + prototype.tree + prototype + + + + + + + + - - prototype.form - prototype - -
- - - -
-

-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
+ + prototype.form + prototype + +
+ + + +
+

+ +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
- - Prototype - prototype - form - tree,form - - + + Prototype + prototype + form + tree,form + + - + -
+
diff --git a/prototype/wizard/prototype_module_export.py b/prototype/wizard/prototype_module_export.py index e5abe5775..1811d0a99 100644 --- a/prototype/wizard/prototype_module_export.py +++ b/prototype/wizard/prototype_module_export.py @@ -1,12 +1,12 @@ # -*- encoding: utf-8 -*- -############################################################################## +# ############################################################################# # -# OpenERP, Open Source Management Solution -# This module copyright (C) 2010 - 2014 Savoir-faire Linux -# (). +# OpenERP, Open Source Management Solution +# This module copyright (C) 2010 - 2014 Savoir-faire Linux +# (). # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # @@ -19,49 +19,103 @@ # along with this program. If not, see . # ############################################################################## -from openerp.osv import fields,osv -from openerp.tools.translate import _ +import StringIO +import base64 +import zipfile +from collections import namedtuple +from openerp import fields, models, api -class prototype_module_export(osv.osv_memory): +class prototype_module_export(models.TransientModel): _name = "prototype.module.export" - _columns = { - 'name': fields.char('File Name', readonly=True), - 'api_version': fields.selection([('8.0','8.0'), - ('7.0', '7.0')], 'API version', - required=True), - 'data': fields.binary('File', readonly=True), - 'state': fields.selection([('choose', 'choose'), # choose version - ('get', 'get')]) # get module - } - _defaults = { - 'state': 'choose', - 'api_version': '8.0', - } + name = fields.Char('File Name', readonly=True) + # It is implemented in order to manage previous and next versions + # of odoo + api_version = fields.Selection( + [ + ('8.0', '8.0'), + # ('7.0', '7.0') + ], + 'API version', + required=True, + default='8.0' + ) + data = fields.Binary('File', readonly=True) + state = fields.Selection( + [ + ('choose', 'choose'), # choose version + ('get', 'get') # get module + ], + default='choose' + ) - def act_getfile(self, cr, uid, ids, context=None): + @api.model + def action_export(self, ids): """ Export a zip file containing the module based on the information provided in the prototype, using the templates chosen in the wizard. """ - this = self.browse(cr, uid, ids)[0] + if isinstance(ids, (int, long)): + ids = [ids] + wizard = self.browse(ids) + + active_model = self._context.get('active_model') + + # checking if the wizard was called by a prototype. + assert active_model == 'prototype', \ + '{} has to be called from a "prototype" , not a "{}"'.format( + self, active_model + ) + + # getting the prototype of the wizard + prototype = self.env[active_model].browse( + self._context.get('active_id') + ) + + # setting the jinja environment. + # They will help the program to find the template to render the files + # with. + prototype.set_jinja_env(wizard.api_version) - # TODO: Implement the export logic here - filename = 'new' - this.name = "%s.%s" % (filename, 'zip') - out = 'toto' - # /TODO + # generate_files ask the prototype to investigate the input + # and to generate the file templates according to it. + # zip_files, in another hand, put all the template files into a package + # ready to be saved by the user. + zip_details = self.zip_files(prototype.generate_files()) + + wizard.write( + { + 'name': '{}.zip'.format(prototype.name), + 'state': 'get', + 'data': base64.encodestring(zip_details.stringIO.getvalue()) + } + ) - self.write(cr, uid, ids, {'state': 'get', - 'data': out, - 'name':this.name}, context=context) return { 'type': 'ir.actions.act_window', 'res_model': 'prototype.module.export', 'view_mode': 'form', 'view_type': 'form', - 'res_id': this.id, + 'res_id': wizard.id, 'views': [(False, 'form')], 'target': 'new', } + + @staticmethod + def zip_files(file_details): + """Takes a set of file and zips them. + :param file_details: tuple (filename, filecontent) + :return: tuple (zip_file, stringIO) + """ + zip_details = namedtuple('Zip_details', ['zip_file', 'stringIO']) + out = StringIO.StringIO() + + with zipfile.ZipFile(out, 'w') as target: + for filename, filecontent in file_details: + info = zipfile.ZipInfo(filename) + info.compress_type = zipfile.ZIP_DEFLATED + info.external_attr = 2175008768 # specifies mode 0644 + target.writestr(info, filecontent) + + return zip_details(zip_file=target, stringIO=out) diff --git a/prototype/wizard/prototype_module_export_view.xml b/prototype/wizard/prototype_module_export_view.xml index 4370e6114..e867c9af4 100644 --- a/prototype/wizard/prototype_module_export_view.xml +++ b/prototype/wizard/prototype_module_export_view.xml @@ -21,7 +21,7 @@

Here is the exported module:

-