From fa68710b3b21a535a50c9b2c95503107cb5360f4 Mon Sep 17 00:00:00 2001 From: EliseDup Date: Wed, 9 Mar 2016 15:44:50 +0100 Subject: [PATCH 01/10] S001 --- beesdoo_product/__openerp__.py | 2 +- beesdoo_product/models/beesdoo_product.py | 13 +++++++- beesdoo_product/views/beesdoo_product.xml | 5 ++- beesdoo_purchase/__init__.py | 2 ++ beesdoo_purchase/__openerp__.py | 31 +++++++++++++++++++ beesdoo_purchase/models/__init__.py | 3 ++ beesdoo_purchase/models/purchase_order.py | 17 ++++++++++ beesdoo_purchase/security/ir.model.access.csv | 1 + beesdoo_purchase/views/purchase_order.xml | 14 +++++++++ 9 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 beesdoo_purchase/__init__.py create mode 100644 beesdoo_purchase/__openerp__.py create mode 100644 beesdoo_purchase/models/__init__.py create mode 100644 beesdoo_purchase/models/purchase_order.py create mode 100644 beesdoo_purchase/security/ir.model.access.csv create mode 100644 beesdoo_purchase/views/purchase_order.xml diff --git a/beesdoo_product/__openerp__.py b/beesdoo_product/__openerp__.py index bc1c3ea..cdf8dd5 100644 --- a/beesdoo_product/__openerp__.py +++ b/beesdoo_product/__openerp__.py @@ -20,7 +20,7 @@ 'version': '0.1', # any module necessary for this one to work correctly - 'depends': ['beesdoo_base', 'product'], + 'depends': ['beesdoo_base', 'product', 'point_of_sale'], # always loaded 'data': [ diff --git a/beesdoo_product/models/beesdoo_product.py b/beesdoo_product/models/beesdoo_product.py index ad95630..9195044 100644 --- a/beesdoo_product/models/beesdoo_product.py +++ b/beesdoo_product/models/beesdoo_product.py @@ -8,7 +8,18 @@ class BeesdooProduct(models.Model): local_label = fields.Many2one('beesdoo.product.label', domain = [('type', '=', 'local')]) fair_label = fields.Many2one('beesdoo.product.label', domain = [('type', '=', 'fair')]) origin_label = fields.Many2one('beesdoo.product.label', domain = [('type', '=', 'delivery')]) - + + main_seller_id = fields.Many2one('res.partner', compute='_compute_main_seller_id', store=True) + + @api.one + @api.depends('seller_ids') + def _compute_main_seller_id(self): + # Ce champs doit être champs calculé qui va chercher + # le vendeur associé qui a la date de début la plus récente et plus petite qu’aujourd’hui + self.main_seller_id = sorted(self.seller_ids, key=lambda seller: seller.date_start, reverse=True)[0].name + + + class BeesdooProductLabel(models.Model): _name = "beesdoo.product.label" diff --git a/beesdoo_product/views/beesdoo_product.xml b/beesdoo_product/views/beesdoo_product.xml index 21b329b..a59a145 100644 --- a/beesdoo_product/views/beesdoo_product.xml +++ b/beesdoo_product/views/beesdoo_product.xml @@ -1,6 +1,8 @@ - + + + bees.product.template.form product.template @@ -10,6 +12,7 @@ + diff --git a/beesdoo_purchase/__init__.py b/beesdoo_purchase/__init__.py new file mode 100644 index 0000000..0f7cb6b --- /dev/null +++ b/beesdoo_purchase/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +import models \ No newline at end of file diff --git a/beesdoo_purchase/__openerp__.py b/beesdoo_purchase/__openerp__.py new file mode 100644 index 0000000..283d686 --- /dev/null +++ b/beesdoo_purchase/__openerp__.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +{ + 'name': "Bees Purchase", + + 'summary': """ + Extension du module Purchase""", + + 'description': """ + Long description of module's purpose + """, + + 'author': "Beescoop - Cellule IT", + 'website': "https://github.com/beescoop/Obeesdoo", + + # Categories can be used to filter modules in modules listing + # Check https://github.com/odoo/odoo/blob/master/openerp/addons/base/module/module_data.xml + # for the full list + 'category': 'Purchase', + 'version': '0.1', + + # any module necessary for this one to work correctly + 'depends': ['base','purchase','beesdoo_product'], + + # always loaded + 'data': [ + 'views/purchase_order.xml', + 'security/ir.model.access.csv', + ], + # only loaded in demonstration mode + 'demo': [], +} \ No newline at end of file diff --git a/beesdoo_purchase/models/__init__.py b/beesdoo_purchase/models/__init__.py new file mode 100644 index 0000000..667b7e3 --- /dev/null +++ b/beesdoo_purchase/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import purchase_order \ No newline at end of file diff --git a/beesdoo_purchase/models/purchase_order.py b/beesdoo_purchase/models/purchase_order.py new file mode 100644 index 0000000..d9d41a5 --- /dev/null +++ b/beesdoo_purchase/models/purchase_order.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from openerp import models, fields, api + +class PurchaseOrder(models.Model): + + _inherit = 'purchase.order' + +class PurchaseOrderLine(models.Model): + + _inherit = 'purchase.order.line' + + product_id = fields.Many2one('product.product', string='Product', + domain=['&',('purchase_ok', '=', True),('template.main_seller_id','=','order_id.partner_id')], change_default=True, required=True) + + @api.onchange('order_id') + def _onchange_order_id(self): + print "changed", self.order_id, self.order_id.partner_id \ No newline at end of file diff --git a/beesdoo_purchase/security/ir.model.access.csv b/beesdoo_purchase/security/ir.model.access.csv new file mode 100644 index 0000000..58262d4 --- /dev/null +++ b/beesdoo_purchase/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink \ No newline at end of file diff --git a/beesdoo_purchase/views/purchase_order.xml b/beesdoo_purchase/views/purchase_order.xml new file mode 100644 index 0000000..7db8df9 --- /dev/null +++ b/beesdoo_purchase/views/purchase_order.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file From 0a17e62595826fdbf03116171ed1463840e8bd4f Mon Sep 17 00:00:00 2001 From: EliseDup Date: Wed, 9 Mar 2016 23:03:32 +0100 Subject: [PATCH 02/10] last changes --- beesdoo_purchase/models/purchase_order.py | 7 ------- beesdoo_purchase/views/purchase_order.xml | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/beesdoo_purchase/models/purchase_order.py b/beesdoo_purchase/models/purchase_order.py index d9d41a5..3731456 100644 --- a/beesdoo_purchase/models/purchase_order.py +++ b/beesdoo_purchase/models/purchase_order.py @@ -8,10 +8,3 @@ class PurchaseOrder(models.Model): class PurchaseOrderLine(models.Model): _inherit = 'purchase.order.line' - - product_id = fields.Many2one('product.product', string='Product', - domain=['&',('purchase_ok', '=', True),('template.main_seller_id','=','order_id.partner_id')], change_default=True, required=True) - - @api.onchange('order_id') - def _onchange_order_id(self): - print "changed", self.order_id, self.order_id.partner_id \ No newline at end of file diff --git a/beesdoo_purchase/views/purchase_order.xml b/beesdoo_purchase/views/purchase_order.xml index 7db8df9..e3e255a 100644 --- a/beesdoo_purchase/views/purchase_order.xml +++ b/beesdoo_purchase/views/purchase_order.xml @@ -1,14 +1,14 @@ - \ No newline at end of file From 9f618377e8953da49921fb272c5169b872886f1e Mon Sep 17 00:00:00 2001 From: EliseDup Date: Thu, 10 Mar 2016 09:23:53 +0100 Subject: [PATCH 03/10] SOO1 : placer le fournisseur principal au bon endroit dans la vue --- beesdoo_product/models/beesdoo_product.py | 3 ++- beesdoo_product/views/beesdoo_product.xml | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/beesdoo_product/models/beesdoo_product.py b/beesdoo_product/models/beesdoo_product.py index 9195044..7e2fe7e 100644 --- a/beesdoo_product/models/beesdoo_product.py +++ b/beesdoo_product/models/beesdoo_product.py @@ -16,7 +16,8 @@ class BeesdooProduct(models.Model): def _compute_main_seller_id(self): # Ce champs doit être champs calculé qui va chercher # le vendeur associé qui a la date de début la plus récente et plus petite qu’aujourd’hui - self.main_seller_id = sorted(self.seller_ids, key=lambda seller: seller.date_start, reverse=True)[0].name + if self.seller_ids: + self.main_seller_id = sorted(self.seller_ids, key=lambda seller: seller.date_start, reverse=True)[0].name diff --git a/beesdoo_product/views/beesdoo_product.xml b/beesdoo_product/views/beesdoo_product.xml index a59a145..b829117 100644 --- a/beesdoo_product/views/beesdoo_product.xml +++ b/beesdoo_product/views/beesdoo_product.xml @@ -2,7 +2,7 @@ - + bees.product.template.form product.template @@ -12,11 +12,21 @@ - + + bees.product.template.form2 + product.template + + +
+ +
+
+
+ bees.product.label.form beesdoo.product.label From d9c8ad9f76a79624a4cb0fa8a5a64fcd31981f8d Mon Sep 17 00:00:00 2001 From: EliseDup Date: Tue, 15 Mar 2016 21:49:49 +0100 Subject: [PATCH 04/10] S0022 --- beesdoo_base/views/partner.xml | 89 +++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 39 deletions(-) diff --git a/beesdoo_base/views/partner.xml b/beesdoo_base/views/partner.xml index ff211a2..067bf1e 100644 --- a/beesdoo_base/views/partner.xml +++ b/beesdoo_base/views/partner.xml @@ -1,43 +1,54 @@ - - beesdoo.partner.form.view - res.partner - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {'invisible' : [('eater', '!=', 'worker_eater')]} - - - - - - + + beesdoo.partner.form.view + res.partner + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {'invisible' : [('eater', '!=', + 'worker_eater')]} + + + + + + + + + + {'search_default_supplier': 1,'default_customer': + 0,'default_supplier': 1, 'default_is_company' : True, + 'default_company_type' : 'company'} + \ No newline at end of file From d05a99c53ca4266cd7e8182ced7aeb269fcb8cb9 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Sun, 17 Apr 2016 15:11:03 +0200 Subject: [PATCH 05/10] [CLEAN] Remove debug print --- beesdoo_product/models/beesdoo_product.py | 1 - 1 file changed, 1 deletion(-) diff --git a/beesdoo_product/models/beesdoo_product.py b/beesdoo_product/models/beesdoo_product.py index 0abe3e4..666c422 100644 --- a/beesdoo_product/models/beesdoo_product.py +++ b/beesdoo_product/models/beesdoo_product.py @@ -17,7 +17,6 @@ class BeesdooProduct(models.Model): def _compute_main_seller_id(self): # Calcule le vendeur associé qui a la date de début la plus récente et plus petite qu’aujourd’hui sellers_ids = self.seller_ids.sorted(key=lambda seller: seller.date_start, reverse=True) - print sellers_ids self.main_seller_id = sellers_ids and sellers_ids[0].name or False From a50be69581f74279253349dd7a7dad48c76f9e27 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Wed, 4 May 2016 11:24:37 +0200 Subject: [PATCH 06/10] [ADD] import script --- beesdoo_migration_asbl_to_coop/__init__.py | 22 + beesdoo_migration_asbl_to_coop/__openerp__.py | 40 ++ beesdoo_migration_asbl_to_coop/migration.py | 222 ++++++++++ .../view/migration.xml | 31 ++ import_base/__init__.py | 25 ++ import_base/__openerp__.py | 42 ++ import_base/import_framework.py | 415 ++++++++++++++++++ import_base/mapper.py | 182 ++++++++ import_odoo/__init__.py | 23 + import_odoo/__openerp__.py | 41 ++ import_odoo/odoo_connector.py | 38 ++ import_odoo/view/connector.xml | 67 +++ 12 files changed, 1148 insertions(+) create mode 100644 beesdoo_migration_asbl_to_coop/__init__.py create mode 100644 beesdoo_migration_asbl_to_coop/__openerp__.py create mode 100644 beesdoo_migration_asbl_to_coop/migration.py create mode 100644 beesdoo_migration_asbl_to_coop/view/migration.xml create mode 100644 import_base/__init__.py create mode 100644 import_base/__openerp__.py create mode 100644 import_base/import_framework.py create mode 100644 import_base/mapper.py create mode 100644 import_odoo/__init__.py create mode 100644 import_odoo/__openerp__.py create mode 100644 import_odoo/odoo_connector.py create mode 100644 import_odoo/view/connector.xml diff --git a/beesdoo_migration_asbl_to_coop/__init__.py b/beesdoo_migration_asbl_to_coop/__init__.py new file mode 100644 index 0000000..7f367d6 --- /dev/null +++ b/beesdoo_migration_asbl_to_coop/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Openerp sa (). +# +# 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 . +# +############################################################################## + +import migration diff --git a/beesdoo_migration_asbl_to_coop/__openerp__.py b/beesdoo_migration_asbl_to_coop/__openerp__.py new file mode 100644 index 0000000..48ee0f1 --- /dev/null +++ b/beesdoo_migration_asbl_to_coop/__openerp__.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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': 'Import data from ASBL', + 'version': '0.9', + 'category': 'Import', + 'description': """ + This module provide a tools to import data from ASBL + """, + 'author': 'Thibault Francois', + 'website': 'https://github.com/tfrancoi/', + 'depends': ['base', 'import_base', 'import_odoo'], + 'data': [ + 'view/migration.xml' + ], + 'test': [], #TODO provide test + 'installable': True, + 'auto_install': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/beesdoo_migration_asbl_to_coop/migration.py b/beesdoo_migration_asbl_to_coop/migration.py new file mode 100644 index 0000000..1226288 --- /dev/null +++ b/beesdoo_migration_asbl_to_coop/migration.py @@ -0,0 +1,222 @@ +# -*- coding: utf-8 -*- + +from openerp import models, fields, api +from openerp.exceptions import Warning + +from openerp.addons.import_base.import_framework import * +from openerp.addons.import_base.mapper import * + + +class odoo_connection_data(models.TransientModel): + + _name = 'beesdoo.import.asbl' + + @api.multi + def migrate(self): + imp = migration_framework(self, self.env.cr, self.env.uid, "Odoo", 'beesdoo.import.asbl', dict(self.env.context)) + imp.launch_import() + + +class migration_framework(import_framework): + black_list_field = { + + } + + tables = ['product.category', + 'product.uom', + 'product.uom.categ', + 'pos.category', + 'res.partner', + 'product.template', + 'product.supplierinfo'] + + table_domain = { + 'res.partner' : [('supplier', '=', True), '|', ('active', '=', True), ('active', '=', False)], + 'product.template' : ['|', ('active', '=', True), ('active', '=', False)] + } + + + def initialize(self): + self.connection = self.obj.env['import.odoo.connection'].search([], limit=1) + self.set_table_list(self.tables) + print self.connection.name + + def _get_field(self, model): + fields_info = model.fields_get() + fields = ['id'] + for f_name, f_info in fields_info.items(): + if f_info['type'] in ('many2one', 'many2many'): + fields.append(f_name + '/id') + elif f_info['type'] != 'one2many': + fields.append(f_name) + #if not 'function' in f_info.keys(): + # elif f_info['type'] in ('float', 'integer', 'char', 'text', 'date', 'datetime', 'boolean', 'selection'): + # fields.append(f_name) + #if f_name in self.black_list_field.get(model.model_name, []): + # print f_info + return fields + + def res_to_dict(self, fields, datas): + datas = datas['datas'] + res = [] + for data in datas: + data_dict = {} + for i, field in enumerate(fields): + data_dict[field] = data[i] + res.append(data_dict) + return res + + def get_data(self, table): + con = self.connection._get_connection() + obj = con.get_model(table) + fields = self._get_field(obj) + ids = obj.search(self.table_domain.get(table, [])) + datas = obj.export_data(ids, fields, context={'lang' : 'fr_BE'}) + return self.res_to_dict(fields, datas) + + def _generate_xml_id(self, name, table): + """ + @param name: name of the object, has to be unique in for a given table + @param table : table where the record we want generate come from + @return: a unique xml id for record, the xml_id will be the same given the same table and same name + To be used to avoid duplication of data that don't have ids + """ + return name + + + def get_mapping(self): + return { + 'product.category': { + 'model' : 'product.category', + 'dependencies' : [], + 'map' : { + 'name' : 'name', + 'parent_id/id_parent' : 'parent_id/id', + 'type' : 'type', + + } + }, + 'product.uom.categ' : { + 'model' : 'product.uom.categ', + 'dependencies' : [], + 'map' : { + 'name' : 'name', + } + }, + 'product.uom': { + 'model' : 'product.uom', + 'dependencies' : ['product.uom.categ'], + 'map' : { + 'name' : 'name', + 'category_id/id' : 'category_id/id', + 'rounding' : 'rounding', + 'uom_type' : 'uom_type', + 'factor' : 'factor', + 'factor_inv' : 'factor_inv', + } + }, + 'pos.category': { + 'model' : 'pos.category', + 'dependencies' : [], + 'map' : { + 'id' : 'id', + 'name' : 'name', + 'parent_id/id_parent' : 'parent_id/id', + } + }, + 'res.partner': { + 'model' : 'res.partner', + 'dependencies' : [], + 'map' : { + 'active' : 'active', + 'barcode' : 'barcode', + 'birthdate' : 'birthdate', + 'city' : 'city', + 'comment' : 'comment', + 'company_type' : 'company_type', + 'contact_address' : 'contact_address', + 'country_id/id' : 'country_id/id', + 'email' : 'email', + 'employee' : 'employee', + 'fax' : 'fax', + 'first_name' : 'first_name', + 'function' : 'function', + 'is_company' : 'is_company', + 'lang' : 'lang', + 'last_name' : 'last_name', + 'mobile' : 'mobile', + 'name' : 'name', + 'parent_id/id_parent' : 'parent_id/id', + 'phone' : 'phone', + 'ref' : 'ref', + 'street' : 'street', + 'street2' : 'street2', + 'supplier' : 'supplier', + 'vat' : 'website', + 'website' : 'website', + 'zip' : 'zip', + 'supplier' : 'supplier', + } + }, + 'beesdoo.product.label' : { + 'model' : 'beesdoo.product.label', + 'dependencies' : [], + 'map' : { + 'color_code' : 'color_code', + 'name' : 'name', + 'type' : 'type', + } + }, + 'product.template': { + 'model' : 'product.template', + 'dependencies' : ['pos.category', 'product.category', 'beesdoo.product.label'], + 'map' : { + 'active' : 'active', + 'available_in_pos' : 'available_in_pos', + 'barcode' : 'barcode', + 'categ_id/id' : 'categ_id/id', + 'default_code' : 'default_code', + 'description' : 'description', + 'description_picking' : 'description_picking', + 'description_purchase' : 'description_purchase', + 'description_sale' : 'descritpion_sale', + 'eco_label/id' : 'eco_label/id', + 'fair_label/id' : 'fair_label/id', + 'invoice_policy' : 'invoice_policy', + 'local_label/id' : 'local_label/id', + 'name' : 'name', + 'origin_label/id' : 'origin_label/id', + 'pos_categ_id/id' : 'pos_categ_id/id', + 'purchase_ok' : 'purchase_ok', + 'sale_delay' : 'sale_delay', + 'sale_ok' : 'sale_ok', + 'standard_price' : 'standard_price', + 'supplier_taxes_id' : 'supplier_taxes_id', #Taxes problème + 'taxes_id' : 'taxes_id', + 'to_weight' : 'to_weight', + 'type' : 'type', + 'uom_id/id' : 'uom_id/id', + 'uom_po_id/id' : 'uom_po_id/id', + 'weight' : 'weight', + } + }, + 'product.supplierinfo': { + 'model' : 'product.supplierinfo', + 'dependencies' : ['product.template'], + 'map' : { + 'delay' : 'delay', + 'min_qty' : 'min_qty', + 'name/id' : 'name/id', + 'price' : 'price', + 'product_code' : 'product_code', + 'product_name' : 'product_name', + 'product_uom/id' : 'product_uom/id', + 'date_start' : 'date_start', + 'date_end' : 'date_end', + 'product_tmpl_id/id': 'product_tmpl_id/id', + } + }, + } + + + diff --git a/beesdoo_migration_asbl_to_coop/view/migration.xml b/beesdoo_migration_asbl_to_coop/view/migration.xml new file mode 100644 index 0000000..568c4f8 --- /dev/null +++ b/beesdoo_migration_asbl_to_coop/view/migration.xml @@ -0,0 +1,31 @@ + + + + + beesdoo.import.asbl.form + beesdoo.import.asbl + +
+
+
+
+
+
+ + + Import From ASBL + beesdoo.import.asbl + form + form + new + + + +
+
diff --git a/import_base/__init__.py b/import_base/__init__.py new file mode 100644 index 0000000..52366e5 --- /dev/null +++ b/import_base/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Openerp sa (). +# +# 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 . +# +############################################################################## + +import import_framework +import mapper + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/import_base/__openerp__.py b/import_base/__openerp__.py new file mode 100644 index 0000000..08f06eb --- /dev/null +++ b/import_base/__openerp__.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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': 'Framework for complex import', + 'version': '0.9', + 'category': 'Hidden/Dependency', + 'description': """ + This module provide a class import_framework to help importing + complex data from other software + """, + 'author': 'OpenERP SA', + 'website': 'http://www.openerp.com', + 'depends': ['base'], + 'init_xml': [], + 'update_xml': [], + 'demo_xml': [], + 'test': [], #TODO provide test + 'installable': True, + 'auto_install': False, + 'certificate': '00141537995453', +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/import_base/import_framework.py b/import_base/import_framework.py new file mode 100644 index 0000000..5deea22 --- /dev/null +++ b/import_base/import_framework.py @@ -0,0 +1,415 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## +import pprint +import mapper +from openerp.tools.translate import _ + +import datetime +import logging +import StringIO +import traceback +pp = pprint.PrettyPrinter(indent=4) + + + + +class import_framework(): + """ + This class should be extends, + get_data and get_mapping have to extends + get_state_map and initialize can be extended + for advanced purpose get_default_hook can also be extended + @see dummy import for a minimal exemple + """ + + """ + for import_object, this domain will avoid to find an already existing object + """ + DO_NOT_FIND_DOMAIN = [('id', '=', 0)] + + #TODO don't use context to pass credential parameters + def __init__(self, obj, cr, uid, instance_name, module_name, context=None): + self.external_id_field = 'id' + self.obj = obj + self.cr = cr + self.uid = uid + self.instance_name = instance_name + self.module_name = module_name + self.context = context or {} + self.table_list = [] + self.logger = logging.getLogger(module_name) + self.initialize() + + """ + Abstract Method to be implemented in + the real instance + """ + def initialize(self): + """ + init before import + usually for the login + """ + pass + + def init_run(self): + """ + call after intialize run in the thread, not in the main process + TO use for long initialization operation + """ + pass + + def get_data(self, table): + """ + @return: a list of dictionaries + each dictionnaries contains the list of pair external_field_name : value + """ + return [{}] + + def get_link(self, from_table, ids, to_table): + """ + @return: a dictionaries that contains the association between the id (from_table) + and the list (to table) of id linked + """ + return {} + + def get_external_id(self, data): + """ + @return the external id + the default implementation return self.external_id_field (that has 'id') by default + if the name of id field is different, you can overwrite this method or change the value + of self.external_id_field + """ + return data[self.external_id_field] + + def get_mapping(self): + """ + @return: { TABLE_NAME : { + 'model' : 'openerp.model.name', + #if true import the table if not just resolve dependencies, use for meta package, by default => True + #Not required + 'import' : True or False, + #Not required + 'dependencies' : [TABLE_1, TABLE_2], + #Not required + 'hook' : self.function_name, #get the val dict of the object, return the same val dict or False + 'map' : { @see mapper + 'openerp_field_name' : 'external_field_name', or val('external_field_name') + 'openerp_field_id/id' : ref(TABLE_1, 'external_id_field'), #make the mapping between the external id and the xml on the right + 'openerp_field2_id/id_parent' : ref(TABLE_1,'external_id_field') #indicate a self dependencies on openerp_field2_id + 'state' : map_val('state_equivalent_field', mapping), # use get_state_map to make the mapping between the value of the field and the value of the state + 'text_field' : concat('field_1', 'field_2', .., delimiter=':'), #concat the value of the list of field in one + 'description_field' : ppconcat('field_1', 'field_2', .., delimiter='\n\t'), #same as above but with a prettier formatting + 'field' : call(callable, arg1, arg2, ..), #call the function with all the value, the function should send the value : self.callable + 'field' : callable + 'field' : call(method, val('external_field') interface of method is self, val where val is the value of the field + 'field' : const(value) #always set this field to value + + any custom mapper that you will define + } + }, + + } + """ + return {} + + def default_hook(self, val): + """ + this hook will be apply on each table that don't have hook + here we define the identity hook + """ + return val + + def _import_table(self, table): + self.logger.info('Import table %s' % table) + data = self.get_data(table) + map = self.get_mapping()[table]['map'] + hook = self.get_mapping()[table].get('hook', self.default_hook) + model = self.get_mapping()[table]['model'] + + final_data = [] + for val in data: + res = hook(val) + if res: + final_data.append(res) + return self._save_data(model, dict(map), final_data, table) + + def _save_data(self, model, mapping, datas, table): + """ + @param model: the model of the object to import + @param table : the external table where the data come from + @param mapping : definition of the mapping + @see: get_mapping + @param datas : list of dictionnaries + datas = [data_1, data_2, ..] + data_i is a map external field_name => value + and each data_i have a external id => in data_id['id'] + """ + self.logger.info(' Importing %s into %s' % (table, model)) + if not datas: + return (0, 'No data found') + mapping['id'] = 'id_new' + res = [] + + + self_dependencies = [] + for k in mapping.keys(): + if '_parent' in k: + self_dependencies.append((k[:-7], mapping.pop(k))) + for data in datas: + for k, field_name in self_dependencies: + data[k] = data.get(field_name) and self._generate_xml_id(data.get(field_name), table) + + data['id_new'] = self._generate_xml_id(self.get_external_id(data), table) + fields, values = self._fields_mapp(data, mapping, table) + res.append(values) + + model_obj = self.obj.pool.get(model) + if not model_obj: + raise ValueError(_("%s is not a valid model name") % model) + self.logger.info(_("fields imported : ") + str(fields)) + (p, r, warning, s) = model_obj.import_data(self.cr, self.uid, fields, res, mode='update', current_module=self.module_name, noupdate=False, context=self.context) + self.logger.info('%s %s %s %s %s' % ("Done", p, r, warning, s)) + for (field, field_name) in self_dependencies: + self.logger.info('Import parent %s' % field) + self._import_self_dependencies(model_obj, field, datas) + return (len(res), warning) + + def _import_self_dependencies(self, obj, parent_field, datas): + """ + @param parent_field: the name of the field that generate a self_dependencies, we call the object referenced in this + field the parent of the object + @param datas: a list of dictionnaries + Dictionnaries need to contains + id_new : the xml_id of the object + field_new : the xml_id of the parent + """ + fields = ['id', parent_field] + for data in datas: + if data.get(parent_field): + values = [data['id_new'], data[parent_field]] + res = obj.import_data(self.cr, self.uid, fields, [values], mode='update', current_module=self.module_name, noupdate=False, context=self.context) + + def _preprocess_mapping(self, mapping): + """ + Preprocess the mapping : + after the preprocces, everything is + callable in the val of the dictionary + + use to allow syntaxical sugar like 'field': 'external_field' + instead of 'field' : value('external_field') + """ + map = dict(mapping) + for key, value in map.items(): + if isinstance(value, basestring): + map[key] = mapper.value(value) + #set parent for instance of dbmapper + elif isinstance(value, mapper.dbmapper): + value.set_parent(self) + return map + + + def _fields_mapp(self,dict_sugar, openerp_dict, table): + """ + call all the mapper and transform data + to be compatible with import_data + """ + fields=[] + data_lst = [] + mapping = self._preprocess_mapping(openerp_dict) + for key,val in mapping.items(): + if key not in fields and dict_sugar: + fields.append(key) + value = val(dict(dict_sugar)) + data_lst.append(value) + return fields, data_lst + + def _generate_xml_id(self, name, table): + """ + @param name: name of the object, has to be unique in for a given table + @param table : table where the record we want generate come from + @return: a unique xml id for record, the xml_id will be the same given the same table and same name + To be used to avoid duplication of data that don't have ids + """ + sugar_instance = self.instance_name + name = name.replace('.', '_').replace(',', '_') + return sugar_instance + "_" + table + "_" + name + + + """ + Public interface of the framework + those function can be use in the callable function defined in the mapping + """ + def xml_id_exist(self, table, external_id): + """ + Check if the external id exist in the openerp database + in order to check if the id exist the table where it come from + should be provide + @return the xml_id generated if the external_id exist in the database or false + """ + if not external_id: + return False + + xml_id = self._generate_xml_id(external_id, table) + id = self.obj.pool.get('ir.model.data').search(self.cr, self.uid, [('name', '=', xml_id), ('module', '=', self.module_name)]) + return id and xml_id or False + + def name_exist(self, table, name, model): + """ + Check if the object with the name exist in the openerp database + in order to check if the id exist the table where it come from + should be provide and the model of the object + """ + fields = ['name'] + data = [name] + return self.import_object(fields, data, model, table, name, [('name', '=', name)]) + + def get_mapped_id(self, table, external_id, context=None): + """ + @return return the databse id linked with the external_id + """ + if not external_id: + return False + + xml_id = self._generate_xml_id(external_id, table) + return self.obj.pool.get('ir.model.data').get_object_reference(self.cr, self.uid, self.module_name, xml_id)[1] + + def import_object_mapping(self, mapping, data, model, table, name, domain_search=False): + """ + same as import_objects but instead of two list fields and data, + this method take a dictionnaries : external_field : value + and the mapping similar to the one define in 'map' key + @see import_object, get_mapping + """ + fields, datas = self._fields_mapp(data, mapping, table) + return self.import_object(fields, datas, model, table, name, domain_search) + + def import_object(self, fields, data, model, table, name, domain_search=False): + """ + This method will import an object in the openerp, usefull for field that is only a char in sugar and is an object in openerp + use import_data that will take care to create/update or do nothing with the data + this method return the xml_id + + To be use, when you want to create an object or link if already exist + use DO_NOT_LINK_DOMAIN to create always a new object + @param fields: list of fields needed to create the object without id + @param data: the list of the data, in the same order as the field + ex : fields = ['firstname', 'lastname'] ; data = ['John', 'Mc donalds'] + @param model: the openerp's model of the create/update object + @param table: the table where data come from in sugarcrm, no need to fit the real name of openerp name, just need to be unique + @param unique_name: the name of the object that we want to create/update get the id + @param domain_search : the domain that should find the unique existing record + + @return: the xml_id of the ressources + """ + domain_search = not domain_search and [('name', 'ilike', name)] or domain_search + obj = self.obj.pool.get(model) + if not obj: #if the model doesn't exist + return False + + xml_id = self._generate_xml_id(name, table) + xml_ref = self.mapped_id_if_exist(model, domain_search, table, name) + fields.append('id') + data.append(xml_id) + obj.import_data(self.cr, self.uid, fields, [data], mode='update', current_module=self.module_name, noupdate=True, context=self.context) + return xml_ref or xml_id + + + def mapped_id_if_exist(self, model, domain, table, name): + """ + To be use when we want link with and existing object, if the object don't exist + just ignore. + @param domain : search domain to find existing record, should return a unique record + @param xml_id: xml_id give to the mapping + @param name: external_id or name of the object to create if there is no id + @param table: the name of the table of the object to map + @return : the xml_id if the record exist in the db, False otherwise + """ + obj = self.obj.pool.get(model) + ids = obj.search(self.cr, self.uid, domain, context=self.context) + if ids: + xml_id = self._generate_xml_id(name, table) + ir_model_data_obj = obj.pool.get('ir.model.data') + id = ir_model_data_obj._update(self.cr, self.uid, model, + self.module_name, {}, mode='update', xml_id=xml_id, + noupdate=True, res_id=ids[0], context=self.context) + return xml_id + return False + + + def set_table_list(self, table_list): + """ + Set the list of table to import, this method should be call before run + @param table_list: the list of external table to import + ['Leads', 'Opportunity'] + """ + self.table_list = table_list + + def launch_import(self): + """ + Import all data into openerp, + this is the Entry point to launch the process of import + + + """ + self.data_started = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + error = False + result = [] + try: + self.init_run() + imported = set() #to invoid importing 2 times the sames modules + for table in self.table_list: + to_import = self.get_mapping()[table].get('import', True) + if not table in imported: + res = self._resolve_dependencies(self.get_mapping()[table].get('dependencies', []), imported) + result.extend(res) + if to_import: + (position, warning) = self._import_table(table) + result.append((table, position, warning)) + imported.add(table) + self.cr.commit() + + except Exception, err: + sh = StringIO.StringIO() + traceback.print_exc(file=sh) + error = sh.getvalue() + self.logger.error(error) + + + self.date_ended = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + def _resolve_dependencies(self, dep, imported): + """ + import dependencies recursively + and avoid to import twice the same table + """ + result = [] + for dependency in dep: + if not dependency in imported: + to_import = self.get_mapping()[dependency].get('import', True) + res = self._resolve_dependencies(self.get_mapping()[dependency].get('dependencies', []), imported) + result.extend(res) + if to_import: + r = self._import_table(dependency) + (position, warning) = r + result.append((dependency, position, warning)) + imported.add(dependency) + return result + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/import_base/mapper.py b/import_base/mapper.py new file mode 100644 index 0000000..925ad1e --- /dev/null +++ b/import_base/mapper.py @@ -0,0 +1,182 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 import tools + +class mapper(object): + """ + super class for all mapper class + They are call before import data + to transform the mapping into real value that we + will import + + the call function receive a dictionary with external data + 'external_field' : value + """ + def __call__(self, external_values): + raise NotImplementedError() + +class dbmapper(mapper): + """ + Super class for mapper that need to access to + data base or any function of the import_framework + + self.parent contains a reference to the instance of + the import framework + """ + def set_parent(self, parent): + self.parent = parent + + +class concat(mapper): + """ + Use : contact('field_name1', 'field_name2', delimiter='_') + concat value of fields using the delimiter, delimiter is optional + and by default is a space + """ + def __init__(self, *arg, **delimiter): + self.arg = arg + self.delimiter = delimiter and delimiter.get('delimiter', ' ') or ' ' + + def __call__(self, external_values): + return self.delimiter.join(map(lambda x : tools.ustr(external_values.get(x,'')), self.arg)) + +class ppconcat(mapper): + """ + Use : contact('field_name1', 'field_name2', delimiter='_') + concat external field name and value of fields using the delimiter, + delimiter is optional and by default is a two line feeds + + """ + def __init__(self, *arg, **delimiter): + self.arg = arg + self.delimiter = delimiter and delimiter.get('delimiter', ' ') or '\n\n' + + def __call__(self, external_values): + return self.delimiter.join(map(lambda x : x + ": " + tools.ustr(external_values.get(x,'')), self.arg)) + +class const(mapper): + """ + Use : const(arg) + return always arg + """ + def __init__(self, val): + self.val = val + + def __call__(self, external_values): + return self.val + +class value(mapper): + """ + Use : value(external_field_name) + Return the value of the external field name + this is equivalent to the a single string + + usefull for call if you want your call get the value + and don't care about the name of the field + call(self.method, value('field1')) + """ + def __init__(self, val, default='', fallback=False): + self.val = val + self.default = default + self.fallback = fallback + + def __call__(self, external_values): + val = external_values.get(self.val, self.default) + if self.fallback and (not val or val == self.default): + val = external_values.get(self.fallback, self.default) + return val + + +class map_val(mapper): + """ + Use : map_val(external_field, val_mapping) + where val_mapping is a dictionary + with external_val : openerp_val + + usefull for selection field like state + to map value + """ + def __init__(self, val, map, default='draft'): + self.val = value(val) + self.map = map + self.default = default + + def __call__(self, external_values): + return self.map.get(self.val(external_values), self.default) + +class ref(dbmapper): + """ + Use : ref(table_name, external_id) + return the xml_id of the ressource + + to associate an already imported object with the current object + """ + def __init__(self, table, field_name): + self.table = table + self.field_name = field_name + + def __call__(self, external_values): + return self.parent.xml_id_exist(self.table, external_values.get(self.field_name)) + +class refbyname(dbmapper): + """ + Use : refbyname(table_name, external_name, res.model) + same as ref but use the name of the ressource to find it + """ + def __init__(self, table, field_name, model): + self.table = table + self.field_name = field_name + self.model = model + + def __call__(self, external_values): + v = external_values.get(self.field_name, '') + return self.parent.name_exist(self.table, v , self.model) + +class call(mapper): + """ + Use : call(function, arg1, arg2) + to call the function with external val follow by the arg specified + """ + def __init__(self, fun, *arg): + self.fun = fun + self.arg = arg + + def __call__(self, external_values): + args = [] + for arg in self.arg: + if isinstance(arg, mapper): + args.append(arg(external_values)) + else: + args.append(arg) + return self.fun(external_values, *args) + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + + +def val(field_name): + def val_fun(data_line): + return data_line[field_name] + + return val_fun + +def const(const): + def val_fun(data_line): + return const diff --git a/import_odoo/__init__.py b/import_odoo/__init__.py new file mode 100644 index 0000000..7f1a5f6 --- /dev/null +++ b/import_odoo/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Openerp sa (). +# +# 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 . +# +############################################################################## + +import odoo_connector +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/import_odoo/__openerp__.py b/import_odoo/__openerp__.py new file mode 100644 index 0000000..18fc142 --- /dev/null +++ b/import_odoo/__openerp__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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': 'Framework to import from other odoo instance', + 'version': '0.9', + 'category': 'Import', + 'description': """ + This module provide a class import_framework to help importing + data from odoo + """, + 'author': 'Thibault Francois', + 'website': 'https://github.com/tfrancoi/', + 'depends': ['base', 'import_base'], + 'data': [ + 'view/connector.xml' + ], + 'test': [], #TODO provide test + 'installable': True, + 'auto_install': False, +} + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/import_odoo/odoo_connector.py b/import_odoo/odoo_connector.py new file mode 100644 index 0000000..205d50a --- /dev/null +++ b/import_odoo/odoo_connector.py @@ -0,0 +1,38 @@ +''' +Created on 25 nov. 2014 + +@author: openerp +''' +from openerp import models, fields, api +import openerplib +from openerp.exceptions import Warning + + + + +class odoo_connection_data(models.Model): + + _name = 'import.odoo.connection' + + name = fields.Char("Name", required=True) + host = fields.Char("Host", required=True) + port = fields.Integer("Port", required=True, default=8069) + database = fields.Char("Database", required=True) + user = fields.Char("Login", required=True, default="admin") + password = fields.Char("Password", required=True) + protocol = fields.Selection([('xmlrpc', 'Xmlrpc'), ('jsonrpc', 'Jsonrpc'),('xmlrpcs', 'Xmlrpcs'), ('jsonrpcs', 'Jsonrpcs')], string="Protocol", default="xmlrpc") + active = fields.Boolean("Active", default=True) + + @api.multi + def test_connection(self): + connection = self._get_connection() + connection.check_login(force=True) + raise Warning("Connection Successful") + + def _get_connection(self): + return openerplib.get_connection(hostname=self.host, + port=self.port, + database=self.database, + login=self.user, + password=self.password, + protocol=self.protocol) diff --git a/import_odoo/view/connector.xml b/import_odoo/view/connector.xml new file mode 100644 index 0000000..357e500 --- /dev/null +++ b/import_odoo/view/connector.xml @@ -0,0 +1,67 @@ + + + + + import.odoo.connection.tree + import.odoo.connection + + + + + + + + + + + import.odoo.connection.form + import.odoo.connection + +
+
+
+ +
+
+
+

+ +

+
+ + + + + + + + + + + + + +
+
+
+
+ + + + + Odoo Connector + import.odoo.connection + form + tree,form + + + + + + + + +
+
From 0495c999f8371d3d74e403eff0642e15c7fc5e80 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Wed, 4 May 2016 15:57:08 +0200 Subject: [PATCH 07/10] [FIX] field for partner --- beesdoo_migration_asbl_to_coop/migration.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/beesdoo_migration_asbl_to_coop/migration.py b/beesdoo_migration_asbl_to_coop/migration.py index 1226288..e0ebed3 100644 --- a/beesdoo_migration_asbl_to_coop/migration.py +++ b/beesdoo_migration_asbl_to_coop/migration.py @@ -155,7 +155,9 @@ class migration_framework(import_framework): 'vat' : 'website', 'website' : 'website', 'zip' : 'zip', - 'supplier' : 'supplier', + 'supplier' : 'supplier', + 'customer' : 'customer', + 'vat' : 'vat', } }, 'beesdoo.product.label' : { From 6bb1d34a0a4e061237cc46093443e19261ed2280 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Wed, 11 May 2016 20:15:05 +0200 Subject: [PATCH 08/10] [FIX] taxes import issue --- beesdoo_migration_asbl_to_coop/migration.py | 40 ++++++++++--------- import_base/mapper.py | 44 ++++++++++++++++++++- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/beesdoo_migration_asbl_to_coop/migration.py b/beesdoo_migration_asbl_to_coop/migration.py index e0ebed3..2593fe2 100644 --- a/beesdoo_migration_asbl_to_coop/migration.py +++ b/beesdoo_migration_asbl_to_coop/migration.py @@ -22,13 +22,14 @@ class migration_framework(import_framework): } - tables = ['product.category', - 'product.uom', - 'product.uom.categ', + tables = ['product.category', + 'product.uom', + 'product.uom.categ', 'pos.category', 'res.partner', 'product.template', - 'product.supplierinfo'] + 'product.supplierinfo', + ] table_domain = { 'res.partner' : [('supplier', '=', True), '|', ('active', '=', True), ('active', '=', False)], @@ -42,18 +43,14 @@ class migration_framework(import_framework): print self.connection.name def _get_field(self, model): - fields_info = model.fields_get() fields = ['id'] - for f_name, f_info in fields_info.items(): - if f_info['type'] in ('many2one', 'many2many'): - fields.append(f_name + '/id') - elif f_info['type'] != 'one2many': - fields.append(f_name) - #if not 'function' in f_info.keys(): - # elif f_info['type'] in ('float', 'integer', 'char', 'text', 'date', 'datetime', 'boolean', 'selection'): - # fields.append(f_name) - #if f_name in self.black_list_field.get(model.model_name, []): - # print f_info + + for mapper_object in self.get_mapping()[model.model_name]['map'].values(): + if isinstance(mapper_object, basestring): + fields.append(mapper_object) + else: + fields.extend(mapper_object.get_fields()) + print "read field", fields return fields def res_to_dict(self, fields, datas): @@ -82,6 +79,12 @@ class migration_framework(import_framework): To be used to avoid duplication of data that don't have ids """ return name + + taxes_mapping = { + '5.5% Marchandise' : '6% Marchandises', + '6% Marchandise' : '6% Marchandises', + '21% Services incluse' : '21% Services', + } def get_mapping(self): @@ -152,7 +155,6 @@ class migration_framework(import_framework): 'street' : 'street', 'street2' : 'street2', 'supplier' : 'supplier', - 'vat' : 'website', 'website' : 'website', 'zip' : 'zip', 'supplier' : 'supplier', @@ -181,7 +183,7 @@ class migration_framework(import_framework): 'description' : 'description', 'description_picking' : 'description_picking', 'description_purchase' : 'description_purchase', - 'description_sale' : 'descritpion_sale', + 'description_sale' : 'description_sale', 'eco_label/id' : 'eco_label/id', 'fair_label/id' : 'fair_label/id', 'invoice_policy' : 'invoice_policy', @@ -193,8 +195,8 @@ class migration_framework(import_framework): 'sale_delay' : 'sale_delay', 'sale_ok' : 'sale_ok', 'standard_price' : 'standard_price', - 'supplier_taxes_id' : 'supplier_taxes_id', #Taxes problème - 'taxes_id' : 'taxes_id', + 'supplier_taxes_id' : map_val_default('supplier_taxes_id', self.taxes_mapping), #Taxes problème + 'taxes_id' : map_val_default('taxes_id', self.taxes_mapping), 'to_weight' : 'to_weight', 'type' : 'type', 'uom_id/id' : 'uom_id/id', diff --git a/import_base/mapper.py b/import_base/mapper.py index 925ad1e..9f034a5 100644 --- a/import_base/mapper.py +++ b/import_base/mapper.py @@ -32,6 +32,9 @@ class mapper(object): """ def __call__(self, external_values): raise NotImplementedError() + + def get_fields(self): + return [] class dbmapper(mapper): """ @@ -58,7 +61,10 @@ class concat(mapper): def __call__(self, external_values): return self.delimiter.join(map(lambda x : tools.ustr(external_values.get(x,'')), self.arg)) -class ppconcat(mapper): + def get_fields(self): + return self.arg + +class ppconcat(concat): """ Use : contact('field_name1', 'field_name2', delimiter='_') concat external field name and value of fields using the delimiter, @@ -104,6 +110,9 @@ class value(mapper): val = external_values.get(self.fallback, self.default) return val + def get_fields(self): + return [self.val] + class map_val(mapper): """ @@ -122,6 +131,31 @@ class map_val(mapper): def __call__(self, external_values): return self.map.get(self.val(external_values), self.default) + def get_fields(self): + return self.val.get_fields() + +class map_val_default(mapper): + """ + Use : map_val(external_field, val_mapping) + where val_mapping is a dictionary + with external_val : openerp_val + + usefull for selection field like state + to map value + """ + def __init__(self, val, map): + self.val = value(val) + self.map = map + + def __call__(self, external_values): + print self.val(external_values) + value = self.map.get(self.val(external_values), self.val(external_values)) + print value + return value + + def get_fields(self): + return self.val.get_fields() + class ref(dbmapper): """ Use : ref(table_name, external_id) @@ -135,6 +169,9 @@ class ref(dbmapper): def __call__(self, external_values): return self.parent.xml_id_exist(self.table, external_values.get(self.field_name)) + + def get_fields(self): + return self.field_name class refbyname(dbmapper): """ @@ -149,7 +186,10 @@ class refbyname(dbmapper): def __call__(self, external_values): v = external_values.get(self.field_name, '') return self.parent.name_exist(self.table, v , self.model) - + + def get_fields(self): + return self.field_name + class call(mapper): """ Use : call(function, arg1, arg2) From 92e50892f84c909a42388896ef325bec1c61bd31 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Thu, 12 May 2016 20:09:06 +0200 Subject: [PATCH 09/10] [FIX] list price import --- beesdoo_migration_asbl_to_coop/migration.py | 1 + import_base/mapper.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/beesdoo_migration_asbl_to_coop/migration.py b/beesdoo_migration_asbl_to_coop/migration.py index 2593fe2..989735e 100644 --- a/beesdoo_migration_asbl_to_coop/migration.py +++ b/beesdoo_migration_asbl_to_coop/migration.py @@ -202,6 +202,7 @@ class migration_framework(import_framework): 'uom_id/id' : 'uom_id/id', 'uom_po_id/id' : 'uom_po_id/id', 'weight' : 'weight', + 'list_price' : 'list_price', } }, 'product.supplierinfo': { diff --git a/import_base/mapper.py b/import_base/mapper.py index 9f034a5..e17a423 100644 --- a/import_base/mapper.py +++ b/import_base/mapper.py @@ -148,9 +148,7 @@ class map_val_default(mapper): self.map = map def __call__(self, external_values): - print self.val(external_values) value = self.map.get(self.val(external_values), self.val(external_values)) - print value return value def get_fields(self): From 521bc4357f3da70ed684888ac031c3baa0fd2c91 Mon Sep 17 00:00:00 2001 From: Thibault Francois Date: Thu, 12 May 2016 23:31:02 +0200 Subject: [PATCH 10/10] [FIX] last solution for taxes import --- beesdoo_migration_asbl_to_coop/migration.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/beesdoo_migration_asbl_to_coop/migration.py b/beesdoo_migration_asbl_to_coop/migration.py index 989735e..112b755 100644 --- a/beesdoo_migration_asbl_to_coop/migration.py +++ b/beesdoo_migration_asbl_to_coop/migration.py @@ -79,13 +79,6 @@ class migration_framework(import_framework): To be used to avoid duplication of data that don't have ids """ return name - - taxes_mapping = { - '5.5% Marchandise' : '6% Marchandises', - '6% Marchandise' : '6% Marchandises', - '21% Services incluse' : '21% Services', - } - def get_mapping(self): return { @@ -195,8 +188,8 @@ class migration_framework(import_framework): 'sale_delay' : 'sale_delay', 'sale_ok' : 'sale_ok', 'standard_price' : 'standard_price', - 'supplier_taxes_id' : map_val_default('supplier_taxes_id', self.taxes_mapping), #Taxes problème - 'taxes_id' : map_val_default('taxes_id', self.taxes_mapping), + 'supplier_taxes_id/id' : 'supplier_taxes_id/id', #Taxes problème + 'taxes_id/id' : 'taxes_id/id', 'to_weight' : 'to_weight', 'type' : 'type', 'uom_id/id' : 'uom_id/id',