Skip to content

Commit

Permalink
Merge pull request #37 from guewen/product-v8-migration
Browse files Browse the repository at this point in the history
[ADD] Product v8 migration
  • Loading branch information
Stefan Rijnhart committed Jun 4, 2014
2 parents 3569cb1 + ee91d78 commit 47113c6
Show file tree
Hide file tree
Showing 8 changed files with 470 additions and 2 deletions.
18 changes: 18 additions & 0 deletions addons/mrp/migrations/8.0.1.1/post-migrate.py
Original file line number Diff line number Diff line change
@@ -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)

2 changes: 1 addition & 1 deletion addons/product/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
24 changes: 24 additions & 0 deletions addons/product/migrations/8.0.1.1/modified_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version='1.0' encoding='utf-8'?>
<openerp>
<data>
<record id="product_supplierinfo_comp_rule" model="ir.rule"><field name="domain_force">['|',('company_id','=',False),('company_id','=',user.company_id.id)]</field>
</record>
<record id="product_pricelist_comp_rule" model="ir.rule"><field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
</record>
<record id="product_uom_kgm" model="product.uom"><field name="rounding" eval="0.001"/>
</record>
<record id="item0" model="product.pricelist.item"><field name="sequence">1000</field>
</record>
<record id="product_category_all" model="product.category"><field name="name">All</field>
</record>
<record id="product_pricelist_version_comp_rule" model="ir.rule"><field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
</record>
<record id="product_pricelist_item_comp_rule" model="ir.rule"><field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
</record>
<record id="product_comp_rule" model="ir.rule"><field name="domain_force"> ['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
</record>
<record id="product_product_consultant" model="product.product"><field name="sale_ok" eval="False"/>
</record>
</data>
</openerp>

163 changes: 163 additions & 0 deletions addons/product/migrations/8.0.1.1/openupgrade_analysis_WORK.txt
Original file line number Diff line number Diff line change
@@ -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
162 changes: 162 additions & 0 deletions addons/product/migrations/8.0.1.1/post-migration.py
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
#
##############################################################################
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)
Loading

0 comments on commit 47113c6

Please sign in to comment.