diff --git a/addons/event/migrations/8.0.0.1/openupgrade_analysis_work.txt b/addons/event/migrations/8.0.0.1/openupgrade_analysis_work.txt new file mode 100644 index 000000000000..f899c9bca0b7 --- /dev/null +++ b/addons/event/migrations/8.0.0.1/openupgrade_analysis_work.txt @@ -0,0 +1,53 @@ +---Fields in module 'event'--- +event / event.event / date_tz (selection) : NEW selection_keys: function +event / event.event / description (html) : NEW +# Converted 'note' value to HTML + +event / event.event / main_speaker_id (many2one) : DEL relation: res.partner +event / event.event / message_last_post (datetime) : NEW +# Used set_message_last_post() + +event / event.event / note (text) : DEL +# Fields argument 'oldname' used, now points to 'description' field + +event / event.event / organizer_id (many2one) : NEW relation: res.partner +event / event.event / register_max (integer) : DEL +# Fields argument 'oldname' used, now points to 'seats_max' field + +event / event.event / register_min (integer) : DEL +# Fields argument 'oldname' used, now points to 'seats_min' field + +event / event.event / seats_max (integer) : NEW +event / event.event / seats_min (integer) : NEW +event / event.event / speaker_confirmed (boolean) : DEL +event / event.registration / message_last_post (datetime) : NEW +# Used set_message_last_post() + +event / report.event.registration / event_date (char) : type is now 'datetime' ('char') +event / report.event.registration / month (selection) : DEL selection_keys: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] +event / report.event.registration / register_max (integer) : DEL +event / report.event.registration / seats_max (integer) : NEW +event / report.event.registration / speaker_id (many2one) : DEL relation: res.partner +event / report.event.registration / year (char) : DEL +event / res.partner / event_ids (one2many) : DEL relation: event.event +event / res.partner / event_registration_ids (one2many): DEL relation: event.registration +---XML records in module 'event'--- +DEL ir.actions.act_window: event.act_event_reg +DEL ir.actions.act_window: event.act_event_view +DEL ir.actions.act_window: event.act_event_view_registration +DEL ir.actions.act_window: event.open_board_associations_manager +DEL ir.actions.act_window.view: event.action_report_event_registration_tree +NEW ir.rule: event.event_event_company_rule +NEW ir.rule: event.event_registration_company_rule +NEW ir.rule: event.report_event_registration_company_rule +DEL ir.rule: event.event_event_comp_rule +DEL ir.rule: event.event_registration_comp_rule +DEL ir.rule: event.report_event_registration_comp_rule +NEW ir.ui.menu: event.event_configuration +DEL ir.ui.menu: base.menu_event_main +DEL ir.ui.menu: event.menu_board_associations_manager +NEW ir.ui.view: event.assets_backend +DEL ir.ui.view: event.board_associations_manager_form +DEL ir.ui.view: event.report_event_registration_tree +DEL ir.ui.view: event.view_report_event_reg_graph +# Nothing to do diff --git a/addons/event/migrations/8.0.0.1/post-migration.py b/addons/event/migrations/8.0.0.1/post-migration.py new file mode 100644 index 000000000000..b6a09cad0f36 --- /dev/null +++ b/addons/event/migrations/8.0.0.1/post-migration.py @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2014 HBEE (http://www.hbee.eu) +# @author: Paulius Sladkevičius +# +# 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 pooler, SUPERUSER_ID +from openerp.openupgrade.openupgrade import migrate, convert_field_to_html +from openerp.openupgrade.openupgrade_80 import set_message_last_post + + +@migrate() +def migrate(cr, version): + pool = pooler.get_pool(cr.dbname) + set_message_last_post( + cr, SUPERUSER_ID, pool, ['event.event', 'event.registration']) + convert_field_to_html(cr, 'event_event', 'note', 'description') diff --git a/addons/mrp/migrations/8.0.1.1/post-migrate.py b/addons/mrp/migrations/8.0.1.1/post-migrate.py new file mode 100644 index 000000000000..d8e1cd22b2c4 --- /dev/null +++ b/addons/mrp/migrations/8.0.1.1/post-migrate.py @@ -0,0 +1,18 @@ +from openerp.openupgrade import openupgrade +from openerp import pooler, SUPERUSER_ID + +def move_fields(cr, pool): + execute = openupgrade.logged_query + queries = [ """ + UPDATE product_product + SET produce_delay=(SELECT pt.%s + FROM product_template + WHERE product_template.id=product_product.product_tmpl_id) + """ % openupgrade.get_legacy_name('produce_delay'), + + +@openupgrade.migrate() +def migrate(cr, version): + pool = pooler.get_pool(cr.dbname) + move_fields(cr, pool) + diff --git a/addons/product/__openerp__.py b/addons/product/__openerp__.py index 83ecea958869..469941620e1a 100644 --- a/addons/product/__openerp__.py +++ b/addons/product/__openerp__.py @@ -25,7 +25,7 @@ 'version': '1.1', 'author': 'OpenERP SA', 'category': 'Sales Management', - 'depends': ['base', 'decimal_precision', 'mail'], + 'depends': ['base', 'decimal_precision', 'mail', 'report'], 'demo': [ 'product_demo.xml', 'product_image_demo.xml', diff --git a/addons/product/migrations/8.0.1.1/modified_data.xml b/addons/product/migrations/8.0.1.1/modified_data.xml new file mode 100644 index 000000000000..144955bcda48 --- /dev/null +++ b/addons/product/migrations/8.0.1.1/modified_data.xml @@ -0,0 +1,24 @@ + + + + ['|',('company_id','=',False),('company_id','=',user.company_id.id)] + + ['|',('company_id','=',user.company_id.id),('company_id','=',False)] + + + + 1000 + + All + + ['|',('company_id','=',user.company_id.id),('company_id','=',False)] + + ['|',('company_id','=',user.company_id.id),('company_id','=',False)] + + ['|',('company_id','=',user.company_id.id),('company_id','=',False)] + + + + + + diff --git a/addons/product/migrations/8.0.1.1/openupgrade_analysis_WORK.txt b/addons/product/migrations/8.0.1.1/openupgrade_analysis_WORK.txt new file mode 100644 index 000000000000..bbde7e6407e6 --- /dev/null +++ b/addons/product/migrations/8.0.1.1/openupgrade_analysis_WORK.txt @@ -0,0 +1,163 @@ +---Fields in module 'product'--- +product / product.attribute / name (char) : NEW required: required +product / product.attribute / value_ids (one2many) : NEW relation: product.attribute.value +product / product.attribute.line / attribute_id (many2one) : NEW relation: product.attribute, required: required +product / product.attribute.line / product_tmpl_id (many2one) : NEW relation: product.template, required: required +product / product.attribute.line / value_ids (many2many) : NEW relation: product.attribute.value +product / product.attribute.price / price_extra (float) : NEW +product / product.attribute.price / product_tmpl_id (many2one) : NEW relation: product.template, required: required +product / product.attribute.price / value_id (many2one) : NEW relation: product.attribute.value, required: required +product / product.attribute.value / attribute_id (many2one) : NEW relation: product.attribute, required: required +product / product.attribute.value / name (char) : NEW required: required +product / product.attribute.value / price_ids (one2many) : NEW relation: product.attribute.price +product / product.attribute.value / product_ids (many2many) : NEW relation: product.product +product / product.attribute.value / sequence (integer) : NEW + +## OK new model, will be handled by standard migration + + +product / product.packaging / ul_container (many2one) : NEW relation: product.ul +product / product.packaging / height (float) : DEL +product / product.ul / height (float) : NEW +product / product.packaging / length (float) : DEL +product / product.ul / length (float) : NEW +product / product.packaging / weight_ul (float) : DEL +product / product.ul / weight (float) : NEW +product / product.packaging / width (float) : DEL +product / product.ul / width (float) : NEW +## OK new relation ul_container handled by migration +## OK the dimensions are weight must be moved to the related UL (through the ul field) + + +product / product.price.history / company_id (many2one) : NEW relation: res.company, required: required, req_default: function +product / product.price.history / cost (float) : NEW +product / product.price.history / datetime (datetime) : NEW +product / product.price.history / product_template_id (many2one): NEW relation: product.template, required: required +# OK new fields -> nothing to do + +product / product.template / attribute_line_ids (one2many) : NEW relation: product.attribute.line +product / product.product / attribute_value_ids (many2many): NEW relation: product.attribute.value +# OK nothing to do + + +product / product.supplierinfo / product_id (many2one) : DEL relation: product.template, required: required +product / product.supplierinfo / product_tmpl_id (many2one) : NEW relation: product.template, required: required +# OK seller_ids moved from product.product to product.template + +product / product.template / active (boolean) : NEW +# OK: set to True if at least one variant is active + +product / product.template / color (integer) : NEW +product / product.product / color (integer) : DEL +## OK color moved up in template + +product / product.template / cost_method (selection) : module is now 'stock_account' ('product') +product / product.template / cost_method (selection) : now a function +product / product.template / cost_method (selection) : selection_keys is now '['average', 'real', 'standard']' ('['average', 'standard']') +# moved in stock_account, now a fields.property + +product / product.template / image (binary) : NEW +product / product.product / image (binary) : now afunction +# OK need to move up to template + +product / product.product / image_variant (binary) : NEW +# nothing to do + +product / product.template / message_ids (one2many) : NEW relation: mail.message +product / product.template / message_last_post (datetime) : NEW +# now product.template derives from mail template +# TODO : move up messages -> they will still be on the product so why bother +product / product.product / message_last_post (datetime) : NEW + + +product / product.template / packaging (one2many) : NEW relation: product.packaging +# OK moved from product.product + +product / product.template / produce_delay (float) : DEL +# OK moved in mrp, defined on product.product + +product / product.template / product_variant_ids (one2many): NEW relation: product.product, required: required +# nothing to do? + +product / product.template / standard_price (float) : now a function +# OK. Now a fields.property, properties needs to be created + +product / product.product / incoming_qty (float) : module is now 'stock' ('product') +product / product.product / outgoing_qty (float) : module is now 'stock' ('product') +# function fields nothing to do + +product / product.product / price_extra (float) : now a function +# OK moved to 'product.attribute.price', needs to create attributes + +product / product.product / price_margin (float) : DEL +# no longer exists! + +product / product.product / qty_available (float) : module is now 'stock' ('product') +# function field nothing to do + +product / product.product / variants (char) : DEL +# OK moved to 'product.attribute.value', needs to create attributes + +product / product.product / virtual_available (float) : module is now 'stock' ('product') +# function field nothing to do + + + +---XML records in module 'product'--- +NEW ir.actions.act_window: product.product_template_action +NEW ir.actions.act_window: product.product_variant_action +NEW ir.actions.act_window: product.variants_template_action +DEL ir.actions.act_window: product.product_normal_action_puchased +DEL ir.actions.act_window: product.product_template_action_tree +DEL ir.actions.act_window.view: product.open_view_product_form1 +DEL ir.actions.act_window.view: product.open_view_product_kanban1 +DEL ir.actions.act_window.view: product.open_view_product_tree1 +NEW ir.actions.report.xml: product.action_report_pricelist +DEL ir.actions.report.xml: product.report_product_pricelist +## ir.actions: the doc says we can safely ignore these + +NEW ir.model.access: product.access_product_attribute +NEW ir.model.access: product.access_product_attribute_line +NEW ir.model.access: product.access_product_attribute_line_sale_manager +NEW ir.model.access: product.access_product_attribute_price +NEW ir.model.access: product.access_product_attribute_price_sale_manager +NEW ir.model.access: product.access_product_attribute_sale_manager +NEW ir.model.access: product.access_product_attribute_value +NEW ir.model.access: product.access_product_attribute_value_sale_manager +NEW ir.model.access: product.access_product_price_history_employee +## access rules: let them be for now + + +NEW ir.ui.menu: product.menu_product_template_action +NEW ir.ui.view: product.product_template_form_view_variant_button +NEW ir.ui.view: product.product_template_kanban_view +NEW ir.ui.view: product.product_template_kanban_view_variant_button +NEW ir.ui.view: product.product_template_search_view +NEW ir.ui.view: product.report_pricelist +NEW ir.ui.view: product.variants_template_tree_view +DEL ir.ui.view: product.product_variant_form_view +DEL ir.ui.view: product.product_variant_tree_view +DEL ir.ui.view_sc: product.ir_ui_view_sc_product0 +## ir.ui.* doc says we can ignore + +DEL process.node: product.process_node_product0 +DEL process.node: product.process_node_supplier0 +DEL process.process: product.process_process_productprocess0 +DEL process.transition: product.process_transition_supplierofproduct0 +## process addon removed -> nothing to do + +NEW product.uom: product.product_uom_floz +NEW product.uom: product.product_uom_foot +NEW product.uom: product.product_uom_gal +NEW product.uom: product.product_uom_inch +NEW product.uom: product.product_uom_lb +NEW product.uom: product.product_uom_mile +NEW product.uom: product.product_uom_oz +NEW product.uom: product.product_uom_qt +## great new stuff, std upgrade should work by itself + +DEL res.groups: product.group_costing_method +DEL res.groups: product.group_product_variant +## well... probably nothing to do either... + +## modified no update records listed in modified_data.xml diff --git a/addons/product/migrations/8.0.1.1/post-migration.py b/addons/product/migrations/8.0.1.1/post-migration.py new file mode 100644 index 000000000000..434eee5aace7 --- /dev/null +++ b/addons/product/migrations/8.0.1.1/post-migration.py @@ -0,0 +1,162 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Alexandre Fayolle +# Copyright 2014 Camptocamp 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 . +# +############################################################################## +from itertools import groupby +from operator import itemgetter +from openerp.openupgrade import openupgrade +from openerp import pooler, SUPERUSER_ID + + +def load_data(cr): + openupgrade.load_data(cr, 'product', + 'migrations/8.0.1.1/modified_data.xml', + mode='init') + + +def move_fields(cr, pool): + execute = openupgrade.logged_query + queries = ["UPDATE product_supplierinfo " + "SET product_tmpl_id=(SELECT product_tmpl_id " + " FROM product_product " + " WHERE product_product.id=product_supplierinfo.%s) " % + openupgrade.get_legacy_name('product_id'), + # + "UPDATE product_template as pt " + "SET color=(SELECT pp1.%s " + " FROM product_product as pp1 " + " WHERE pp1.product_tmpl_id=pt.id ORDER BY pp1.id LIMIT 1), " + " image=(SELECT pp2.image_variant " + " FROM product_product as pp2 " + " WHERE pp2.product_tmpl_id=pt.id ORDER BY pp2.id LIMIT 1)" % + openupgrade.get_legacy_name('color') + # + + ] + for sql in queries: + execute(cr, sql) + + +def copy_fields(cr, pool): + product_tmpl = pool['product.template'] + # copy the active field from product to template + ctx = {'active_test': False} + tmpl_ids = product_tmpl.search(cr, SUPERUSER_ID, [], context=ctx) + for template in product_tmpl.browse(cr, SUPERUSER_ID, tmpl_ids, context=ctx): + template.write({'active': any(variant.active + for variant in template.product_variant_ids) + }) + + +def migrate_packaging(cr, pool): + """create 1 product UL for each different product packaging dimension + and link it to the packagings + """ + ul_obj = pool['product.ul'] + execute = openupgrade.logged_query + legacy_columns = dict((key, openupgrade.get_legacy_name(key)) + for key in ('height', 'width', + 'length', 'weight_ul')) + execute(cr, + 'select ul, %(height)s, %(width)s, %(length)s, %(weight_ul)s ' + 'from product_packaging' % legacy_columns) + for ul_id, height, width, length, weight in cr.fetchall(): + ul_obj.write(cr, SUPERUSER_ID, [ul_id], + {'height': height, + 'width': width, + 'length': length, + 'weight': weight, + }) + + +def create_properties(cr, pool): + """ Fields moved to properties (standard_price). + + Write using the ORM so the prices will be written as properties. + """ + template_obj = pool['product.template'] + company_obj = pool['res.company'] + company_ids = company_obj.search(cr, SUPERUSER_ID, []) + sql = ("SELECT id, %s FROM product_template" % + openupgrade.get_legacy_name('standard_price')) + cr.execute(sql) + for template_id, std_price in cr.fetchall(): + for company_id in company_ids: + ctx = {'force_company': company_id} + template_obj.write(cr, SUPERUSER_ID, [template_id], + {'standard_price': std_price}, + context=ctx) + # product.price.history entries have been generated with a value for + # today, we want a value for the past as well, write a bogus date to + # be sure that we have an historic value whenever we want + cr.execute("UPDATE product_price_history SET " + # calling a field 'datetime' is not really a good idea + "datetime = '1970-01-01 00:00:00+00'") + + +def migrate_variants(cr, pool): + template_obj = pool['product.template'] + attribute_obj = pool['product.attribute'] + attribute_value_obj = pool['product.attribute.value'] + attribute_line_obj = pool['product.attribute.line'] + fields = {'variant': openupgrade.get_legacy_name('variants'), + 'price': openupgrade.get_legacy_name('price_extra')} + sql = ("SELECT id, %(variant)s, %(price)s, product_tmpl_id " + "FROM product_product " + "WHERE %(variant)s IS NOT NULL " + "OR %(price)s IS NOT NULL AND %(price)s <> 0" + "ORDER BY product_tmpl_id, id" % fields) + cr.execute(sql) + rows = cr.dictfetchall() + for tmpl_id, variants in groupby(rows, key=itemgetter('product_tmpl_id')): + # create an attribute shared by all the variants + template = template_obj.browse(cr, SUPERUSER_ID, tmpl_id) + attr_id = attribute_obj.create(cr, SUPERUSER_ID, + {'name': template.name}) + for variant in variants: + # create an attribute value for this variant + price_extra = variant[fields['price']] or 0 + name = variant[fields['variant']] + # active_id needed to create the 'product.attribute.price' + ctx = {'active_id': tmpl_id} + values = { + 'name': name or '%.2f' % price_extra, + 'attribute_id': attr_id, + 'product_ids': [(6, 0, [variant['id']])], + # a 'product.attribute.price' is created when we write + # a price_extra on an attribute value + 'price_extra': price_extra, + } + value_id = attribute_value_obj.create(cr, SUPERUSER_ID, values, + context=ctx) + values = {'product_tmpl_id': tmpl_id, + 'attribute_id': attr_id, + 'value_ids': [(6, 0, [value_id])]} + attribute_line_obj.create(cr, SUPERUSER_ID, values) + + +@openupgrade.migrate() +def migrate(cr, version): + pool = pooler.get_pool(cr.dbname) + move_fields(cr, pool) + copy_fields(cr, pool) + migrate_packaging(cr, pool) + create_properties(cr, pool) + migrate_variants(cr, pool) + load_data(cr) diff --git a/addons/product/migrations/8.0.1.1/pre-migration.py b/addons/product/migrations/8.0.1.1/pre-migration.py new file mode 100644 index 000000000000..b064f977114a --- /dev/null +++ b/addons/product/migrations/8.0.1.1/pre-migration.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Alexandre Fayolle +# Copyright 2014 Camptocamp 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 . +# +############################################################################## + +from openerp.openupgrade import openupgrade + +column_renames = { + # Using magic None value to trigger call to get_legacy_name() + 'product_supplierinfo': [ + ('product_id', None), + ], + 'product_product': [ + ('color', None), + ('image', 'image_variant'), + ('variants', None), + ('price_extra', None), + ], + 'product_template': [ + ('produce_delay', None), # need to handle in mrp migration + ('cost_method', None), # need to handle in stock_account migration + ('standard_price', None), + ], + 'product_packaging': [ + ('height', None), + ('length', None), + ('weight_ul', None), + ('width', None), + ] +} + + +@openupgrade.migrate() +def migrate(cr, version): + openupgrade.rename_columns(cr, column_renames) diff --git a/addons/product/product.py b/addons/product/product.py index 2369db49d436..ebf6181290c1 100644 --- a/addons/product/product.py +++ b/addons/product/product.py @@ -344,6 +344,8 @@ def _get_price_extra(self, cr, uid, ids, name, args, context=None): return result def _set_price_extra(self, cr, uid, id, name, value, args, context=None): + if context is None: + context = {} if 'active_id' not in context: return None p_obj = self.pool['product.attribute.price'] @@ -351,7 +353,7 @@ def _set_price_extra(self, cr, uid, id, name, value, args, context=None): if p_ids: p_obj.write(cr, uid, p_ids, {'price_extra': value}, context=context) else: - p_obj.create(cr, uid, p_ids, { + p_obj.create(cr, uid, { 'product_tmpl_id': context['active_id'], 'value_id': id, 'price_extra': value, diff --git a/addons/stock_account/migrations/8.0.1.1/post-migrate.py b/addons/stock_account/migrations/8.0.1.1/post-migrate.py new file mode 100644 index 000000000000..3d64f97ae899 --- /dev/null +++ b/addons/stock_account/migrations/8.0.1.1/post-migrate.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2014 Camptocamp 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 . +# +############################################################################## + +from openerp.openupgrade import openupgrade +from openerp import pooler, SUPERUSER_ID + + +def create_properties(cr, pool): + """ Fields moved to properties (cost_method). + + Write using the ORM so the cost_method will be written as properties. + """ + template_obj = pool['product.template'] + company_obj = pool['res.company'] + company_ids = company_obj.search(cr, SUPERUSER_ID, []) + sql = ("SELECT id, %s FROM product_template" % + openupgrade.get_legacy_name('cost_method')) + cr.execute(sql) + for template_id, cost_method in cr.fetchall(): + for company_id in company_ids: + ctx = {'force_company': company_id} + template_obj.write(cr, SUPERUSER_ID, [template_id], + {'cost_method': cost_method}, + context=ctx) + + +@openupgrade.migrate() +def migrate(cr, version): + pool = pooler.get_pool(cr.dbname) + create_properties(cr, pool) diff --git a/openerp/addons/base/migrations/8.0.1.3/openupgrade_analysis_work.txt b/openerp/addons/base/migrations/8.0.1.3/openupgrade_analysis_work.txt index 02da8b841790..84525ef655d1 100644 --- a/openerp/addons/base/migrations/8.0.1.3/openupgrade_analysis_work.txt +++ b/openerp/addons/base/migrations/8.0.1.3/openupgrade_analysis_work.txt @@ -6,41 +6,65 @@ base / ir.actions.report.xml / parser (char) : NEW base / ir.actions.report.xml / report_type (char) : selection_keys is now '['controller', 'pdf', 'qweb-html', 'qweb-pdf', 'sxw', 'webkit']' ('False') base / ir.actions.report.xml / report_type (char) : type is now 'selection' ('char') -# TODO -base / ir.actions.server / copy_object (reference) : DEL -base / ir.actions.server / copyvalue (char) : NEW -base / ir.actions.server / crud_model_id (many2one) : NEW relation: ir.model -base / ir.actions.server / email (char) : DEL +# For the following ir.actions.server changes, OpenUpgrade won't try to manage the values because: +# - ir.actions.server are generally created by system, (re) loading xml files; +# - ir.actions.server has been fully refunded; +# - when doing test, all the following fields are empty when we install modules. (in 7.0 for DEL fields and in 8.0 for NEW fields) +base / ir.actions.server / loop_action (many2one) : DEL relation: ir.actions.server base / ir.actions.server / expression (char) : DEL +base / ir.actions.server / trigger_name (selection) : DEL selection_keys: function +base / ir.actions.server / copyvalue (char) : NEW base / ir.actions.server / id_object (reference) : NEW base / ir.actions.server / id_value (char) : NEW -base / ir.actions.server / link_field_id (many2one) : NEW relation: ir.model.fields base / ir.actions.server / link_new_record (boolean) : NEW -base / ir.actions.server / loop_action (many2one) : DEL relation: ir.actions.server base / ir.actions.server / menu_ir_values_id (many2one) : NEW relation: ir.values -base / ir.actions.server / message (text) : DEL -base / ir.actions.server / mobile (char) : DEL base / ir.actions.server / model_object_field (many2one) : NEW relation: ir.model.fields -base / ir.actions.server / record_id (many2one) : DEL relation: ir.model.fields -base / ir.actions.server / ref_object (reference) : NEW +base / ir.actions.server / sub_model_object_field (many2one): NEW relation: ir.model.fields +base / ir.actions.server / sub_object (many2one) : NEW relation: ir.model + +# The feature of 'email', 'sms', 'mobile', has been removed. --> Nothing to do. +base / ir.actions.server / email (char) : DEL base / ir.actions.server / sms (char) : DEL +base / ir.actions.server / mobile (char) : DEL +base / ir.actions.server / message (text) : DEL + +# 'srcmodel_id' renamed into 'crud_model_id'. oldname feature is used. --> Nothing to do. base / ir.actions.server / srcmodel_id (many2one) : DEL relation: ir.model +base / ir.actions.server / crud_model_id (many2one) : NEW relation: ir.model +# 'trigger_obj_id' renamed into 'wkf_field_id'. oldname feature is used. --> Nothing to do. +base / ir.actions.server / trigger_obj_id (many2one) : DEL relation: ir.model.fields +base / ir.actions.server / wkf_field_id (many2one) : NEW relation: ir.model.fields +# 'copy_object' renamed into 'ref_object'. oldname feature is used. --> Nothing to do. +base / ir.actions.server / copy_object (reference) : DEL +base / ir.actions.server / ref_object (reference) : NEW +# 'record_id' renamed into 'link_field_id'. oldname feature is used. --> Nothing to do. +base / ir.actions.server / record_id (many2one) : DEL relation: ir.model.fields +base / ir.actions.server / link_field_id (many2one) : NEW relation: ir.model.fields +# 'write_id' renamed into 'write_expression'. oldname feature is used. --> Nothing to do. +base / ir.actions.server / write_id (char) : DEL +base / ir.actions.server / write_expression (char) : NEW + +# 'state' was a selection field and become a selection field defined by a function (_get_states) +# 'dummy', 'email', 'loop', 'object_copy', 'other', 'sms' values has been deleted; +# 'multi' is new. +# OpenUpgrade will test and warn if there is invalid values in this field. calling _get_states in post-migration script--> DONE. base / ir.actions.server / state (selection) : selection_keys is now 'function' ('['client_action', 'code', 'dummy', 'email', 'loop', 'object_copy', 'object_create', 'object_write', 'other', 'sms', 'trigger']') -base / ir.actions.server / sub_model_object_field (many2one): NEW relation: ir.model.fields -base / ir.actions.server / sub_object (many2one) : NEW relation: ir.model + +# Field is move to a upper-level module. We assume that the field will not be used in previous version if 'email_template' is not installed. --> Nothing to do. base / ir.actions.server / subject (char) : module is now 'email_template' ('base') base / ir.actions.server / subject (char) : now a function -base / ir.actions.server / trigger_name (selection) : DEL selection_keys: function -base / ir.actions.server / trigger_obj_id (many2one) : DEL relation: ir.model.fields + +# New feature for ir.actions.server : using default value is OK. --> Nothing to do. base / ir.actions.server / use_create (selection) : NEW required: required, selection_keys: ['copy_current', 'copy_other', 'new', 'new_other'], req_default: new +# New feature for ir.actions.server : using default value is OK. --> Nothing to do. base / ir.actions.server / use_relational_model (selection): NEW required: required, selection_keys: ['base', 'relational'], req_default: base +# New feature for ir.actions.server : using default value is OK. --> Nothing to do. base / ir.actions.server / use_write (selection) : NEW required: required, selection_keys: ['current', 'expression', 'other'], req_default: current -base / ir.actions.server / wkf_field_id (many2one) : NEW relation: ir.model.fields + +# New feature, nothing to do. base / ir.actions.server / wkf_transition_id (many2one) : NEW relation: workflow.transition -base / ir.actions.server / write_expression (char) : NEW -base / ir.actions.server / write_id (char) : DEL -# TODO +# New model 'ir.logging' associated to a new feature. --> Nothing to do. base / ir.logging / create_date (datetime) : NEW base / ir.logging / create_uid (integer) : NEW base / ir.logging / dbname (char) : NEW @@ -52,12 +76,14 @@ base / ir.logging / name (char) : NEW re base / ir.logging / path (char) : NEW required: required base / ir.logging / type (selection) : NEW required: required, selection_keys: ['client', 'server'] -# TODO +# 'view_load' concept has been removed. redundant because the value was true only on properties fields. --> Nothing to do. base / ir.model.fields / view_load (boolean) : DEL -# TODO +# field changed from 'reference' to 'char' but the storage is identical. --> Nothing to do. base / ir.property / res_id (reference) : type is now 'char' ('reference') +# New option. --> Nothing to do. base / ir.property / type (selection) : selection_keys is now '['binary', 'boolean', 'char', 'date', 'datetime', 'float', 'integer', 'many2one', 'selection', 'text']' ('['binary', 'boolean', 'char', 'date', 'datetime', 'float', 'integer', 'many2one', 'text']') +# field changed from 'reference' to 'char' but the storage is identical. --> Nothing to do. base / ir.property / value_reference (reference) : type is now 'char' ('reference') # New feature for ir.ui.view that allow enable or disable inheritance : using default value is OK. --> Nothing to do. @@ -66,18 +92,23 @@ base / ir.ui.view / application (selection) : NEW re base / ir.ui.view / create_date (datetime) : NEW # new one2many field on an existing many2one field (ir_ui_view.inherit_id). --> Nothing to do. base / ir.ui.view / inherit_children_ids (one2many): NEW relation: ir.ui.view +# New feature for ir.ui.view : using default value is OK. --> Nothing to do. base / ir.ui.view / mode (selection) : NEW required: required, selection_keys: ['extension', 'primary'], req_default: primary # new one2many field on an existing many2one field (ir_model_data.res_id). --> Nothing to do. base / ir.ui.view / model_ids (one2many) : NEW relation: ir.model.data +# function -> selection. Nothing to do. base / ir.ui.view / type (selection) : not a function anymore +# removed value : 'mdx'. unused in addons. OpenUpgrade will test if extra-addons doesnt use this value. Done. +# new value : 'qweb'. --> Nothing to do. base / ir.ui.view / type (selection) : selection_keys is now '['calendar', 'diagram', 'form', 'gantt', 'graph', 'kanban', 'qweb', 'search', 'tree']' ('['calendar', 'diagram', 'form', 'gantt', 'graph', 'kanban', 'mdx', 'search', 'tree']') # 'write_date' was already present in V7 but not in the model. --> Nothing to do. base / ir.ui.view / write_date (datetime) : NEW + # New feature: using default value is OK. --> Nothing to do. base / res.company / font (many2one) : NEW relation: res.font -# 'paper_format' renamed into 'rml_paper_format'. --> DONE. +# 'paper_format' renamed into 'rml_paper_format'. oldname feature is used. --> Nothing to do. base / res.company / paper_format (selection) : DEL required: required, selection_keys: ['a4', 'us_letter'], req_default: a4 base / res.company / rml_paper_format (selection) : NEW required: required, selection_keys: ['a4', 'us_letter'], req_default: a4 @@ -96,7 +127,7 @@ base / res.font / path (char) : NEW re # The feature has been removed. It gaves the possibility to a user to have a different menu as the default one. --> Nothing to do. base / res.users / menu_id (many2one) : DEL relation: ir.actions.actions -# TODO +# This field is new in the model but not in Database. It was created by the 7.0 script in server/openerp/addons/base/base.sql .--> Nothing to do. base / workflow.instance / transition_ids (many2many) : NEW relation: workflow.transition diff --git a/openerp/addons/base/migrations/8.0.1.3/post-migration.py b/openerp/addons/base/migrations/8.0.1.3/post-migration.py new file mode 100644 index 000000000000..3c1f0e7634b1 --- /dev/null +++ b/openerp/addons/base/migrations/8.0.1.3/post-migration.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenUpgrade module for Odoo +# @copyright 2014-Today: Odoo Community Association +# @author: Sylvain LE GAL +# +# 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 logging +from openerp import pooler, SUPERUSER_ID +from openerp.openupgrade import openupgrade +logger = logging.getLogger('OpenUpgrade') + + +def check_ir_actions_server_state(cr, pool): + """Test if 'state' values are correct. + If not, log an error to indicate that the user has to overload _get_state + function in his custom modules.""" + ias_obj = pool['ir.actions.server'] + valid_selection = ias_obj._get_states(cr, SUPERUSER_ID) + valid_list = [x[0] for x in valid_selection] + ias_ids = ias_obj.search( + cr, SUPERUSER_ID, [('state', 'not in', valid_list)]) + for ias in ias_obj.browse(cr, SUPERUSER_ID, ias_ids): + logger.error( + "Invalid value '%s' in the model 'ir_actions_server' " + "for the field 'state'. (id %s).Please overload the new " + "ir_actions_server._get_state function." % ( + ias.state, ias.id)) + + +@openupgrade.migrate() +def migrate(cr, version): + pool = pooler.get_pool(cr.dbname) + check_ir_actions_server_state(cr, pool) diff --git a/openerp/addons/base/migrations/8.0.1.3/pre-migration.py b/openerp/addons/base/migrations/8.0.1.3/pre-migration.py index 71eac3855ac1..98441506359c 100644 --- a/openerp/addons/base/migrations/8.0.1.3/pre-migration.py +++ b/openerp/addons/base/migrations/8.0.1.3/pre-migration.py @@ -22,16 +22,13 @@ from openerp.openupgrade import openupgrade -column_renames = { - 'res_company': [ - ('paper_format', 'rml_paper_format'), - ] -} - @openupgrade.migrate() def migrate(cr, version): openupgrade.check_values_selection_field( cr, 'ir_act_report_xml', 'report_type', ['controller', 'pdf', 'qweb-html', 'qweb-pdf', 'sxw', 'webkit']) - openupgrade.rename_columns(cr, column_renames) + openupgrade.check_values_selection_field( + cr, 'ir_ui_view', 'type', [ + 'calendar', 'diagram', 'form', 'gantt', 'graph', 'kanban', + 'qweb', 'search', 'tree']) diff --git a/openerp/addons/openupgrade_records/lib/compare.py b/openerp/addons/openupgrade_records/lib/compare.py index f52f08cb6b73..ef8a44e55b3a 100644 --- a/openerp/addons/openupgrade_records/lib/compare.py +++ b/openerp/addons/openupgrade_records/lib/compare.py @@ -240,7 +240,7 @@ def compare_xml_sets(old_records, new_records): sorted_records = sorted( old_records + new_records, - key=lambda k: '%-128s%s%s' % (k['model'], 'old' in k, k['name']) + key=lambda k: (k['model'], 'old' in k, k['name']) ) for entry in sorted_records: if 'old' in entry: diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index 82fb0b13a60a..892025b3e3a4 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -166,6 +166,8 @@ def _load_data(cr, module_name, idref, mode, kind): # OpenUpgrade: add this module's models to the registry local_registry = {} for model in models: + if not model._auto: + continue openupgrade_loading.log_model(model, local_registry) openupgrade_loading.compare_registries( cr, package.name, upg_registry, local_registry) diff --git a/openerp/modules/migration.py b/openerp/modules/migration.py index ad67df966599..9aef265b7865 100644 --- a/openerp/modules/migration.py +++ b/openerp/modules/migration.py @@ -157,17 +157,14 @@ def mergedict(a, b): name, ext = os.path.splitext(os.path.basename(pyfile)) if ext.lower() != '.py': continue - mod = fp = fp2 = None + # OpenUpgrade edit start: + # Removed a copy of migration script to temp directory + # Replaced call to load_source with load_module so frame isn't lost and breakpoints can be set + mod = fp = None try: - fp = tools.file_open(pyfile) - - # imp.load_source need a real file object, so we create - # one from the file-like object we get from file_open - fp2 = os.tmpfile() - fp2.write(fp.read()) - fp2.seek(0) + fp, pathname = tools.file_open(pyfile, pathinfo=True) try: - mod = imp.load_source(name, pyfile, fp2) + mod = imp.load_module(name, fp, pathname, ('.py', 'r', imp.PY_SOURCE)) _logger.info('module %(addon)s: Running migration %(version)s %(name)s', mergedict({'name': mod.__name__}, strfmt)) except ImportError: @@ -186,10 +183,9 @@ def mergedict(a, b): finally: if fp: fp.close() - if fp2: - fp2.close() if mod: del mod + # OpenUpgrade edit end # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/openupgrade/doc/source/migrate.py.rst b/openerp/openupgrade/doc/source/migrate.py.rst index a2e7425ea7fe..5d07b7f388b5 100644 --- a/openerp/openupgrade/doc/source/migrate.py.rst +++ b/openerp/openupgrade/doc/source/migrate.py.rst @@ -9,7 +9,7 @@ migrate.py that takes care of downloading the necessary branches, set up a configuration for the migration and passing the correct parameters to the OpenUpgrade server. -Download it from launchpad_. +Download it from github_. It accepts a couple of parameters, the mandatory ones are @@ -52,7 +52,7 @@ In a nutshell :: - bzr cat lp:openupgrade-server/scripts/migrate.py > migrate.py + wget https://raw.githubusercontent.com/OpenUpgrade/OpenUpgrade/HEAD/scripts/migrate.py python migrate.py --config=[your openerp.conf] --database=[your database] --run-migrations=[your migrations] -.. _launchpad: http://bazaar.launchpad.net/~openupgrade-committers/openupgrade-server/7.0/view/head:/scripts/migrate.py +.. _github: https://github.com/OpenUpgrade/OpenUpgrade/blob/8.0/scripts/migrate.py diff --git a/openerp/openupgrade/doc/source/modules70-80.rst b/openerp/openupgrade/doc/source/modules70-80.rst index 3cd4968ba5c4..f4ec69eb3320 100644 --- a/openerp/openupgrade/doc/source/modules70-80.rst +++ b/openerp/openupgrade/doc/source/modules70-80.rst @@ -72,7 +72,7 @@ Status : +-----------------------------------+-----------------------------------+ |auth_signup | Nothing to do | +-----------------------------------+-----------------------------------+ -|base | | +|base | Done | +-----------------------------------+-----------------------------------+ |base_action_rule | | +-----------------------------------+-----------------------------------+ @@ -122,7 +122,7 @@ Status : +-----------------------------------+-----------------------------------+ |email_template | Done | +-----------------------------------+-----------------------------------+ -|event | | +|event |Done | +-----------------------------------+-----------------------------------+ |event_sale | | +-----------------------------------+-----------------------------------+ diff --git a/openerp/openupgrade/openupgrade.py b/openerp/openupgrade/openupgrade.py index c33bf3d8737f..51d26a08081c 100644 --- a/openerp/openupgrade/openupgrade.py +++ b/openerp/openupgrade/openupgrade.py @@ -24,6 +24,7 @@ import logging from openerp import release, tools, SUPERUSER_ID from openerp.osv import orm +from openerp.tools.mail import plaintext2html import openupgrade_tools # The server log level has not been set at this point @@ -54,6 +55,7 @@ 'm2o_to_m2m', 'float_to_integer', 'message', + 'convert_field_to_html', 'check_values_selection_field', ] @@ -581,3 +583,22 @@ def wrapped_function(cr, version): raise return wrapped_function return wrap + + +def convert_field_to_html(cr, table, field_name, html_field_name): + """ + Convert field value to HTML value. + """ + cr.execute( + "SELECT id, %(field)s FROM %(table)s WHERE %(field)s IS NOT NULL" % { + 'field': field_name, + 'table': table, + } + ) + for row in cr.fetchall(): + logged_query( + cr, "UPDATE %(table)s SET %(field)s = %s WHERE id = %s" % { + 'field': html_field_name, + 'table': table, + }, (plaintext2html(row[1]), row[0]) + ) diff --git a/scripts/migrate.py b/scripts/migrate.py old mode 100644 new mode 100755 index 3c107737644c..98a7a0e08f48 --- a/scripts/migrate.py +++ b/scripts/migrate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python2 import os import sys @@ -7,10 +7,31 @@ import psycopg2.extensions from optparse import OptionParser from ConfigParser import SafeConfigParser -import bzrlib.plugin -import bzrlib.builtins +try: + import bzrlib.plugin + import bzrlib.builtins +except ImportError: + print ('couldn\'t import bzrlib. You won\'t be able to run migrations ' + '<= 7.0!') migrations = { + '8.0': { + 'addons': { + 'addons': { + 'type': 'link', + 'url': os.path.join('server', 'addons'), + }, + }, + 'server': { + 'type': 'git', + 'url': 'git://github.com/OpenUpgrade/OpenUpgrade.git', + 'branch': '8.0', + 'addons_dir': os.path.join('openerp', 'addons'), + 'root_dir': os.path.join(''), + 'cmd': 'openerp-server --update=all --database=%(db)s ' + '--config=%(config)s --stop-after-init --no-xmlrpc', + }, + }, '7.0': { 'addons': { 'addons': 'lp:openupgrade-addons/7.0', @@ -169,46 +190,71 @@ def deep_update(dict1, dict2): for version in options.migrations.split(','): if not os.path.exists(os.path.join(options.branch_dir, version)): os.mkdir(os.path.join(options.branch_dir, version)) - for (name, url) in dict( + for (name, addon_config) in dict( migrations[version]['addons'], - server=migrations[version]['server']['url']).iteritems(): - link = url.get('link', False) if isinstance(url, dict) else False - url = url['url'] if isinstance(url, dict) else url + server=migrations[version]['server']).iteritems(): + addon_config = addon_config\ + if isinstance(addon_config, dict)\ + else {'url': addon_config} + addon_config_type = addon_config.get('type', 'bzr') if os.path.exists(os.path.join(options.branch_dir, version, name)): - if link: + if addon_config_type == 'link': continue - cmd_revno = bzrlib.builtins.cmd_revno() - cmd_revno.outf = StringIO.StringIO() - cmd_revno.run(location=os.path.join(options.branch_dir, - version, - name)) - print 'updating %s rev%s' % ( - os.path.join(version, name), - cmd_revno.outf.getvalue().strip()) - cmd_update = bzrlib.builtins.cmd_update() - cmd_update.outf = StringIO.StringIO() - cmd_update.outf.encoding = 'utf8' - cmd_update.run( - dir=os.path.join(options.branch_dir, version, name)) - if hasattr(cmd_update, '_operation'): - cmd_update.cleanup_now() - print 'now at rev' + cmd_revno.outf.getvalue().strip() + elif addon_config_type == 'bzr': + cmd_revno = bzrlib.builtins.cmd_revno() + cmd_revno.outf = StringIO.StringIO() + cmd_revno.run(location=os.path.join(options.branch_dir, + version, + name)) + print 'updating %s rev%s' % ( + os.path.join(version, name), + cmd_revno.outf.getvalue().strip()) + cmd_update = bzrlib.builtins.cmd_update() + cmd_update.outf = StringIO.StringIO() + cmd_update.outf.encoding = 'utf8' + cmd_update.run( + dir=os.path.join(options.branch_dir, version, name)) + if hasattr(cmd_update, '_operation'): + cmd_update.cleanup_now() + print 'now at rev' + cmd_revno.outf.getvalue().strip() + elif addon_config_type == 'git': + os.system('cd %(location)s; git pull origin %(branch)s' % { + 'branch': addon_config.get('branch', 'master'), + 'location': os.path.join(options.branch_dir, + version, + name), + }) + else: + raise Exception('Unknown type %s' % addon_config_type) else: - if link: - print 'linking %s to %s' % (url, + if addon_config_type == 'link': + print 'linking %s to %s' % (addon_config['url'], os.path.join(options.branch_dir, version, name)) - os.symlink(url, + os.symlink(addon_config['url'], os.path.join(options.branch_dir, version, name)) - else: - print 'getting ' + url + elif addon_config_type == 'bzr': + print 'getting ' + addon_config['url'] cmd_checkout = bzrlib.builtins.cmd_checkout() cmd_checkout.outf = StringIO.StringIO() cmd_checkout.run( - url, + addon_config['url'], os.path.join(options.branch_dir, version, name), lightweight=True) + elif addon_config_type == 'git': + print 'getting ' + addon_config['url'] + os.system('git clone --branch %(branch)s --single-branch ' + '--depth=1 %(url)s %(target)s' % + { + 'branch': addon_config.get('branch', 'master'), + 'url': addon_config['url'], + 'target': os.path.join(options.branch_dir, + version, + name), + }) + else: + raise Exception('Unknown type %s' % addon_config_type) if not options.inplace: print('copying database %(db_name)s to %(db)s...' % {'db_name': db_name,