~julie-w/unifield-wm/UTP-925

1 by jf
Initial Import
1
#!/usr/bin/env python
2
# -*- encoding: utf-8 -*-
3
##############################################################################
4
#
5
#    OpenERP, Open Source Management Solution
6
#    Copyright (C) 2011 TeMPO Consulting, MSF
7
#
8
#    This program is free software: you can redistribute it and/or modify
9
#    it under the terms of the GNU Affero General Public License as
10
#    published by the Free Software Foundation, either version 3 of the
11
#    License, or (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 Affero General Public License for more details.
17
#
18
#    You should have received a copy of the GNU Affero General Public License
19
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
#
21
##############################################################################
22
23
import time
24
import netsvc
25
26
from osv import osv
27
from osv import fields
28
from tools.translate import _
29
30
class procurement_list(osv.osv):
31
    _name = 'procurement.list'
32
    _description = 'Procurement list'
33
34
    _columns = {
35
        'name': fields.char(size=64, string='Ref.', required=True, readonly=True, 
36
                            states={'draft': [('readonly', False)]}),
37
        'requestor': fields.char(size=20, string='Requestor',),
38
        'order_date': fields.date(string='Order date', required=True),
39
        'warehouse_id': fields.many2one('stock.warehouse', string='Warehouse'),
40
        'origin': fields.char(size=64, string='Origin'),
41
        'state': fields.selection([('draft', 'Draft'),('done', 'Done'), ('cancel', 'Cancel')], 
42
                                   string='State', readonly=True),
43
        'line_ids': fields.one2many('procurement.list.line', 'list_id', string='Lines', readonly=True,
44
                                    states={'draft': [('readonly', False)]}),
45
        'notes': fields.text(string='Notes'),
46
        'order_ids': fields.many2many('purchase.order', 'procurement_list_order_rel',
47
                                      'list_id', 'order_id', string='Orders', readonly=True),
48
    }
49
50
    _defaults = {
51
        'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'procurement.list'),
52
        'state': lambda *a: 'draft',
53
        'order_date': lambda *a: time.strftime('%Y-%m-%d'),
54
    }
55
    
56
    def copy(self, cr, uid, ids, default={}, context={}):
57
        '''
58
        Increments the sequence for the new list
59
        '''        
60
        default['name'] = self.pool.get('ir.sequence').get(cr, uid, 'procurement.list')
61
        default['order_ids'] = []
62
        
63
        res = super(procurement_list, self).copy(cr, uid, ids, default, context=context)
64
        
65
        return res
66
67
    def cancel(self, cr, uid, ids, context={}):
68
        '''
69
        Sets the procurement list to the 'Cancel' state
70
        '''
71
        self.write(cr, uid, ids, {'state': 'cancel'})
72
73
        return True
33 by jf
UF-108: [MERGE] default supp. sugg.
74
    
75
    def create_po(self, cr, uid, ids, context={}):
76
        '''
77
        Creates all purchase orders according to choices on lines
78
        '''
79
        if ids and isinstance(ids, (int, long)):
80
            ids = [ids]
81
            
82
        order_obj = self.pool.get('purchase.order')
83
        order_line_obj = self.pool.get('purchase.order.line')
84
        proc_obj = self.pool.get('procurement.list')
85
        line_obj = self.pool.get('procurement.list.line')
86
        prod_sup_obj = self.pool.get('product.supplierinfo')
87
88
        # We search if at least one line hasn't defined supplier
89
        for list in self.browse(cr, uid, ids):
90
            for line in list.line_ids:
91
                if not line.supplier_id:
92
                    raise osv.except_osv(_('Error'), _('You cannot create purchase orders while all lines haven\'t a defined supplier'))
93
94
            # We search lines group by supplier_id
95
            po_exists = {}
96
            po_id = False
97
            po_ids = []
98
            line_ids = line_obj.search(cr, uid, [('list_id', 'in', ids)], order='supplier_id')
99
            for l in line_obj.browse(cr, uid, line_ids):
100
                # Search if a PO already exists in the system
101
                if not po_exists.get(l.supplier_id.id, False):
102
                    # If no PO in local memory, search in DB
103
                    po_exist = order_obj.search(cr, uid, [('origin', '=', l.list_id.name), ('partner_id', '=', l.supplier_id.id)])
104
                    if po_exist:
105
                        # A PO exists in DB, set the id in local memory
106
                        po_exists[l.supplier_id.id] = po_exist[0]
107
                    else: 
108
                        # try to create a new PO, and set its id in local memory
109
                        address = l.supplier_id.address_get().get('default')
110
                        # Returns an error when the supplier has not defined address
111
                        if not address:
112
                            raise osv.except_osv(_('Error'), _('The supplier %s has no address defined on its form' %l.supplier_id.name))
113
                        # When starting or when the supplier changed, we create a Purchase Order
114
                        po_id = order_obj.create(cr, uid, {'partner_id': l.supplier_id.id,
115
                                                           'partner_address_id': address,
116
                                                           'pricelist_id': l.supplier_id.property_product_pricelist.id,
117
                                                           'origin': l.list_id.name,
118
                                                           'location_id': proc_obj._get_location(cr, uid, l.list_id.warehouse_id)})
119
                        po_exists[l.supplier_id.id] = po_id
120
    
121
                # Get the PO id in local memory
122
                po_id = po_exists.get(l.supplier_id.id)
123
                    
124
                # We create all lines for this supplier
125
                price_unit = prod_sup_obj.price_get(cr, uid, [l.supplier_id.id], l.product_id.id, l.product_qty)
126
                order_line_obj.create(cr, uid, {'product_uom': l.product_uom_id.id,
127
                                                'product_id': l.product_id.id,
128
                                                'order_id': po_id,
129
                                                'price_unit': price_unit[l.supplier_id.id],
130
                                                'date_planned': l.list_id.order_date,
131
                                                'product_qty': l.product_qty,
132
                                                'name': l.product_id.name,})
133
    
134
            for supplier in po_exists:
135
                po_ids.append(po_exists.get(supplier))
136
    
137
            # We confirm all created orders
138
            wf_service = netsvc.LocalService("workflow")
139
            for po in po_ids:
140
                wf_service.trg_validate(uid, 'purchase.order', po, 'purchase_confirm', cr)
141
    
142
            proc_obj.write(cr, uid, ids[0], {'state': 'done', 'order_ids': [(6, 0, po_ids)]}) 
143
144
        return {'type': 'ir.actions.act_window',
145
                'res_model': 'purchase.order',
146
                'view_type': 'form',
147
                'view_mode': 'tree,form',
148
                'domain': [('id', 'in', po_ids)],
149
               }
1 by jf
Initial Import
150
151
    def create_rfq(self, cr, uid, ids, context={}):
152
        ''' 
153
        Create a RfQ per supplier with all products
154
        '''
155
        purchase_obj = self.pool.get('purchase.order')
156
        line_obj = self.pool.get('purchase.order.line')
157
158
        order_ids = []
159
160
        for list in self.browse(cr, uid, ids, context=context):
33 by jf
UF-108: [MERGE] default supp. sugg.
161
            # Returns an error message if no products defined
1 by jf
Initial Import
162
            if not list.line_ids or len(list.line_ids) == 0:
163
                raise osv.except_osv(_('Error'), _('No line defined for this list !'))
164
165
            location_id = self._get_location(cr, uid, list.warehouse_id)
33 by jf
UF-108: [MERGE] default supp. sugg.
166
167
        context['active_ids'] = ids
168
        context['active_id'] = ids[0]
1 by jf
Initial Import
169
170
        return {'type': 'ir.actions.act_window',
33 by jf
UF-108: [MERGE] default supp. sugg.
171
                'res_model': 'procurement.choose.supplier.rfq',
172
                'target': 'new',
1 by jf
Initial Import
173
                'view_type': 'form',
33 by jf
UF-108: [MERGE] default supp. sugg.
174
                'view_mode': 'form',
175
                'context': context}
1 by jf
Initial Import
176
177
    def reset(self, cr, uid, ids, context={}):
178
        '''
179
        Sets the procurement list to the 'Draft' state
180
        '''
181
        self.write(cr, uid, ids, {'state': 'draft'})
182
183
        return True
184
185
    def _get_location(self, cr, uid, warehouse=None):
186
        '''
187
        Returns the default input location for product
188
        '''
189
        if warehouse:
190
            return warehouse.lot_input_id.id
191
        warehouse_obj = self.pool.get('stock.warehouse')
192
        warehouse_id = warehouse_obj.search(cr, uid, [])[0]
193
        return warehouse_obj.browse(cr, uid, warehouse_id).lot_input_id.id
194
195
procurement_list()
196
197
198
class procurement_list_line(osv.osv):
199
    _name = 'procurement.list.line'
200
    _description = 'Procurement line'
201
    _rec_name = 'product_id'
202
203
    _columns = {
204
        'product_id': fields.many2one('product.product', string='Product', required=True),
205
        'product_uom_id': fields.many2one('product.uom', string='UoM', required=True),
206
        'product_qty': fields.float(digits=(16,4), string='Quantity', required=True),
207
        'comment': fields.char(size=128, string='Comment'),
208
        'from_stock': fields.boolean(string='From stock ?'),
209
        'latest': fields.char(size=64, string='Latest document', readonly=True),
210
        'list_id': fields.many2one('procurement.list', string='List', required=True, ondelete='cascade'),
33 by jf
UF-108: [MERGE] default supp. sugg.
211
        'supplier_id': fields.many2one('res.partner', string='Supplier'),
1 by jf
Initial Import
212
    }
213
    
214
    _defaults = {
215
        'latest': lambda *a: '',
216
    }
217
    
218
    def copy_data(self, cr, uid, id, default={}, context={}):
219
        '''
220
        Initializes the 'latest' fields to an empty field
221
        '''
222
        default['latest'] = ''
223
        
224
        res = super(procurement_list_line, self).copy_data(cr, uid, id, default, context=context)
225
        
226
        return res
227
228
    def product_id_change(self, cr, uid, ids, product_id, context={}):
229
        '''
230
        Fills automatically the product_uom_id field on the line when the 
231
        product was changed.
232
        '''
233
        product_obj = self.pool.get('product.product')
234
235
        v = {}
236
        if not product_id:
33 by jf
UF-108: [MERGE] default supp. sugg.
237
            v.update({'product_uom_id': False, 'supplier_id': False})
1 by jf
Initial Import
238
        else:
239
            product = product_obj.browse(cr, uid, product_id, context=context)
33 by jf
UF-108: [MERGE] default supp. sugg.
240
            v.update({'product_uom_id': product.uom_id.id, 'supplier_id': product.seller_id.id})
1 by jf
Initial Import
241
242
        return {'value': v}
33 by jf
UF-108: [MERGE] default supp. sugg.
243
    
244
    
245
    def split_line(self, cr, uid, ids, context={}):
246
        '''
247
        Split a line into two lines
248
        '''
249
        if ids and isinstance(ids, (int, long)):
250
            ids = [ids]
251
        for line in self.browse(cr, uid, ids):
252
            state = line.list_id.state
253
        context.update({'line_id': ids[0], 'state': state})
254
        return {'type': 'ir.actions.act_window',
255
                'res_model': 'procurement.list.line.split',
256
                'target': 'new',
257
                'view_type': 'form',
258
                'view_mode': 'form',
259
                'context': context,
260
                }
261
        
262
    def merge_line(self, cr, uid, ids, context={}):
263
        '''
264
        Merges two lines
265
        '''
266
        if ids and isinstance(ids, (int, long)):
267
            ids = [ids]
268
        for line in self.browse(cr, uid, ids):
269
            state = line.list_id.state
270
        context.update({'line_id': ids[0], 'state': state})
271
        
272
        return {'type': 'ir.actions.act_window',
273
                'res_model': 'procurement.list.line.merge',
274
                'target': 'new',
275
                'view_type': 'form',
276
                'view_mode': 'form',
277
                'context': context,
278
                }
1 by jf
Initial Import
279
280
procurement_list_line()
281
282
283
class purchase_order_line(osv.osv):
284
    _name = 'purchase.order.line'
285
    _inherit = 'purchase.order.line'
286
    
287
    _columns = {
288
        'procurement_line_id': fields.many2one('procurement.list.line', string='Procurement Line', readonly=True, ondelete='set null'),
289
    }
290
    
291
    def action_confirm(self, cr, uid, ids, context={}):
292
        '''
293
        Changes the status of the procurement line
294
        '''
295
        proc_line_obj = self.pool.get('procurement.list.line')
296
        for line in self.browse(cr, uid, ids):
297
            if line.procurement_line_id and line.procurement_line_id.id:
298
                proc_line_obj.write(cr, uid, [line.procurement_line_id.id], {'latest': line.order_id.name})
299
        
300
        return super(purchase_order_line, self).action_confirm(cr, uid, ids, context=context)
301
    
302
purchase_order_line()
303
304
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
305