def migrate_stock_qty(cr, registry): """Reprocess stock moves in done state to fill stock.quant.""" # First set restrict_lot_id so that quants point to correct moves sql = ''' UPDATE stock_move SET restrict_lot_id = {} '''.format(openupgrade.get_legacy_name('prodlot_id')) openupgrade.logged_query(cr, sql) with api.Environment.manage(): env = api.Environment(cr, SUPERUSER_ID, {}) done_moves = env['stock.move'].search( [('state', '=', 'done')], order="date") openupgrade.message( cr, 'stock', 'stock_move', 'state', 'Reprocess %s stock moves in state done to fill stock.quant', len(done_moves.ids)) done_moves.write({'state': 'draft'}) # disable all workflow steps - massive performance boost, no side # effects of workflow transitions with yet unknown condition set_workflow_org = models.BaseModel.step_workflow models.BaseModel.step_workflow = lambda *args, **kwargs: None # Process moves using action_done. for move in done_moves: date_done = move.date move.action_done() # Rewrite date to keep old data move.date = date_done # Assign the same date for the created quants (not the existing) quants_to_rewrite = move.quant_ids.filtered( lambda x: x.in_date > date_done) quants_to_rewrite.write({'in_date': date_done}) models.BaseModel.step_workflow = set_workflow_org
def migrate_stock_location(cr, registry): """Create a Push rule for each pair of locations linked. Will break if there are multiple warehouses for the same company.""" path_obj = registry['stock.location.path'] location_obj = registry['stock.location'] warehouse_obj = registry['stock.warehouse'] head_sql = """SELECT id, %s, %s, %s, %s, name, %s FROM stock_location""" % ( openupgrade.get_legacy_name('chained_location_id'), openupgrade.get_legacy_name('chained_auto_packing'), openupgrade.get_legacy_name('chained_company_id'), openupgrade.get_legacy_name('chained_delay'), openupgrade.get_legacy_name('chained_picking_type')) tail_sql = """ WHERE %s = 'fixed'""" % ( openupgrade.get_legacy_name('chained_location_type')) cr.execute(head_sql + tail_sql) for location in cr.fetchall(): loc = location_obj.browse(cr, uid, location[1]) loc_from = location_obj.browse(cr, uid, location[0]) name = '{} -> {}'.format(location[5], loc.name) vals = { 'active': True, 'propagate': True, 'location_from_id': location[0], 'location_dest_id': location[1], 'auto': location[2], 'company_id': location[3], 'delay': location[4], 'name': name, } company_id = location[3] or loc.company_id.id or loc_from.company_id.id args = company_id and [('company_id', '=', company_id)] or [] warehouse_ids = warehouse_obj.search(cr, uid, args) if not warehouse_ids: warehouse_ids = [ registry['ir.model.data'].xmlid_to_res_id( cr, uid, 'stock.warehouse0', raise_if_not_found=True) ] openupgrade.message( cr, 'stock', 'stock_location_path', 'warehouse_id', 'No warehouse found for company #%s, but this company does ' 'have chained pickings. Taking the default warehouse.', company_id) vals['warehouse_id'] = warehouse_ids[0] warehouse = warehouse_obj.browse(cr, uid, vals['warehouse_id']) if len(warehouse_ids) > 1: openupgrade.message( cr, 'stock', 'stock_location_path', 'warehouse_id', 'Multiple warehouses found for location path %s. Taking ' '%s. Please verify this setting.', name, warehouse.name) if location[6] == 'in': vals['picking_type_id'] = warehouse.in_type_id.id elif location[6] == 'out': vals['picking_type_id'] = warehouse.out_type_id.id else: vals['picking_type_id'] = warehouse.int_type_id.id path_obj.create(cr, uid, vals)
def migrate_stock_qty(cr, registry): """Reprocess stock moves in done state to fill stock.quant.""" # First set restrict_lot_id so that quants point to correct moves sql = ''' UPDATE stock_move SET restrict_lot_id = {} '''.format(openupgrade.get_legacy_name('prodlot_id')) openupgrade.logged_query(cr, sql) with api.Environment.manage(): env = api.Environment(cr, SUPERUSER_ID, {}) done_moves = env['stock.move'].search([('state', '=', 'done')], order="date") openupgrade.message( cr, 'stock', 'stock_move', 'state', 'Reprocess %s stock moves in state done to fill stock.quant', len(done_moves.ids)) done_moves.write({'state': 'draft'}) # Process moves using action_done. for move in done_moves: date_done = move.date move.action_done() # Rewrite date to keep old data move.date = date_done # Assign the same date for the created quants (not the existing) quants_to_rewrite = move.quant_ids.filtered( lambda x: x.in_date > date_done) quants_to_rewrite.write({'in_date': date_done})
def migrate_stock_qty(cr, registry): """Reprocess stock moves in state done to fill stock.quant.""" stock_move_obj = registry['stock.move'] done_move_ids = stock_move_obj.search(cr, uid, [('state', '=', 'done')]) openupgrade.message( cr, 'stock', 'stock_move', 'state', 'Reprocess %s stock moves in state done to fill stock.quant', len(done_move_ids)) stock_move_obj.write(cr, uid, done_move_ids, {'state': 'draft'}) # Process moves using action_done. stock_move_obj.action_done(cr, uid, done_move_ids, context=None)
def migrate_stock_picking(cr, registry): """Update picking records with the correct picking_type_id and state. As elsewhere, multiple warehouses with the same company pose a problem. """ warehouse_obj = registry['stock.warehouse'] company_obj = registry['res.company'] picking_obj = registry['stock.picking'] type_legacy = openupgrade.get_legacy_name('type') for company in company_obj.browse(cr, uid, company_obj.search(cr, uid, [])): warehouse_ids = warehouse_obj.search(cr, uid, [('company_id', '=', company.id)]) if not warehouse_ids: picking_ids = picking_obj.search(cr, uid, [('company_id', '=', company.id)]) if not picking_ids: continue warehouse_ids = [ registry['ir.model.data'].xmlid_to_res_id( cr, uid, 'stock.warehouse0', raise_if_not_found=True) ] openupgrade.message( cr, 'stock', 'stock_picking', 'picking_type_id', 'No warehouse found for company %s, but this company does ' 'have pickings. Taking the default warehouse.', company.name) warehouse = warehouse_obj.browse(cr, uid, warehouse_ids[0]) if len(warehouse_ids) > 1: openupgrade.message( cr, 'stock', 'stock_picking', 'picking_type_id', 'Multiple warehouses found for company %s. Taking first' 'one found (%s) to determine the picking types for this ' 'company\'s pickings. Please verify this setting.', company.name, warehouse.name) # Fill picking_type_id required field for picking_type, type_id in (('in', warehouse.in_type_id.id), ('out', warehouse.out_type_id.id), ('internal', warehouse.int_type_id.id)): openupgrade.logged_query( cr, """ UPDATE stock_picking SET picking_type_id = %s WHERE {type_legacy} = %s """.format(type_legacy=type_legacy), ( type_id, picking_type, )) # state key auto -> waiting cr.execute("UPDATE stock_picking SET state = %s WHERE state = %s", ( 'waiting', 'auto', ))
def ensure_admin_email(cr, pool): """During migration, there are writes via the ORM to tracking fields. This breaks if admin neither has a valid alias nor an email""" admin = pool['res.users'].browse(cr, SUPERUSER_ID, SUPERUSER_ID) if not admin.email and not pool['ir.config_parameter'].get_param( cr, SUPERUSER_ID, 'mail.catchall.domain'): # that's the default value for new installations default_email = '*****@*****.**' openupgrade.message( 'base', None, None, 'No email address for admin and no catchall domain defined - ' 'setting admin\'s email address to %s', default_email) admin.write({'email': default_email})
def migrate_stock_warehouse(cr, pool): """Enable purchasing on all warehouses. This will trigger the creation of the purchase procurement rule""" warehouse_obj = pool['stock.warehouse'] warehouse_ids = warehouse_obj.search(cr, uid, []) warehouse_obj.write(cr, uid, warehouse_ids, {'buy_to_resupply': True}) if len(warehouse_ids) > 1: openupgrade.message( cr, 'purchase', False, False, "Purchasing is now enabled on all your warehouses. If this is " "not appropriate, disable the option 'Purchase to resupply this " "Warehouse' on the warehouse settings. You need to have 'Manage " "Push and Pull inventory flows' checked on your user record in " "order to access this setting.")
def process_states(cr): """Map obsolete active states to 'running' and let the scheduler decide if these procurements are actually 'done'. Warn if there are procurements in obsolete draft state""" openupgrade.logged_query( cr, "UPDATE procurement_order SET state = %s WHERE state in %s", ('running', ('ready', 'waiting'))) cr.execute("SELECT COUNT(*) FROM procurement_order WHERE state = 'draft'") count = cr.fetchone()[0] if count: openupgrade.message( cr, 'procurement', 'procurement_order', 'state', 'In this database, %s procurements are in draft state. In ' 'Odoo 8.0, these procurements cannot be processed further.', count)
def migrate_procurement_order(cr, registry): """Set warehouse, partner from the move.""" cr.execute(""" UPDATE procurement_order AS po SET partner_dest_id = sm.partner_id FROM stock_move AS sm WHERE po.move_dest_id = sm.id """) company_obj = registry['res.company'] warehouse_obj = registry['stock.warehouse'] procurement_obj = registry['procurement.order'] for company in company_obj.browse(cr, uid, company_obj.search(cr, uid, [])): procurement_ids = procurement_obj.search( cr, uid, [('company_id', '=', company.id)]) if not procurement_ids: continue warehouse_ids = warehouse_obj.search(cr, uid, [('company_id', '=', company.id)]) if not warehouse_ids: # Warehouse_id is not required on procurements openupgrade.message( cr, 'stock', 'procurement_order', 'warehouse_id', 'No warehouse found for company %s, but this company does ' 'have procurements. Not setting a warehouse on them.', company.name) continue warehouse = warehouse_obj.browse(cr, uid, warehouse_ids[0]) if len(warehouse_ids) > 1: openupgrade.message( cr, 'stock', 'procurement_order', 'warehouse_id', 'Multiple warehouses found for company %s. Taking first' 'one found (%s) to append to this company\'s procurements. ' 'Please verify this setting.', company.name, warehouse.name) procurement_obj.write(cr, uid, procurement_ids, {'warehouse_id': warehouse.id})
def migrate_procurement_order(cr, registry): """ In 7.0: procurement_order.move_id: the reservation for which the procurement was generated. Counterpart field on the stock move is stock_move.procurements. This is the move_dest_id on the purchase order lines that are created for the procurement, which is propagated as the move_dest_id on the move lines created for the incoming products of the purchase order. The id(s) of these move lines are recorded as the purchase line's move_ids (or stock_move.purchase_line_id). Something similar occurs in mrp: stock_move.production_id vs. production_ order.move_created_ids(2), and procurement_order.production_id. The procurement order's move_id is production_order.move_prod_id. In 8.0: procurement_order.move_dest_id: stock move that generated the procurement order, e.g. a sold product from stock to customer location. Counterpart field on the stock move does not seem to exist. procurement_order.move_ids: moves that the procurement order has generated, e.g. a purchased product from supplier to stock location. Counterpart field on the stock move is stock_move.procurement_id. """ # Reverse the link between procurement orders and the stock moves that # satisfy them. cr.execute(""" UPDATE stock_move sm SET procurement_id = po.id FROM procurement_order po WHERE po.{move_id} = sm.id """.format(move_id=openupgrade.get_legacy_name('move_id'))) # Sync the destination move, if any cr.execute(""" UPDATE procurement_order po SET move_dest_id = sm.move_dest_id FROM stock_move sm WHERE sm.procurement_id = po.id AND sm.move_dest_id IS NOT NULL """) # Set partner from the destination move. cr.execute(""" UPDATE procurement_order AS po SET partner_dest_id = sm.partner_id FROM stock_move AS sm WHERE po.move_dest_id = sm.id AND sm.partner_id IS NOT NULL """) # Set warehouse company_obj = registry['res.company'] warehouse_obj = registry['stock.warehouse'] procurement_obj = registry['procurement.order'] for company in company_obj.browse(cr, uid, company_obj.search(cr, uid, [])): procurement_ids = procurement_obj.search( cr, uid, [('company_id', '=', company.id)]) if not procurement_ids: continue warehouse_ids = warehouse_obj.search(cr, uid, [('company_id', '=', company.id)]) if not warehouse_ids: # Warehouse_id is not required on procurements openupgrade.message( cr, 'stock', 'procurement_order', 'warehouse_id', 'No warehouse found for company %s, but this company does ' 'have procurements. Not setting a warehouse on them.', company.name) continue warehouse = warehouse_obj.browse(cr, uid, warehouse_ids[0]) if len(warehouse_ids) > 1: openupgrade.message( cr, 'stock', 'procurement_order', 'warehouse_id', 'Multiple warehouses found for company %s. Taking first' 'one found (%s) to append to this company\'s procurements. ' 'Please verify this setting.', company.name, warehouse.name) procurement_obj.write(cr, uid, procurement_ids, {'warehouse_id': warehouse.id})
def set_warehouse_view_location(cr, registry, warehouse): """ Getting the shared view locations of all existing locations which is not the overall Physical locations view. Searching for parent left/right explicitely for lack of a parent_of operator. For parent left/right clarification, refer to https://answers.launchpad.net/openobject-server/+question/186704 Known issue: we don't know if the found view location includes locations of other warehouses and is thus not warehouse specific so we'll just warn about the changes we make. """ location_obj = registry['stock.location'] all_warehouse_view = registry['ir.model.data'].get_object_reference( cr, uid, 'stock', 'stock_location_locations')[1] location_ids = location_obj.search(cr, uid, [ ('parent_left', '<', warehouse.lot_stock_id.parent_left), ('parent_left', '<', warehouse.lot_stock_id.parent_right), ('parent_right', '>', warehouse.lot_stock_id.parent_left), ('parent_right', '>', warehouse.lot_stock_id.parent_right), ('parent_left', '<', warehouse.wh_input_stock_loc_id.parent_left), ('parent_left', '<', warehouse.wh_input_stock_loc_id.parent_right), ('parent_right', '>', warehouse.wh_input_stock_loc_id.parent_left), ('parent_right', '>', warehouse.wh_input_stock_loc_id.parent_right), ('parent_left', '<', warehouse.wh_output_stock_loc_id.parent_left), ('parent_left', '<', warehouse.wh_output_stock_loc_id.parent_right), ('parent_right', '>', warehouse.wh_output_stock_loc_id.parent_left), ('parent_right', '>', warehouse.wh_output_stock_loc_id.parent_right), ('id', 'child_of', all_warehouse_view), ('id', '!=', all_warehouse_view), ]) if location_ids: warehouse_view_id = location_ids[0] location = location_obj.browse(cr, uid, location_ids[0]) openupgrade.message( cr, 'stock', 'stock_warehouse', 'view_location_id', "Selecting location '%s' as the view location of warehouse %s", location.name, warehouse.code) else: openupgrade.message(cr, 'stock', 'stock_warehouse', 'view_location_id', "Creating new view location for warehouse %s", warehouse.code) for location in (warehouse.lot_stock_id, warehouse.wh_input_stock_loc_id, warehouse.wh_output_stock_loc_id): if (location.location_id and location.location_id.id != all_warehouse_view): openupgrade.message( cr, 'stock', 'stock_location', 'location_id', "Overwriting existing parent location (%s) of location %s " "with the warehouse's new view location", location.location_id.name, location.name) warehouse_view_id = location_obj.create( cr, uid, { 'name': warehouse.code, 'usage': 'view', 'location_id': all_warehouse_view, }) location_obj.write( cr, uid, set([ warehouse.lot_stock_id.id, warehouse.wh_input_stock_loc_id.id, warehouse.wh_output_stock_loc_id.id ]), {'location_id': warehouse_view_id}) warehouse.write({'view_location_id': warehouse_view_id}) warehouse.refresh()
def migrate_stock_picking(cr, registry): """Update picking records with the correct picking_type_id and state. As elsewhere, multiple warehouses with the same company pose a problem. """ warehouse_obj = registry['stock.warehouse'] company_obj = registry['res.company'] picking_obj = registry['stock.picking'] type_legacy = openupgrade.get_legacy_name('type') for company in company_obj.browse(cr, uid, company_obj.search(cr, uid, [])): warehouse_ids = warehouse_obj.search(cr, uid, [('company_id', '=', company.id)]) if not warehouse_ids: picking_ids = picking_obj.search(cr, uid, [('company_id', '=', company.id)]) if not picking_ids: continue warehouse_ids = [ registry['ir.model.data'].xmlid_to_res_id( cr, uid, 'stock.warehouse0', raise_if_not_found=True) ] openupgrade.message( cr, 'stock', 'stock_picking', 'picking_type_id', 'No warehouse found for company %s, but this company does ' 'have pickings. Taking the default warehouse.', company.name) warehouse = warehouse_obj.browse(cr, uid, warehouse_ids[0]) if len(warehouse_ids) > 1: openupgrade.message( cr, 'stock', 'stock_picking', 'picking_type_id', 'Multiple warehouses found for company %s. Taking first' 'one found (%s) to determine the picking types for this ' 'company\'s pickings. Please verify this setting.', company.name, warehouse.name) # Fill picking_type_id required field for picking_type, type_id in (('in', warehouse.in_type_id.id), ('out', warehouse.out_type_id.id), ('internal', warehouse.int_type_id.id)): openupgrade.logged_query( cr, """ UPDATE stock_picking SET picking_type_id = %s WHERE {type_legacy} = %s """.format(type_legacy=type_legacy), ( type_id, picking_type, )) # state key auto -> waiting cr.execute("UPDATE stock_picking SET state = %s WHERE state = %s", ( 'waiting', 'auto', )) # Add a column for referring stock moves in stock pack operation cr.execute(""" ALTER TABLE stock_pack_operation ADD COLUMN %s INTEGER """ % openupgrade.get_legacy_name('move_id')) # Recreate stock.pack.operation (only for moves that belongs to a picking) stock_move_obj = registry['stock.move'] done_move_ids = stock_move_obj.search(cr, uid, [('state', '=', 'done')]) if not done_move_ids: return openupgrade.logged_query( cr, """ INSERT INTO stock_pack_operation (%s, picking_id, product_id, product_uom_id, product_qty, qty_done, lot_id, date, location_id, location_dest_id, processed) SELECT id, picking_id, product_id, product_uom, product_uom_qty, product_uom_qty, %s, date, location_id, location_dest_id, 'true' FROM stock_move WHERE id IN %%s AND picking_id IS NOT NULL """ % (openupgrade.get_legacy_name('move_id'), openupgrade.get_legacy_name('prodlot_id')), (tuple(done_move_ids), )) # And link it with moves creating stock.move.operation.link records openupgrade.logged_query( cr, """ INSERT INTO stock_move_operation_link (move_id, operation_id, qty) SELECT %s, id, product_qty FROM stock_pack_operation """ % openupgrade.get_legacy_name('move_id'))
def migrate_stock_picking(cr, registry): """Update picking records with the correct picking_type_id and state. As elsewhere, multiple warehouses with the same company pose a problem. """ warehouse_obj = registry['stock.warehouse'] company_obj = registry['res.company'] picking_obj = registry['stock.picking'] location_obj = registry['stock.location'] type_legacy = openupgrade.get_legacy_name('type') for company in company_obj.browse(cr, uid, company_obj.search(cr, uid, [])): warehouse_ids = warehouse_obj.search(cr, uid, [('company_id', '=', company.id)]) if not warehouse_ids: picking_ids = picking_obj.search(cr, uid, [('company_id', '=', company.id)]) if not picking_ids: continue warehouse_ids = [ registry['ir.model.data'].xmlid_to_res_id( cr, uid, 'stock.warehouse0', raise_if_not_found=True) ] openupgrade.message( cr, 'stock', 'stock_picking', 'picking_type_id', 'No warehouse found for company %s, but this company does ' 'have pickings. Taking the default warehouse.', company.name) for warehouse in warehouse_obj.browse(cr, uid, warehouse_ids): # Select all the child locations of this Warehouse location_ids = location_obj.search( cr, uid, [('id', 'child_of', warehouse.view_location_id.id)]) # Fill picking_type_id required field for picking_type, type_id in (('in', warehouse.in_type_id.id), ('out', warehouse.out_type_id.id), ('internal', warehouse.int_type_id.id)): openupgrade.logged_query( cr, """ UPDATE stock_picking AS sp SET picking_type_id = %s WHERE sp.id IN ( SELECT sp1.id FROM stock_picking AS sp1 INNER JOIN stock_move AS sm1 ON sm1.picking_id = sp1.id WHERE ( sm1.location_dest_id in %s OR sm1.location_id in %s ) AND sp1.{type_legacy} = %s ) """.format(type_legacy=type_legacy), ( type_id, tuple(location_ids), tuple(location_ids), picking_type, )) if warehouse_ids: warehouse = warehouse_obj.browse(cr, uid, warehouse_ids[0]) # For other stock pickings that were associated to no warehouse # at all, just take the picking from the main warehouse. for picking_type, type_id in (('in', warehouse.in_type_id.id), ('out', warehouse.out_type_id.id), ('internal', warehouse.int_type_id.id)): openupgrade.logged_query( cr, """ UPDATE stock_picking as sp SET picking_type_id = %s WHERE picking_type_id IS NULL AND sp.{type_legacy} = %s """.format(type_legacy=type_legacy), ( type_id, picking_type, )) # state key auto -> waiting cr.execute("UPDATE stock_picking SET state = %s WHERE state = %s", ( 'waiting', 'auto', )) # Add a column for referring stock moves in stock pack operation cr.execute(""" ALTER TABLE stock_pack_operation ADD COLUMN %s INTEGER """ % openupgrade.get_legacy_name('move_id')) # Recreate stock.pack.operation (only for moves that belongs to a picking) openupgrade.logged_query( cr, """ INSERT INTO stock_pack_operation (%s, picking_id, product_id, product_uom_id, product_qty, qty_done, lot_id, date, location_id, location_dest_id, processed) SELECT id, picking_id, product_id, product_uom, product_uom_qty, product_uom_qty, %s, date, location_id, location_dest_id, 'true' FROM stock_move WHERE state = 'done' AND picking_id IS NOT NULL """ % (openupgrade.get_legacy_name('move_id'), openupgrade.get_legacy_name('prodlot_id')), ) # And link it with moves creating stock.move.operation.link records openupgrade.logged_query( cr, """ INSERT INTO stock_move_operation_link (move_id, operation_id, qty) SELECT %s, id, product_qty FROM stock_pack_operation """ % openupgrade.get_legacy_name('move_id'))