merged
[odoo/odoo.git] / addons / purchase / wizard / wizard_group.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import time
24
25 import wizard
26 import netsvc
27 import pooler
28 from osv.orm import browse_record, browse_null
29
30
31 merge_form = """<?xml version="1.0"?>
32 <form string="Merge orders">
33     <separator string="Are you sure you want to merge these orders ?"/>
34     <newline/>
35     <label>Please note that:
36       - orders will only be merged if:
37         * their status is draft
38         * they belong to the same partner
39         * are going to the same location
40         * have the same pricelist
41       - lines will only be merged if:
42         * they are exactly the same except for the quantity and unit</label>
43 </form>
44 """
45
46 merge_fields = {
47 }
48
49 ack_form = """<?xml version="1.0"?>
50 <form string="Merge orders">
51     <separator string="Orders merged"/>
52 </form>"""
53
54 ack_fields = {}
55
56
57 def _merge_orders(self, cr, uid, data, context):
58     pool = pooler.get_pool(cr.dbname)
59     order_obj = pool.get('purchase.order')
60     mod_obj = pool.get('ir.model.data')
61     result = mod_obj._get_id(cr, uid, 'purchase', 'view_purchase_order_filter')
62     id = mod_obj.read(cr, uid, result, ['res_id'])
63
64     def make_key(br, fields):
65         list_key = []
66         for field in fields:
67             field_val = getattr(br, field)
68             if field in ('product_id', 'move_dest_id', 'account_analytic_id'):
69                 if not field_val:
70                     field_val = False
71             if isinstance(field_val, browse_record):
72                 field_val = field_val.id
73             elif isinstance(field_val, browse_null):
74                 field_val = False
75             elif isinstance(field_val, list):
76                 field_val = ((6, 0, tuple([v.id for v in field_val])),)
77             list_key.append((field, field_val))
78         list_key.sort()
79         return tuple(list_key)
80
81     # compute what the new orders should contain
82     new_orders = {}
83     for porder in [order for order in order_obj.browse(cr, uid, data['ids']) if order.state == 'draft']:
84         order_key = make_key(porder, ('partner_id', 'location_id', 'pricelist_id'))
85
86         new_order = new_orders.setdefault(order_key, ({}, []))
87         new_order[1].append(porder.id)
88         order_infos = new_order[0]
89         if not order_infos:
90             order_infos.update({
91                 'origin': porder.origin,
92                 'date_order': time.strftime('%Y-%m-%d'),
93                 'partner_id': porder.partner_id.id,
94                 'partner_address_id': porder.partner_address_id.id,
95                 'dest_address_id': porder.dest_address_id.id,
96                 'warehouse_id': porder.warehouse_id.id,
97                 'location_id': porder.location_id.id,
98                 'pricelist_id': porder.pricelist_id.id,
99                 'state': 'draft',
100                 'order_line': {},
101                 'notes': '%s' % (porder.notes or '',),
102             })
103         else:
104             #order_infos['name'] += ', %s' % porder.name
105             if porder.notes:
106                 order_infos['notes'] = (order_infos['notes'] or '') + ('\n%s' % (porder.notes,))
107             if porder.origin:
108                 order_infos['origin'] = (order_infos['origin'] or '') + ' ' + porder.origin
109
110         for order_line in porder.order_line:
111             line_key = make_key(order_line, ('name', 'date_planned', 'taxes_id', 'price_unit', 'notes', 'product_id', 'move_dest_id', 'account_analytic_id'))
112             o_line = order_infos['order_line'].setdefault(line_key, {})
113             if o_line:
114                 # merge the line with an existing line
115                 o_line['product_qty'] += order_line.product_qty * order_line.product_uom.factor / o_line['uom_factor']
116             else:
117                 # append a new "standalone" line
118                 for field in ('product_qty', 'product_uom'):
119                     field_val = getattr(order_line, field)
120                     if isinstance(field_val, browse_record):
121                         field_val = field_val.id
122                     o_line[field] = field_val
123                 o_line['uom_factor'] = order_line.product_uom and order_line.product_uom.factor or 1.0
124
125     wf_service = netsvc.LocalService("workflow")
126
127     allorders = []
128     for order_key, (order_data, old_ids) in new_orders.iteritems():
129         # skip merges with only one order
130         if len(old_ids) < 2:
131             allorders += (old_ids or [])
132             continue
133
134         # cleanup order line data
135         for key, value in order_data['order_line'].iteritems():
136             del value['uom_factor']
137             value.update(dict(key))
138         order_data['order_line'] = [(0, 0, value) for value in order_data['order_line'].itervalues()]
139
140         # create the new order
141         neworder_id = order_obj.create(cr, uid, order_data)
142         allorders.append(neworder_id)
143
144         # make triggers pointing to the old orders point to the new order
145         for old_id in old_ids:
146             wf_service.trg_redirect(uid, 'purchase.order', old_id, neworder_id, cr)
147             wf_service.trg_validate(uid, 'purchase.order', old_id, 'purchase_cancel', cr)
148
149     return {
150         'domain': "[('id','in', [" + ','.join(map(str, allorders)) + "])]",
151         'name': 'Purchase Orders',
152         'view_type': 'form',
153         'view_mode': 'tree,form',
154         'res_model': 'purchase.order',
155         'view_id': False,
156         'type': 'ir.actions.act_window',
157         'search_view_id': id['res_id']
158     }
159
160
161 class merge_orders(wizard.interface):
162     states = {
163         'init': {
164             'actions': [],
165             'result': {'type': 'form', 'arch': merge_form, 'fields' : merge_fields, 'state' : [('end', 'Cancel'), ('merge', 'Merge orders') ]}
166         },
167         'merge': {
168             'actions': [],
169             'result': {'type': 'action', 'action': _merge_orders, 'state': 'end'}
170         },
171     }
172
173 merge_orders("purchase.order.merge")
174