From c5b08dc354bb982a14832dbd1aa9f506b109aa7c Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 25 Mar 2010 13:55:11 +0530 Subject: [PATCH] [REF] puchase: merge order wizard bzr revid: hmo@tinyerp.com-20100325082511-k3ri4500pjd7kwsz --- addons/purchase/purchase.py | 110 +++++++++++- .../purchase/wizard/purchase_order_group.py | 160 ++++-------------- 2 files changed, 143 insertions(+), 127 deletions(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 7077d688beb..0dc7926f428 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -32,7 +32,7 @@ from tools import config from tools.translate import _ import decimal_precision as dp - +from osv.orm import browse_record, browse_null # # Model definition @@ -446,6 +446,114 @@ class purchase_order(osv.osv): }) return super(purchase_order, self).copy(cr, uid, id, default, context) + + def do_merge(self, cr, uid, ids, context): + """ + To merge similar type of purchase orders. + Orders will only be merged if: + * Purchase Orders are in draft + * Purchase Orders belong to the same partner + * Purchase Orders are have same stock location, same pricelist + Lines will only be merged if: + * Order lines are exactly the same except for the quantity and unit + + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param ids: the ID or list of IDs + @param context: A standard dictionary + + @return: new purchase order id + + """ + wf_service = netsvc.LocalService("workflow") + def make_key(br, fields): + list_key = [] + for field in fields: + field_val = getattr(br, field) + if field in ('product_id', 'move_dest_id', 'account_analytic_id'): + if not field_val: + field_val = False + if isinstance(field_val, browse_record): + field_val = field_val.id + elif isinstance(field_val, browse_null): + field_val = False + elif isinstance(field_val, list): + field_val = ((6, 0, tuple([v.id for v in field_val])),) + list_key.append((field, field_val)) + list_key.sort() + return tuple(list_key) + + # compute what the new orders should contain + + new_orders = {} + + for porder in [order for order in self.browse(cr, uid, ids) if order.state == 'draft']: + order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id')) + new_order = new_orders.setdefault(order_key, ({}, [])) + new_order[1].append(porder.id) + order_infos = new_order[0] + if not order_infos: + order_infos.update({ + 'origin': porder.origin, + 'date_order': time.strftime('%Y-%m-%d'), + 'partner_id': porder.partner_id.id, + 'partner_address_id': porder.partner_address_id.id, + 'dest_address_id': porder.dest_address_id.id, + 'warehouse_id': porder.warehouse_id.id, + 'location_id': porder.location_id.id, + 'pricelist_id': porder.pricelist_id.id, + 'state': 'draft', + 'order_line': {}, + 'notes': '%s' % (porder.notes or '',), + }) + else: + #order_infos['name'] += ', %s' % porder.name + if porder.notes: + order_infos['notes'] = (order_infos['notes'] or '') + ('\n%s' % (porder.notes,)) + if porder.origin: + order_infos['origin'] = (order_infos['origin'] or '') + ' ' + porder.origin + + for order_line in porder.order_line: + line_key = make_key(order_line, ('name', 'date_planned', 'taxes_id', 'price_unit', 'notes', 'product_id', 'move_dest_id', 'account_analytic_id')) + o_line = order_infos['order_line'].setdefault(line_key, {}) + if o_line: + # merge the line with an existing line + o_line['product_qty'] += order_line.product_qty * order_line.product_uom.factor / o_line['uom_factor'] + else: + # append a new "standalone" line + for field in ('product_qty', 'product_uom'): + field_val = getattr(order_line, field) + if isinstance(field_val, browse_record): + field_val = field_val.id + o_line[field] = field_val + o_line['uom_factor'] = order_line.product_uom and order_line.product_uom.factor or 1.0 + + + + allorders = [] + for order_key, (order_data, old_ids) in new_orders.iteritems(): + # skip merges with only one order + if len(old_ids) < 2: + allorders += (old_ids or []) + continue + + # cleanup order line data + for key, value in order_data['order_line'].iteritems(): + del value['uom_factor'] + value.update(dict(key)) + order_data['order_line'] = [(0, 0, value) for value in order_data['order_line'].itervalues()] + + # create the new order + neworder_id = self.create(cr, uid, order_data) + allorders.append(neworder_id) + + # make triggers pointing to the old orders point to the new order + for old_id in old_ids: + wf_service.trg_redirect(uid, 'purchase.order', old_id, neworder_id, cr) + wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr) + return allorders + purchase_order() class purchase_order_line(osv.osv): diff --git a/addons/purchase/wizard/purchase_order_group.py b/addons/purchase/wizard/purchase_order_group.py index c34b610f26b..8c4e0784a7b 100644 --- a/addons/purchase/wizard/purchase_order_group.py +++ b/addons/purchase/wizard/purchase_order_group.py @@ -28,135 +28,43 @@ import wizard from osv.orm import browse_record, browse_null class purchase_order_group(osv.osv_memory): - _name = "purchase.order.group" - _description = "Purchase Wizard" - _columns = { - - } + _name = "purchase.order.group" + _description = "Purchase Wizard" + _columns = { + + } - def merge_orders(self, cr, uid, ids, context): - """ - To merge similar type of purchase orders. - - @param self: The object pointer. - @param cr: A database cursor - @param uid: ID of the user currently logged in - @param ids: the ID or list of IDs - @param context: A standard dictionary - - @return: purchase order view - - """ - order_obj = self.pool.get('purchase.order') - mod_obj =self.pool.get('ir.model.data') - result = mod_obj._get_id(cr, uid, 'purchase', 'view_purchase_order_filter') - id = mod_obj.read(cr, uid, result, ['res_id']) + def merge_orders(self, cr, uid, ids, context): + """ + To merge similar type of purchase orders. + + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param ids: the ID or list of IDs + @param context: A standard dictionary + + @return: purchase order view + + """ + order_obj = self.pool.get('purchase.order') + mod_obj =self.pool.get('ir.model.data') + result = mod_obj._get_id(cr, uid, 'purchase', 'view_purchase_order_filter') + id = mod_obj.read(cr, uid, result, ['res_id']) - - def make_key(br, fields): - """ - Returns tuple indicating the value corresponding to fields - - @param br: record object - @param fields: name of fields - @return: Returns tuple indicating the value corresponding to fields - - """ - list_key = [] - for field in fields: - field_val = getattr(br, field) - if field in ('product_id', 'move_dest_id', 'account_analytic_id'): - if not field_val: - field_val = False - if isinstance(field_val, browse_record): - field_val = field_val.id - elif isinstance(field_val, browse_null): - field_val = False - elif isinstance(field_val, list): - field_val = ((6, 0, tuple([v.id for v in field_val])),) - list_key.append((field, field_val)) - list_key.sort() - return tuple(list_key) + allorders = order_obj.do_merge(cr, uid, context.get('active_ids',[]), context) + - # compute what the new orders should contain - - new_orders = {} - - for porder in [order for order in order_obj.browse(cr, uid, context['active_ids']) if order.state == 'draft']: - order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id')) - new_order = new_orders.setdefault(order_key, ({}, [])) - new_order[1].append(porder.id) - order_infos = new_order[0] - if not order_infos: - order_infos.update({ - 'origin': porder.origin, - 'date_order': time.strftime('%Y-%m-%d'), - 'partner_id': porder.partner_id.id, - 'partner_address_id': porder.partner_address_id.id, - 'dest_address_id': porder.dest_address_id.id, - 'warehouse_id': porder.warehouse_id.id, - 'location_id': porder.location_id.id, - 'pricelist_id': porder.pricelist_id.id, - 'state': 'draft', - 'order_line': {}, - 'notes': '%s' % (porder.notes or '',), - }) - else: - #order_infos['name'] += ', %s' % porder.name - if porder.notes: - order_infos['notes'] = (order_infos['notes'] or '') + ('\n%s' % (porder.notes,)) - if porder.origin: - order_infos['origin'] = (order_infos['origin'] or '') + ' ' + porder.origin - - for order_line in porder.order_line: - line_key = make_key(order_line, ('name', 'date_planned', 'taxes_id', 'price_unit', 'notes', 'product_id', 'move_dest_id', 'account_analytic_id')) - o_line = order_infos['order_line'].setdefault(line_key, {}) - if o_line: - # merge the line with an existing line - o_line['product_qty'] += order_line.product_qty * order_line.product_uom.factor / o_line['uom_factor'] - else: - # append a new "standalone" line - for field in ('product_qty', 'product_uom'): - field_val = getattr(order_line, field) - if isinstance(field_val, browse_record): - field_val = field_val.id - o_line[field] = field_val - o_line['uom_factor'] = order_line.product_uom and order_line.product_uom.factor or 1.0 - - wf_service = netsvc.LocalService("workflow") - - allorders = [] - for order_key, (order_data, old_ids) in new_orders.iteritems(): - # skip merges with only one order - if len(old_ids) < 2: - allorders += (old_ids or []) - continue - - # cleanup order line data - for key, value in order_data['order_line'].iteritems(): - del value['uom_factor'] - value.update(dict(key)) - order_data['order_line'] = [(0, 0, value) for value in order_data['order_line'].itervalues()] - - # create the new order - neworder_id = order_obj.create(cr, uid, order_data) - allorders.append(neworder_id) - - # make triggers pointing to the old orders point to the new order - for old_id in old_ids: - wf_service.trg_redirect(uid, 'purchase.order', old_id, neworder_id, cr) - wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr) - - return { - 'domain': "[('id','in', [" + ','.join(map(str, allorders)) + "])]", - 'name': 'Purchase Orders', - 'view_type': 'form', - 'view_mode': 'tree,form', - 'res_model': 'purchase.order', - 'view_id': False, - 'type': 'ir.actions.act_window', - 'search_view_id': id['res_id'] - } + return { + 'domain': "[('id','in', [" + ','.join(map(str, allorders)) + "])]", + 'name': 'Purchase Orders', + 'view_type': 'form', + 'view_mode': 'tree,form', + 'res_model': 'purchase.order', + 'view_id': False, + 'type': 'ir.actions.act_window', + 'search_view_id': id['res_id'] + } purchase_order_group()