~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to tender_flow/tender_flow.py

  • Committer: jf
  • Date: 2012-08-03 14:15:44 UTC
  • mfrom: (1071.2.4 uf-1303)
  • Revision ID: jf@tempo4-20120803141544-xaplb4ot6do2b7iz
UF-1311 [FIX] Column of local expense should not be all in bold
UF-1310 [FIX] A menu is missing in supply configuration
lp:~unifield-team/unifield-wm/uf-1310

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
from osv import osv, fields
25
25
from osv.orm import browse_record, browse_null
26
26
from tools.translate import _
27
 
from lxml import etree
28
27
 
29
28
import decimal_precision as dp
30
29
import netsvc
31
30
import pooler
32
31
import time
33
32
 
34
 
# xml parser
35
 
from lxml import etree
36
 
 
37
33
from purchase_override import PURCHASE_ORDER_STATE_SELECTION
38
34
 
39
35
class tender(osv.osv):
47
43
        if not default:
48
44
            default = {}
49
45
        default['internal_state'] = 'draft' # UF-733: Reset the internal_state
50
 
        if not 'sale_order_id' in default:
51
 
            default['sale_order_id'] = False
52
46
        return super(osv.osv, self).copy(cr, uid, id, default, context=context)
53
47
    
54
48
    def unlink(self, cr, uid, ids, context=None):
55
49
        '''
56
50
        cannot delete tender not draft
57
51
        '''
58
 
        # Objects
59
 
        t_line_obj = self.pool.get('tender.line')
60
 
 
61
52
        if context is None:
62
53
            context = {}
63
54
        if isinstance(ids, (int, long)):
66
57
        for obj in self.browse(cr, uid, ids, context=context):
67
58
            if obj.state != 'draft':
68
59
                raise osv.except_osv(_('Warning !'), _("Cannot delete Tenders not in 'draft' state."))
69
 
 
70
 
            if obj.sale_order_id:
71
 
                obj_name = obj.sale_order_id.procurement_request and _('an Internal Request') or _('a Field Order')
72
 
                raise osv.except_osv(_('Warning !'), _("This tender is linked to %s, so you cannot delete it. Please cancel it instead.") % obj_name)
73
 
 
74
 
            for line in obj.tender_line_ids:
75
 
               t_line_obj.fake_unlink(cr, uid, [line.id], context=context)
76
 
 
77
60
        return super(tender, self).unlink(cr, uid, ids, context=context)
78
61
    
79
62
    def _vals_get(self, cr, uid, ids, fields, arg, context=None):
84
67
        for obj in self.browse(cr, uid, ids, context=context):
85
68
            result[obj.id] = {'rfq_name_list': '',
86
69
                              }
 
70
            
87
71
            rfq_names = []
88
72
            for rfq in obj.rfq_ids:
89
73
                rfq_names.append(rfq.name)
92
76
            result[obj.id]['rfq_name_list'] = ','.join(rfq_names)
93
77
            
94
78
        return result
95
 
 
96
 
    def _is_tender_from_fo(self, cr, uid, ids, field_name, args, context=None):
97
 
        res = {}
98
 
        for tender in self.browse(cr, uid, ids, context=context):
99
 
            retour = False
100
 
            ids_proc = self.pool.get('procurement.order').search(cr,uid,[('tender_id','=',tender.id)])
101
 
            ids_sol = self.pool.get('sale.order.line').search(cr,uid,[('procurement_id','in',ids_proc),('order_id.procurement_request','=',False)])
102
 
            if ids_sol:
103
 
                retour = True
104
 
            res[tender.id] = retour
105
 
        return res
106
 
 
 
79
    
107
80
    _columns = {'name': fields.char('Tender Reference', size=64, required=True, select=True, readonly=True),
108
81
                'sale_order_id': fields.many2one('sale.order', string="Sale Order", readonly=True),
109
82
                'state': fields.selection([('draft', 'Draft'),('comparison', 'Comparison'), ('done', 'Closed'), ('cancel', 'Cancelled'),], string="State", readonly=True),
123
96
                'notes': fields.text('Notes'),
124
97
                'internal_state': fields.selection([('draft', 'Draft'),('updated', 'Rfq Updated'), ], string="Internal State", readonly=True),
125
98
                'rfq_name_list': fields.function(_vals_get, method=True, string='RfQs Ref', type='char', readonly=True, store=False, multi='get_vals',),
126
 
                'product_id': fields.related('tender_line_ids', 'product_id', type='many2one', relation='product.product', string='Product'),
127
 
                'delivery_address': fields.many2one('res.partner.address', string='Delivery address', required=True),
128
 
               'tender_from_fo': fields.function(_is_tender_from_fo, method=True, type='boolean', string='Is tender from FO ?',),
 
99
                'product_id': fields.related('tender_line_ids', 'product_id', type='many2one', relation='product.product', string='Product')
129
100
                }
130
101
    
131
 
    _defaults = {'categ': 'other',
132
 
                 'state': 'draft',
 
102
    _defaults = {'state': 'draft',
133
103
                 'internal_state': 'draft',
 
104
                 'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'tender'),
134
105
                 'company_id': lambda obj, cr, uid, context: obj.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.id,
135
106
                 'creator': lambda obj, cr, uid, context: uid,
136
107
                 'creation_date': lambda *a: time.strftime('%Y-%m-%d'),
140
111
                 }
141
112
    
142
113
    _order = 'name desc'
143
 
 
144
 
    def _check_restriction_line(self, cr, uid, ids, context=None):
145
 
        '''
146
 
        Check if there is no restrictive products in lines
147
 
        '''
148
 
        if isinstance(ids, (int, long)):
149
 
            ids = [ids]
150
 
 
151
 
        line_obj = self.pool.get('tender.line')
152
 
 
153
 
        res = True
154
 
        for tender in self.browse(cr, uid, ids, context=context):
155
 
            res = res and line_obj._check_restriction_line(cr, uid, [x.id for x in tender.tender_line_ids if x.line_state != 'cancel'], context=context)
156
 
 
157
 
        return res
158
 
 
159
 
    def default_get(self, cr, uid, fields, context=None):
160
 
        '''
161
 
        Set default data
162
 
        '''
163
 
        # Object declaration
164
 
        partner_obj = self.pool.get('res.partner')
165
 
        user_obj = self.pool.get('res.users')
166
 
 
167
 
        res = super(tender, self).default_get(cr, uid, fields, context=context)
168
 
 
169
 
        # Get the delivery address
170
 
        company = user_obj.browse(cr, uid, uid, context=context).company_id
171
 
        res['delivery_address'] = partner_obj.address_get(cr, uid, company.partner_id.id, ['delivery'])['delivery']
172
 
 
173
 
        return res
174
 
 
175
 
    def _check_tender_from_fo(self, cr, uid, ids, context=None):
176
 
        if not context:
177
 
            context = {}
178
 
        retour = True
179
 
        for tender in self.browse(cr, uid, ids, context=context):
180
 
            if not tender.tender_from_fo:
181
 
                return retour
182
 
            for sup in tender.supplier_ids:
183
 
                if sup.partner_type == 'internal' :
184
 
                    retour = False
185
 
        return retour
186
 
 
187
 
    _constraints = [
188
 
        (_check_tender_from_fo, 'You cannot choose an internal supplier for this tender', []),
189
 
    ]
190
114
    
191
 
    def create(self, cr, uid, vals, context=None):
192
 
        '''
193
 
        Set the reference of the tender at this time
194
 
        '''
195
 
        if not vals.get('name', False):
196
 
            vals.update({'name': self.pool.get('ir.sequence').get(cr, uid, 'tender')})
197
 
 
198
 
        return super(tender, self).create(cr, uid, vals, context=context)
199
 
 
200
 
    def _check_service(self, cr, uid, ids, vals, context=None):
201
 
        '''
202
 
        Avoid the saving of a Tender with non service products on Service Tender
203
 
        '''
204
 
        if isinstance(ids, (int, long)):
205
 
            ids = [ids]
206
 
        categ = {'transport': _('Transport'),
207
 
                 'service': _('Service')}
208
 
        if context is None:
209
 
            context = {}
210
 
        if context.get('import_in_progress'):
211
 
            return True
212
 
        for tender in self.browse(cr, uid, ids, context=context):
213
 
            for line in tender.tender_line_ids:
214
 
                if line.line_state == 'cancel':
215
 
                    continue
216
 
                if vals.get('categ', tender.categ) == 'transport' and line.product_id and (line.product_id.type not in ('service', 'service_recep') or not line.product_id.transport_ok):
217
 
                    raise osv.except_osv(_('Error'), _('The product [%s]%s is not a \'Transport\' product. You can have only \'Transport\' products on a \'Transport\' tender. Please remove this line.') % (line.product_id.default_code, line.product_id.name))
218
 
                    return False
219
 
                elif vals.get('categ', tender.categ) == 'service' and line.product_id and line.product_id.type not in ('service', 'service_recep'):
220
 
                    raise osv.except_osv(_('Error'), _('The product [%s] %s is not a \'Service\' product. You can have only \'Service\' products on a \'Service\' tender. Please remove this line.') % (line.product_id.default_code, line.product_id.name))
221
 
                    return False
222
 
                
223
 
        return True
224
 
 
225
 
    def write(self, cr, uid, ids, vals, context=None):
226
 
        """
227
 
        Check consistency between lines and categ of tender
228
 
        """
229
 
        self._check_service(cr, uid, ids, vals, context=context)
230
 
        return super(tender, self).write(cr, uid, ids, vals, context=context)
231
 
 
232
 
    def onchange_categ(self, cr, uid, ids, categ, context=None):
233
 
        """ Check that the categ is compatible with the product
234
 
        @param categ: Changed value of categ.
235
 
        @return: Dictionary of values.
236
 
        """
237
 
        if isinstance(ids, (int, long)):
238
 
            ids = [ids]
239
 
        message = {}
240
 
        if ids and categ in ['service', 'transport']:
241
 
            # Avoid selection of non-service producs on Service Tender
242
 
            category = categ=='service' and 'service_recep' or 'transport'
243
 
            transport_cat = ''
244
 
            if category == 'transport':
245
 
                transport_cat = 'OR p.transport_ok = False'
246
 
            cr.execute('''SELECT p.default_code AS default_code, t.name AS name
247
 
                          FROM tender_line l
248
 
                            LEFT JOIN product_product p ON l.product_id = p.id
249
 
                            LEFT JOIN product_template pt ON p.product_tmpl_id = pt.id
250
 
                            LEFT JOIN tender t ON l.tender_id = t.id
251
 
                          WHERE (pt.type != 'service_recep' %s) AND t.id in (%s) LIMIT 1''' % (transport_cat, ','.join(str(x) for x in ids)))
252
 
            res = cr.fetchall()
253
 
            if res:
254
 
                cat_name = categ=='service' and 'Service' or 'Transport'
255
 
                message.update({'title': _('Warning'),
256
 
                                'message': _('The product [%s] %s is not a \'%s\' product. You can have only \'%s\' products on a \'%s\' tender. Please remove this line before saving.') % (res[0][0], res[0][1], cat_name, cat_name, cat_name)})
257
 
                
258
 
        return {'warning': message}
259
 
 
260
115
    def onchange_warehouse(self, cr, uid, ids, warehouse_id, context=None):
261
116
        '''
262
117
        on_change function for the warehouse
278
133
        pol_obj = self.pool.get('purchase.order.line')
279
134
        partner_obj = self.pool.get('res.partner')
280
135
        pricelist_obj = self.pool.get('product.pricelist')
281
 
        obj_data = self.pool.get('ir.model.data')
282
 
 
283
136
        # no suppliers -> raise error
284
137
        for tender in self.browse(cr, uid, ids, context=context):
285
138
            # check some supplier have been selected
286
139
            if not tender.supplier_ids:
287
140
                raise osv.except_osv(_('Warning !'), _('You must select at least one supplier!'))
288
 
            #utp-315: check that the suppliers are not inactive (I use a SQL request because the inactive partner are ignored with the browse)
289
 
            sql = """
290
 
            select tsr.supplier_id, rp.name, rp.active
291
 
            from tender_supplier_rel tsr
292
 
            left join res_partner rp
293
 
            on tsr.supplier_id = rp.id
294
 
            where tsr.tender_id=%s
295
 
            and rp.active=False
296
 
            """
297
 
            cr.execute(sql, (ids[0],))
298
 
            inactive_supplier_ids = cr.dictfetchall()
299
 
            if any(inactive_supplier_ids):
300
 
                raise osv.except_osv(_('Warning !'), _("You can't have inactive supplier! Please remove: %s"
301
 
                                                       ) % ' ,'.join([partner['name'] for partner in inactive_supplier_ids]))
302
141
            # check some products have been selected
303
 
            tender_line_ids = self.pool.get('tender.line').search(cr, uid, [('tender_id', '=', tender.id), ('line_state', '!=', 'cancel')], context=context)
 
142
            tender_line_ids = self.pool.get('tender.line').search(cr, uid, [('tender_id', '=', tender.id)], context=context)
304
143
            if not tender_line_ids:
305
144
                raise osv.except_osv(_('Warning !'), _('You must select at least one product!'))
306
145
            for supplier in tender.supplier_ids:
307
146
                # create a purchase order for each supplier
308
 
                address_id = partner_obj.address_get(cr, uid, [supplier.id], ['default'])['default']
 
147
                address_id = partner_obj.address_get(cr, uid, [supplier.id], ['delivery'])['delivery']
309
148
                if not address_id:
310
149
                    raise osv.except_osv(_('Warning !'), _('The supplier "%s" has no address defined!')%(supplier.name,))
311
150
                pricelist_id = supplier.property_product_pricelist_purchase.id
312
 
                values = {'origin': tender.sale_order_id and tender.sale_order_id.name + ';' + tender.name or tender.name,
 
151
                values = {'name': self.pool.get('ir.sequence').get(cr, uid, 'rfq'),
 
152
                          'origin': tender.sale_order_id and tender.sale_order_id.name + '/' + tender.name or tender.name,
313
153
                          'rfq_ok': True,
314
154
                          'partner_id': supplier.id,
315
155
                          'partner_address_id': address_id,
323
163
                          'priority': tender.priority,
324
164
                          'details': tender.details,
325
165
                          'delivery_requested_date': tender.requested_date,
326
 
                          'rfq_delivery_address': tender.delivery_address and tender.delivery_address.id or False,
327
166
                          }
328
167
                # create the rfq - dic is udpated for default partner_address_id at purchase.order level
329
 
                po_id = po_obj.create(cr, uid, values, context=dict(context, partner_id=supplier.id, rfq_ok=True))
 
168
                po_id = po_obj.create(cr, uid, values, context=dict(context, partner_id=supplier.id))
330
169
                
331
170
                for line in tender.tender_line_ids:
332
 
                    if line.line_state == 'cancel':
333
 
                        continue
334
 
 
335
 
                    if line.qty <= 0.00:
336
 
                        raise osv.except_osv(_('Error !'), _('You cannot generate RfQs for an line with a null quantity.'))
337
 
 
338
 
                    if line.product_id.id == obj_data.get_object_reference(cr, uid,'msf_doc_import', 'product_tbd')[1]:
339
 
                        raise osv.except_osv(_('Warning !'), _('You can\'t have "To Be Defined" for the product. Please select an existing product.'))
340
171
                    # create an order line for each tender line
341
172
                    price = pricelist_obj.price_get(cr, uid, [pricelist_id], line.product_id.id, line.qty, supplier.id, {'uom': line.product_uom.id})[pricelist_id]
342
173
                    newdate = datetime.strptime(line.date_planned, '%Y-%m-%d')
349
180
                              'date_planned': newdate.strftime('%Y-%m-%d'),
350
181
                              'notes': line.product_id.description_purchase,
351
182
                              'order_id': po_id,
352
 
                              'tender_line_id': line.id,
353
183
                              }
354
184
                    # create purchase order line
355
185
                    pol_id = pol_obj.create(cr, uid, values, context=context)
372
202
        '''
373
203
        # done all related rfqs
374
204
        wf_service = netsvc.LocalService("workflow")
375
 
        sol_obj = self.pool.get('sale.order.line')
376
 
        proc_obj = self.pool.get('procurement.order')
377
 
        date_tools = self.pool.get('date.tools')                                
378
 
        fields_tools = self.pool.get('fields.tools')                            
379
 
        db_date_format = date_tools.get_db_date_format(cr, uid, context=context)
380
 
 
381
205
        for tender in self.browse(cr, uid, ids, context=context):
382
206
            rfq_list = []
383
207
            for rfq in tender.rfq_ids:
391
215
                raise osv.except_osv(_('Warning !'), _("Generated RfQs must be Updated or Cancelled."))
392
216
            
393
217
            # integrity check, all lines must have purchase_order_line_id
394
 
            if not all([line.purchase_order_line_id.id for line in tender.tender_line_ids if line.line_state != 'cancel']):
 
218
            if not all([line.purchase_order_line_id.id for line in tender.tender_line_ids]):
395
219
                raise osv.except_osv(_('Error !'), _('All tender lines must have been compared!'))
396
 
 
397
 
            if tender.sale_order_id:
398
 
                # Update procurement order
399
 
                for line in tender.tender_line_ids:
400
 
                    if line.line_state == 'cancel':
401
 
                        proc_id = line.sale_order_line_id and line.sale_order_line_id.procurement_id and line.sale_order_line_id.procurement_id.id
402
 
                        if proc_id:
403
 
                            wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_cancel', cr)
404
 
                        continue
405
 
                    vals = {'product_id': line.product_id.id,
406
 
                            'product_uom': line.product_uom.id,
407
 
                            'product_uos': line.product_uom.id,
408
 
                            'product_qty': line.qty,
409
 
                            'price_unit': line.price_unit,
410
 
                            'product_uos_qty': line.qty}
411
 
                    if line.sale_order_line_id and line.sale_order_line_id.procurement_id:
412
 
                        proc_id = line.sale_order_line_id.procurement_id.id
413
 
                        proc_obj.write(cr, uid, [proc_id], vals, context=context)
414
 
                    else: # Create procurement order to add the lines in a PO
415
 
                        create_vals = vals.copy()
416
 
                        prep_lt = fields_tools.get_field_from_company(cr, uid, object='sale.order', field='preparation_lead_time', context=context)
417
 
                        rts = datetime.strptime(tender.sale_order_id.ready_to_ship_date, db_date_format)       
418
 
                        rts = rts - relativedelta(days=prep_lt or 0)                            
419
 
                        rts = rts.strftime(db_date_format)                                      
420
 
                        create_vals.update({'procure_method': 'make_to_order',
421
 
                                            'is_tender': True,
422
 
                                            'tender_id': tender.id,
423
 
                                            'tender_line_id': line.id,
424
 
                                            'price_unit': line.price_unit,
425
 
                                            'date_planned': rts,
426
 
                                            'origin': tender.sale_order_id.name,
427
 
                                            'supplier': line.purchase_order_line_id.order_id.partner_id.id,
428
 
                                            'name': '[%s] %s' % (line.product_id.default_code, line.product_id.name),
429
 
                                            'location_id': tender.sale_order_id.warehouse_id.lot_stock_id.id,
430
 
                                            'po_cft': 'cft',
431
 
                                            })
432
 
                        proc_id = proc_obj.create(cr, uid, create_vals, context=context)
433
 
                        wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
434
 
                        wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_check', cr)
435
 
                    
 
220
        
436
221
        # update product supplierinfo and pricelist
437
222
        self.update_supplier_info(cr, uid, ids, context=context, integrity_test=False,)
438
223
        # change tender state
476
261
            # gather the product_id -> supplier_id relationship to display it back in the compare wizard
477
262
            suppliers = {}
478
263
            for line in tender.tender_line_ids:
479
 
                if line.product_id and line.supplier_id and line.line_state != 'cancel':
 
264
                if line.product_id and line.supplier_id:
480
265
                    suppliers.update({line.product_id.id:line.supplier_id.id,})
481
266
            # rfq corresponding to this tender with done state (has been updated and not canceled)
482
267
            # the list of rfq which will be compared
500
285
            if integrity_test:
501
286
                self.tender_integrity(cr, uid, tender, context=context)
502
287
            for line in tender.tender_line_ids:
503
 
                if line.line_state == 'cancel':
504
 
                    continue
505
288
                # if a supplier has been selected
506
289
                if line.purchase_order_line_id:
507
290
                    # set the flag
581
364
            # check if corresponding rfqs are in the good state
582
365
            self.tender_integrity(cr, uid, tender, context=context)
583
366
            # integrity check, all lines must have purchase_order_line_id
584
 
            if not all([line.purchase_order_line_id.id for line in tender.tender_line_ids if line.line_state != 'cancel']):
 
367
            if not all([line.purchase_order_line_id.id for line in tender.tender_line_ids]):
585
368
                raise osv.except_osv(_('Error !'), _('All tender lines must have been compared!'))
586
369
            data = {}
587
370
            for line in tender.tender_line_ids:
588
 
                if line.line_state == 'cancel':
589
 
                    continue
590
371
                data.setdefault(line.supplier_id.id, {}) \
591
372
                    .setdefault('order_line', []).append((0,0,{'name': line.product_id.partner_ref,
592
373
                                                               'product_qty': line.qty,
600
381
                                                               }))
601
382
                    
602
383
                # fill data corresponding to po creation
603
 
                address_id = partner_obj.address_get(cr, uid, [line.supplier_id.id], ['default'])['default']
 
384
                address_id = partner_obj.address_get(cr, uid, [line.supplier_id.id], ['delivery'])['delivery']
604
385
                pricelist = line.supplier_id.property_product_pricelist_purchase.id,
605
386
                if line.currency_id:
606
387
                    price_ids = self.pool.get('product.pricelist').search(cr, uid, [('type', '=', 'purchase'), ('currency_id', '=', line.currency_id.id)], context=context)
607
388
                    if price_ids:
608
389
                        pricelist = price_ids[0]
609
 
                po_values = {'origin': (tender.sale_order_id and tender.sale_order_id.name or "") + '; ' + tender.name,
 
390
                po_values = {'origin': (tender.sale_order_id and tender.sale_order_id.name or "") + '/' + tender.name,
610
391
                             'partner_id': line.supplier_id.id,
611
392
                             'partner_address_id': address_id,
612
393
                             'location_id': tender.location_id.id,
620
401
                             'warehouse_id': tender.warehouse_id.id,
621
402
                             'details': tender.details,
622
403
                             'delivery_requested_date': tender.requested_date,
623
 
                             'dest_address_id': tender.delivery_address.id,
624
404
                             }
625
405
                data[line.supplier_id.id].update(po_values)
626
406
            
636
416
            self.done(cr, uid, [tender.id], context=context)
637
417
        
638
418
        return po_id
639
 
 
640
 
    def cancel_tender(self, cr, uid, ids, context=None):
641
 
        '''
642
 
        Ask the user if he wants to re-source all lines
643
 
        '''
644
 
        wiz_obj = self.pool.get('tender.cancel.wizard')
645
 
 
646
 
        if context is None:
647
 
            context = {}
648
 
 
649
 
        if isinstance(ids, (int, long)):
650
 
            ids = [ids]
651
 
 
652
 
        tender = self.read(cr, uid, ids[0], ['state'], context=context)
653
 
        wiz_id = wiz_obj.create(cr, uid, {'tender_id': tender['id'], 'not_draft': tender['state'] != 'draft'}, context=context)
654
 
 
655
 
        return {'type': 'ir.actions.act_window',
656
 
                'res_model': 'tender.cancel.wizard',
657
 
                'res_id': wiz_id,
658
 
                'view_mode': 'form',
659
 
                'view_type': 'form',
660
 
                'target': 'new',
661
 
                'context': context}
662
419
    
663
420
    def wkf_action_cancel(self, cr, uid, ids, context=None):
664
421
        '''
665
422
        cancel all corresponding rfqs
666
423
        '''
667
 
        if context is None:
668
 
            context = {}
669
 
 
670
424
        po_obj = self.pool.get('purchase.order')
671
 
        t_line_obj = self.pool.get('tender.line')
672
425
        wf_service = netsvc.LocalService("workflow")
673
426
        # set state
674
427
        self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
677
430
            rfq_ids = po_obj.search(cr, uid, [('tender_id', '=', tender.id),], context=context)
678
431
            for rfq_id in rfq_ids:
679
432
                wf_service.trg_validate(uid, 'purchase.order', rfq_id, 'purchase_cancel', cr)
680
 
 
681
 
            for line in tender.tender_line_ids:
682
 
                t_line_obj.cancel_sourcing(cr, uid, [line.id], context=context)
683
433
                
684
434
        return True
685
435
 
731
481
    
732
482
    _SELECTION_TENDER_STATE = [('draft', 'Draft'),('comparison', 'Comparison'), ('done', 'Closed'),]
733
483
    
734
 
    def on_product_change(self, cr, uid, id, product_id, uom_id, product_qty, context=None):
 
484
    def on_product_change(self, cr, uid, id, product_id, context=None):
735
485
        '''
736
486
        product is changed, we update the UoM
737
487
        '''
738
 
        if not context:
739
 
            context = {}
740
 
 
741
488
        prod_obj = self.pool.get('product.product')
742
489
        result = {'value': {}}
743
490
        if product_id:
744
 
            # Test the compatibility of the product with a tender
745
 
            result, test = prod_obj._on_change_restriction_error(cr, uid, product_id, field_name='product_id', values=result, vals={'constraints': ['external', 'esc', 'internal']}, context=context)
746
 
            if test:
747
 
                return result
748
 
 
749
 
            product = prod_obj.browse(cr, uid, product_id, context=context)
750
 
            result['value']['product_uom'] = product.uom_id.id
751
 
            result['value']['text_error'] = False
752
 
            result['value']['to_correct_ok'] = False
753
 
        
754
 
        res_qty = self.onchange_uom_qty(cr, uid, id, uom_id or result.get('value', {}).get('product_uom',False), product_qty)
755
 
        result['value']['qty'] = res_qty.get('value', {}).get('qty', product_qty)
756
 
        
757
 
        if uom_id:
758
 
            result['value']['product_uom'] = uom_id
759
 
 
 
491
            result['value']['product_uom'] = prod_obj.browse(cr, uid, product_id, context=context).uom_po_id.id
 
492
            
760
493
        return result
761
 
 
762
 
    def onchange_uom_qty(self, cr, uid, ids, uom_id, qty):
763
 
        '''
764
 
        Check round of qty according to the UoM
765
 
        '''
766
 
        res = {}
767
 
 
768
 
        if qty:
769
 
            res = self.pool.get('product.uom')._change_round_up_qty(cr, uid, uom_id, qty, 'qty', result=res)
770
 
 
771
 
        return res
772
494
    
773
495
    def _get_total_price(self, cr, uid, ids, field_name, arg, context=None):
774
496
        '''
805
527
    
806
528
    _columns = {'product_id': fields.many2one('product.product', string="Product", required=True),
807
529
                'qty': fields.float(string="Qty", required=True),
808
 
                'tender_id': fields.many2one('tender', string="Tender", required=True, ondelete='cascade'),
 
530
                'tender_id': fields.many2one('tender', string="Tender", required=True),
809
531
                'purchase_order_line_id': fields.many2one('purchase.order.line', string="Related RfQ line", readonly=True),
810
532
                'sale_order_line_id': fields.many2one('sale.order.line', string="Sale Order Line"),
811
533
                'product_uom': fields.many2one('product.uom', 'Product UOM', required=True),
812
534
                'date_planned': fields.related('tender_id', 'requested_date', type='date', string='Requested Date', store=False,),
813
535
                # functions
814
536
                'supplier_id': fields.related('purchase_order_line_id', 'order_id', 'partner_id', type='many2one', relation='res.partner', string="Supplier", readonly=True),
815
 
                'price_unit': fields.related('purchase_order_line_id', 'price_unit', type="float", string="Price unit", digits_compute=dp.get_precision('Purchase Price Computation'), readonly=True), # same precision as related field!
816
 
                'total_price': fields.function(_get_total_price, method=True, type='float', string="Total Price", digits_compute=dp.get_precision('Purchase Price'), multi='total'),
 
537
                'price_unit': fields.related('purchase_order_line_id', 'price_unit', type="float", string="Price unit", readonly=True),
 
538
                'total_price': fields.function(_get_total_price, method=True, type='float', string="Total Price", multi='total'),
817
539
                'currency_id': fields.function(_get_total_price, method=True, type='many2one', relation='res.currency', string='Cur.', multi='total'),
818
 
                'func_total_price': fields.function(_get_total_price, method=True, type='float', string="Func. Total Price", digits_compute=dp.get_precision('Purchase Price'), multi='total'),
 
540
                'func_total_price': fields.function(_get_total_price, method=True, type='float', string="Func. Total Price", multi='total'),
819
541
                'func_currency_id': fields.function(_get_total_price, method=True, type='many2one', relation='res.currency', string='Func. Cur.', multi='total'),
820
542
                'purchase_order_id': fields.related('purchase_order_line_id', 'order_id', type='many2one', relation='purchase.order', string="Related RfQ", readonly=True,),
821
 
                'purchase_order_line_number': fields.related('purchase_order_line_id', 'line_number', type="char", string="Related Line Number", readonly=True,),
 
543
                'purchase_order_line_number': fields.related('purchase_order_line_id', 'line_number', type="integer", string="Related Line Number", readonly=True,),
822
544
                'state': fields.related('tender_id', 'state', type="selection", selection=_SELECTION_TENDER_STATE, string="State",),
823
 
                'line_state': fields.selection([('draft','Draft'), ('cancel', 'Canceled'), ('done', 'Done')], string='State', readonly=True),
824
 
                'comment': fields.char(size=128, string='Comment'),
825
 
                'has_to_be_resourced': fields.boolean(string='Has to be resourced'),
826
 
                'created_by_rfq': fields.boolean(string='Created by RfQ'),
827
545
                }
828
546
    _defaults = {'qty': lambda *a: 1.0,
829
547
                 'state': lambda *a: 'draft',
830
 
                 'line_state': lambda *a: 'draft',
831
548
                 }
832
549
    
833
 
    def _check_restriction_line(self, cr, uid, ids, context=None):
834
 
        '''
835
 
        Check if there is no restrictive products in lines
836
 
        '''
837
 
        if isinstance(ids, (int, long)):
838
 
            ids = [ids]
839
 
 
840
 
        for line in self.browse(cr, uid, ids, context=context):
841
 
            if line.tender_id and line.product_id:
842
 
                if not self.pool.get('product.product')._get_restriction_error(cr, uid, line.product_id.id, vals={'constraints': ['external']}, context=context):
843
 
                    return False
844
 
 
845
 
        return True
846
 
 
847
 
    _sql_constraints = [
848
 
#        ('product_qty_check', 'CHECK( qty > 0 )', 'Product Quantity must be greater than zero.'),
849
 
    ]
850
 
 
851
 
 
852
 
    def copy(self, cr, uid, id, default=None, context=None):
853
 
        if default is None:
854
 
            default = {}
855
 
 
856
 
        if not 'created_by_rf' in default:
857
 
            default['created_by_rfq'] = False
858
 
 
859
 
        return super(tender_line, self).copy(cr, uid, id, default, context=context)
860
 
 
861
 
    def cancel_sourcing(self,cr, uid, ids, context=None):
862
 
        '''
863
 
        Cancel the line and re-source the FO line
864
 
        '''
865
 
        # Objects
866
 
        sol_obj = self.pool.get('sale.order.line')
867
 
        uom_obj = self.pool.get('product.uom')
868
 
        tender_obj = self.pool.get('tender')
869
 
 
870
 
        # Variables
871
 
        wf_service = netsvc.LocalService("workflow")
872
 
        to_remove = []
873
 
        to_cancel = []
874
 
        sol_ids = {}
875
 
        sol_to_update = {}
876
 
        so_to_update = set()
877
 
        tender_to_update = set()
878
 
 
879
 
        for line in self.browse(cr, uid, ids, context=context):
880
 
            tender_to_update.add(line.tender_id.id)
881
 
            if line.sale_order_line_id:
882
 
                so_to_update.add(line.sale_order_line_id.order_id.id)
883
 
                to_cancel.append(line.id)
884
 
                # Get the ID and the product qty of the FO line to re-source
885
 
                diff_qty = uom_obj._compute_qty(cr, uid, line.product_uom.id, line.qty, line.sale_order_line_id.product_uom.id)
886
 
 
887
 
                if line.has_to_be_resourced:
888
 
                    sol_ids.update({line.sale_order_line_id.id: diff_qty})
889
 
 
890
 
                sol_to_update.setdefault(line.sale_order_line_id.id, 0.00)
891
 
                sol_to_update[line.sale_order_line_id.id] += diff_qty
892
 
            elif line.tender_id.state == 'draft':
893
 
                to_remove.append(line.id)
894
 
            else:
895
 
                to_cancel.append(line.id)
896
 
 
897
 
        if to_cancel:
898
 
            self.write(cr, uid, to_cancel, {'line_state': 'cancel'}, context=context)
899
 
 
900
 
        if sol_ids:
901
 
            for sol in sol_ids:
902
 
                sol_obj.add_resource_line(cr, uid, sol, False, sol_ids[sol], context=context)
903
 
 
904
 
        # Update sale order lines
905
 
        for sol in sol_to_update:
906
 
            sol_obj.update_or_cancel_line(cr, uid, sol, sol_to_update[sol], context=context)
907
 
 
908
 
        # Update the FO state
909
 
        for so in so_to_update:
910
 
            wf_service.trg_write(uid, 'sale.order', so, cr)
911
 
 
912
 
        # UF-733: if all tender lines have been compared (have PO Line id), then set the tender to be ready
913
 
        # for proceeding to other actions (create PO, Done etc) 
914
 
        for tender in tender_obj.browse(cr, uid, list(tender_to_update), context=context):
915
 
            if tender.internal_state == 'draft':
916
 
                flag = True
917
 
                for line in tender.tender_line_ids:
918
 
                    if line.line_state != 'cancel' and not line.purchase_order_line_id:
919
 
                        flag = False
920
 
                if flag:
921
 
                    tender_obj.write(cr, uid, [tender.id], {'internal_state': 'updated'})
922
 
 
923
 
        if context.get('fake_unlink'):
924
 
            return to_remove
925
 
 
926
 
        return True
927
 
 
928
 
    def fake_unlink(self, cr, uid, ids, context=None):
929
 
        '''
930
 
        Cancel the line if it is linked to a FO line
931
 
        '''
932
 
        to_remove = self.cancel_sourcing(cr, uid, ids, context=dict(context, fake_unlink=True))
933
 
 
934
 
        return self.unlink(cr, uid, to_remove, context=context)
935
 
 
936
 
    def ask_unlink(self, cr, uid, ids, context=None):
937
 
        '''
938
 
        Ask user if he wants to re-source the needs
939
 
        '''
940
 
        # Objects
941
 
        wiz_obj = self.pool.get('tender.line.cancel.wizard')
942
 
 
943
 
        # Variables
944
 
        if context is None:
945
 
            context = {}
946
 
 
947
 
        if isinstance(ids, (int, long)):
948
 
            ids = [ids]
949
 
 
950
 
        tender_id = False
951
 
        for line in self.browse(cr, uid, ids, context=context):
952
 
            tender_id = line.tender_id.id
953
 
            if line.sale_order_line_id:
954
 
                wiz_id = wiz_obj.create(cr, uid, {'tender_line_id': line.id}, context=context)
955
 
        
956
 
                return {'type': 'ir.actions.act_window',
957
 
                        'res_model': 'tender.line.cancel.wizard',
958
 
                        'view_type': 'form',
959
 
                        'view_mode': 'form',
960
 
                        'res_id': wiz_id,
961
 
                        'target': 'new',
962
 
                        'context': context}
963
 
        
964
 
        self.fake_unlink(cr, uid, ids, context=context)
965
 
 
966
 
        return {'type': 'ir.actions.act_window',
967
 
                'res_model': 'tender',
968
 
                'view_type': 'form',
969
 
                'view_mode': 'form,tree',
970
 
                'res_id': tender_id,
971
 
                'target': 'crush',
972
 
                'context': context}
973
 
    
974
550
tender_line()
975
551
 
976
552
 
1008
584
        # reset the tender line
1009
585
        for line in result['tender_line_ids']:
1010
586
            line[2].update(sale_order_line_id=False,
1011
 
                           purchase_order_line_id=False,
1012
 
                           line_state='draft',)
 
587
                           purchase_order_line_id=False,)
1013
588
        return result
1014
589
 
1015
590
tender2()
1021
596
    '''
1022
597
    _inherit = 'procurement.order'
1023
598
    
1024
 
    def _is_tender_rfq(self, cr, uid, ids, field_name, arg, context=None):
 
599
    def _is_tender(self, cr, uid, ids, field_name, arg, context=None):
1025
600
        '''
1026
 
        tell if the corresponding sale order line is tender/rfq sourcing or not
 
601
        tell if the corresponding sale order line is tender sourcing or not
1027
602
        '''
1028
603
        result = {}
 
604
        for id in ids:
 
605
            result[id] = False
 
606
            
1029
607
        for proc in self.browse(cr, uid, ids, context=context):
1030
 
            result[proc.id] = {'is_tender': False, 'is_rfq': False}
1031
608
            for line in proc.sale_order_line_ids:
1032
 
                result[proc.id]['is_tender'] = line.po_cft == 'cft'
1033
 
                result[proc.id]['is_rfq'] = line.po_cft == 'rfq'
 
609
                result[proc.id] = line.po_cft == 'cft'
1034
610
                                
1035
611
        return result
1036
612
    
1037
 
    _columns = {'is_tender': fields.function(_is_tender_rfq, method=True, type='boolean', string='Is Tender', readonly=True, multi='tender_rfq'),
1038
 
                'is_rfq': fields.function(_is_tender_rfq, method=True, type='boolean', string='Is RfQ', readonly=True, multi='tender_rfq'),
 
613
    _columns = {'is_tender': fields.function(_is_tender, method=True, type='boolean', string='Is Tender', readonly=True,),
1039
614
                'sale_order_line_ids': fields.one2many('sale.order.line', 'procurement_id', string="Sale Order Lines"),
1040
615
                'tender_id': fields.many2one('tender', string='Tender', readonly=True),
1041
 
                'tender_line_id': fields.many2one('tender.line', string='Tender line', readonly=True),
1042
616
                'is_tender_done': fields.boolean(string="Tender Closed"),
1043
 
                'rfq_id': fields.many2one('purchase.order', string='RfQ', readonly=True),
1044
 
                'rfq_line_id': fields.many2one('purchase.order.line', string='RfQ line', readonly=True),
1045
 
                'is_rfq_done': fields.boolean(string="RfQ Closed"),
1046
617
                'state': fields.selection([('draft','Draft'),
1047
618
                                           ('confirmed','Confirmed'),
1048
619
                                           ('exception','Exception'),
1051
622
                                           ('ready','Ready'),
1052
623
                                           ('done','Closed'),
1053
624
                                           ('tender', 'Tender'),
1054
 
                                           ('rfq', 'Request for Quotation'),
1055
625
                                           ('waiting','Waiting'),], 'State', required=True,
1056
626
                                          help='When a procurement is created the state is set to \'Draft\'.\n If the procurement is confirmed, the state is set to \'Confirmed\'.\
1057
627
                                                \nAfter confirming the state is set to \'Running\'.\n If any exception arises in the order then the state is set to \'Exception\'.\n Once the exception is removed the state becomes \'Ready\'.\n It is in \'Waiting\'. state when the procurement is waiting for another one to finish.'),
1058
 
                'price_unit': fields.float('Unit Price from Tender', digits_compute=dp.get_precision('Purchase Price Computation')),
 
628
                'price_unit': fields.float('Unit Price from Tender', digits_compute= dp.get_precision('Purchase Price')),
1059
629
        }
1060
 
    _defaults = {
1061
 
        'is_tender_done': False,
1062
 
        'is_rfq_done': False,
1063
 
    }
1064
 
 
1065
 
    def wkf_action_rfq_create(self, cr, uid, ids, context=None):
1066
 
        '''
1067
 
        creation of rfq from procurement workflow
1068
 
        '''
1069
 
        rfq_obj = self.pool.get('purchase.order')
1070
 
        rfq_line_obj = self.pool.get('purchase.order.line')
1071
 
        partner_obj = self.pool.get('res.partner')
1072
 
 
1073
 
        if not context:
1074
 
            context = {}
1075
 
 
1076
 
        # find the corresponding sale order id for rfq
1077
 
        for proc in self.browse(cr, uid, ids, context=context):
1078
 
            if proc.rfq_id:
1079
 
                return proc.rfq_id
1080
 
            sale_order = False
1081
 
            sale_order_line = False
1082
 
            for sol in proc.sale_order_line_ids:
1083
 
                sale_order = sol.order_id
1084
 
                sale_order_line = sol
1085
 
                break
1086
 
            # find the rfq
1087
 
            rfq_id = False
1088
 
            # UTP-934: If source rfq to different supplier, different rfq must be created, and cannot be using the same rfq 
1089
 
            rfq_ids = rfq_obj.search(cr, uid, [('sale_order_id', '=', sale_order.id),('partner_id', '=', proc.supplier.id), ('state', '=', 'draft'), ('rfq_ok', '=', True),], context=context)
1090
 
            if rfq_ids:
1091
 
                rfq_id = rfq_ids[0]
1092
 
            # create if not found
1093
 
            if not rfq_id:
1094
 
                supplier = proc.supplier
1095
 
                company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
1096
 
                pricelist_id = supplier.property_product_pricelist_purchase.id
1097
 
                address_id = partner_obj.address_get(cr, uid, [supplier.id], ['default'])['default']
1098
 
                if not address_id:
1099
 
                    raise osv.except_osv(_('Warning !'), _('The supplier "%s" has no address defined!')%(supplier.name,))
1100
 
 
1101
 
                context['rfq_ok'] = True
1102
 
                rfq_id = rfq_obj.create(cr, uid, {'sale_order_id': sale_order.id,
1103
 
                                                  'categ': sale_order.categ,
1104
 
                                                  'priority': sale_order.priority,
1105
 
                                                  'fiscal_position': supplier.property_account_position and supplier.property_account_position.id or False,
1106
 
                                                  'rfq_delivery_address': partner_obj.address_get(cr, uid, company.partner_id.id, ['delivery'])['delivery'],
1107
 
                                                  'warehouse_id': sale_order.shop_id.warehouse_id.id,
1108
 
                                                  'location_id': proc.location_id.id,
1109
 
                                                  'partner_id': supplier.id,
1110
 
                                                  'partner_address_id': address_id,
1111
 
                                                  'pricelist_id': pricelist_id,
1112
 
                                                  'rfq_ok': True,
1113
 
                                                  'from_procurement': True,
1114
 
                                                  'order_type': sale_order.order_type,
1115
 
                                                  'origin': sale_order.name,}, context=context)
1116
 
 
1117
 
            # add a line to the RfQ
1118
 
            rfq_line_id = rfq_line_obj.create(cr, uid, {'product_id': proc.product_id.id,
1119
 
                                                        'comment': sale_order_line.comment,
1120
 
                                                        'name': sale_order_line.name,
1121
 
                                                        'price_unit': 0.00,
1122
 
                                                        'product_qty': proc.product_qty,
1123
 
                                                        'origin': sale_order.name,
1124
 
                                                        'order_id': rfq_id,
1125
 
                                                        'sale_order_line_id': sale_order_line.id,
1126
 
                                                        'location_id': proc.location_id.id,
1127
 
                                                        'product_uom': proc.product_uom.id,
1128
 
                                                        'procurement_id': proc.id,
1129
 
                                                        #'date_planned': proc.date_planned, # function at line level
1130
 
                                                        }, context=context)
1131
 
            
1132
 
            self.write(cr, uid, ids, {'rfq_id': rfq_id, 'rfq_line_id': rfq_line_id}, context=context)
1133
 
            
1134
 
            # log message concerning RfQ creation
1135
 
            rfq_obj.log(cr, uid, rfq_id, "The Request for Quotation '%s' has been created and must be completed before purchase order creation."%rfq_obj.browse(cr, uid, rfq_id, context=context).name, context={'rfq_ok': 1})
1136
 
        # state of procurement is Tender
1137
 
        self.write(cr, uid, ids, {'state': 'rfq'}, context=context)
1138
 
        
1139
 
        return rfq_id
 
630
    _defaults = {'is_tender_done': False,}
1140
631
    
1141
632
    def wkf_action_tender_create(self, cr, uid, ids, context=None):
1142
633
        '''
1146
637
        tender_line_obj = self.pool.get('tender.line')
1147
638
        # find the corresponding sale order id for tender
1148
639
        for proc in self.browse(cr, uid, ids, context=context):
1149
 
            if proc.tender_id:
1150
 
                return proc.tender_id
1151
640
            sale_order = False
1152
641
            sale_order_line = False
1153
642
            for sol in proc.sale_order_line_ids:
1168
657
                                                        'requested_date': proc.date_planned,
1169
658
                                                        }, context=context)
1170
659
            # add a line to the tender
1171
 
            tender_line_id = tender_line_obj.create(cr, uid, {'product_id': proc.product_id.id,
1172
 
                                                              'comment': sale_order_line.comment,
1173
 
                                                              'qty': proc.product_qty,
1174
 
                                                              'tender_id': tender_id,
1175
 
                                                              'sale_order_line_id': sale_order_line.id,
1176
 
                                                              'location_id': proc.location_id.id,
1177
 
                                                              'product_uom': proc.product_uom.id,
1178
 
                                                              #'date_planned': proc.date_planned, # function at line level
1179
 
                                                              }, context=context)
 
660
            tender_line_obj.create(cr, uid, {'product_id': proc.product_id.id,
 
661
                                             'qty': proc.product_qty,
 
662
                                             'tender_id': tender_id,
 
663
                                             'sale_order_line_id': sale_order_line.id,
 
664
                                             'location_id': proc.location_id.id,
 
665
                                             'product_uom': proc.product_uom.id,
 
666
                                             #'date_planned': proc.date_planned, # function at line level
 
667
                                             }, context=context)
1180
668
            
1181
 
            self.write(cr, uid, ids, {'tender_id': tender_id, 'tender_line_id': tender_line_id}, context=context)
 
669
            self.write(cr, uid, ids, {'tender_id': tender_id}, context=context)
1182
670
            
1183
671
            # log message concerning tender creation
1184
672
            tender_obj.log(cr, uid, tender_id, "The tender '%s' has been created and must be completed before purchase order creation."%tender_obj.browse(cr, uid, tender_id, context=context).name)
1193
681
        '''
1194
682
        self.write(cr, uid, ids, {'is_tender_done': True, 'state': 'exception',}, context=context)
1195
683
        return True
1196
 
 
1197
 
    def wkf_action_rfq_done(self, cr, uid, ids, context=None):
1198
 
        '''
1199
 
        set is_rfq_done value
1200
 
        '''
1201
 
        self.write(cr, uid, ids, {'is_rfq_done': True, 'state': 'exception',}, context=context)
1202
 
        return True
1203
684
    
1204
685
    def action_po_assign(self, cr, uid, ids, context=None):
1205
686
        '''
1207
688
        - add message at po creation during on_order workflow
1208
689
        '''
1209
690
        po_obj = self.pool.get('purchase.order')
1210
 
        sol_obj = self.pool.get('sale.order.line')
1211
 
 
1212
 
        # If the line has been created by a confirmed PO, doesn't create a new PO
1213
 
        sol_ids = sol_obj.search(cr, uid, [('procurement_id', 'in', ids), ('created_by_po', '!=', False)], context=context)
1214
 
        if sol_ids:
1215
 
            return sol_obj.read(cr, uid, sol_ids[0], ['created_by_po'], context=context)['created_by_po'][0]
1216
 
 
1217
691
        result = super(procurement_order, self).action_po_assign(cr, uid, ids, context=context)
1218
692
        # The quotation 'SO001' has been converted to a sales order.
1219
693
        if result:
1221
695
            data = self.read(cr, uid, ids, ['so_back_update_dest_po_id_procurement_order'], context=context)
1222
696
            if not data[0]['so_back_update_dest_po_id_procurement_order']:
1223
697
                po_obj.log(cr, uid, result, "The Purchase Order '%s' has been created following 'on order' sourcing."%po_obj.browse(cr, uid, result, context=context).name)
 
698
            if self.browse(cr, uid, ids[0], context=context).is_tender:
 
699
                wf_service = netsvc.LocalService("workflow")
 
700
                wf_service.trg_validate(uid, 'purchase.order', result, 'purchase_confirm', cr)
1224
701
        return result
1225
702
    
 
703
    def create_po_hook(self, cr, uid, ids, context=None, *args, **kwargs):
 
704
        '''
 
705
        if the procurement corresponds to a tender, the created po is confirmed but not validated
 
706
        '''
 
707
        po_obj = self.pool.get('purchase.order')
 
708
        procurement = kwargs['procurement']
 
709
        purchase_id = super(procurement_order, self).create_po_hook(cr, uid, ids, context=context, *args, **kwargs)
 
710
        if purchase_id:
 
711
            # if tender
 
712
            if procurement.is_tender:
 
713
                wf_service = netsvc.LocalService("workflow")
 
714
                wf_service.trg_validate(uid, 'purchase.order', purchase_id, 'purchase_confirm', cr)
 
715
        return purchase_id
 
716
    
1226
717
    def po_values_hook(self, cr, uid, ids, context=None, *args, **kwargs):
1227
718
        '''
1228
719
        data for the purchase order creation
1229
720
        '''
1230
721
        values = super(procurement_order, self).po_values_hook(cr, uid, ids, context=context, *args, **kwargs)
1231
722
        procurement = kwargs['procurement']
1232
 
 
1233
 
        values['partner_address_id'] = self.pool.get('res.partner').address_get(cr, uid, [values['partner_id']], ['default'])['default']
1234
 
 
1235
 
        # set tender link in purchase order
1236
 
        if procurement.tender_id:
1237
 
            values['origin_tender_id'] = procurement.tender_id.id
1238
 
 
1239
 
        # set rfq link in purchase order
1240
 
        if procurement.rfq_id:
1241
 
            values['origin_rfq_id'] = procurement.rfq_id.id
1242
 
 
1243
 
        values['date_planned'] = procurement.date_planned
1244
723
        
1245
 
        if procurement.product_id:
1246
 
            if procurement.product_id.type == 'consu':
1247
 
                values['location_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock_override', 'stock_location_non_stockable')[1]
1248
 
            elif procurement.product_id.type == 'service_recep':
1249
 
                values['location_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'msf_config_locations', 'stock_location_service')[1]
1250
 
            else:
1251
 
                wh_ids = self.pool.get('stock.warehouse').search(cr, uid, [])
1252
 
                if wh_ids:
1253
 
                    values['location_id'] = self.pool.get('stock.warehouse').browse(cr, uid, wh_ids[0]).lot_input_id.id
1254
 
                else:
1255
 
                    values['location_id'] = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'msf_config_locations', 'stock_location_service')[1]
 
724
        values['date_planned'] = procurement.date_planned 
1256
725
        
1257
726
        return values
1258
727
    
1272
741
            if obj.state == 'rfq_updated' and not obj.valid_till:
1273
742
                return False
1274
743
        return True
1275
 
 
1276
744
    _columns = {'tender_id': fields.many2one('tender', string="Tender", readonly=True),
1277
 
                'rfq_delivery_address': fields.many2one('res.partner.address', string='Delivery address'),
1278
745
                'origin_tender_id': fields.many2one('tender', string='Tender', readonly=True),
1279
 
                'from_procurement': fields.boolean(string='RfQ created by a procurement order'),
1280
746
                'rfq_ok': fields.boolean(string='Is RfQ ?'),
1281
747
                'state': fields.selection(PURCHASE_ORDER_STATE_SELECTION, 'State', readonly=True, help="The state of the purchase order or the quotation request. A quotation is a purchase order in a 'Draft' state. Then the order has to be confirmed by the user, the state switch to 'Confirmed'. Then the supplier must confirm the order to change the state to 'Approved'. When the purchase order is paid and received, the state becomes 'Closed'. If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception.", select=True),
1282
748
                'valid_till': fields.date(string='Valid Till', states={'rfq_updated': [('required', True), ('readonly', True)], 'rfq_sent':[('required',False), ('readonly', False),]}, readonly=True,),
1283
749
                # add readonly when state is Done
1284
 
                'sale_order_id': fields.many2one('sale.order', string='Link between RfQ and FO', readonly=True),
1285
750
                }
1286
751
 
1287
752
    _defaults = {
1288
753
                'rfq_ok': lambda self, cr, uid, c: c.get('rfq_ok', False),
 
754
                'name': lambda obj, cr, uid, c: obj.pool.get('ir.sequence').get(cr, uid, c.get('rfq_ok', False) and 'rfq' or 'purchase.order'),
1289
755
                 }
1290
756
    
1291
757
    _constraints = [
1292
758
        (_check_valid_till,
1293
759
            'You must specify a Valid Till date.',
1294
760
            ['valid_till']),]
1295
 
 
1296
 
    def default_get(self, cr, uid, fields, context=None):
1297
 
        '''
1298
 
        Set default data
1299
 
        '''
1300
 
        # Object declaration
1301
 
        partner_obj = self.pool.get('res.partner')
1302
 
        user_obj = self.pool.get('res.users')
1303
 
 
1304
 
        res = super(purchase_order, self).default_get(cr, uid, fields, context=context)
1305
 
 
1306
 
        # Get the delivery address
1307
 
        company = user_obj.browse(cr, uid, uid, context=context).company_id
1308
 
        res['rfq_delivery_address'] = partner_obj.address_get(cr, uid, company.partner_id.id, ['delivery'])['delivery']
1309
 
 
1310
 
        return res
1311
 
 
1312
 
    def create(self, cr, uid, vals, context=None):
1313
 
        '''
1314
 
        Set the reference at this step
1315
 
        '''
1316
 
        if context is None:
1317
 
            context = {}
1318
 
        if context.get('rfq_ok', False) and not vals.get('name', False):
1319
 
            vals.update({'name': self.pool.get('ir.sequence').get(cr, uid, 'rfq')})
1320
 
        elif not vals.get('name', False):
1321
 
            vals.update({'name': self.pool.get('ir.sequence').get(cr, uid, 'purchase.order')})
1322
 
 
1323
 
        return super(purchase_order, self).create(cr, uid, vals, context=context)
1324
761
    
1325
762
    def unlink(self, cr, uid, ids, context=None):
1326
763
        '''
1347
784
        HOOK from purchase>purchase.py for COPY function. Modification of default copy values
1348
785
        define which name value will be used
1349
786
        '''
1350
 
        # default values from copy function
1351
 
        default = kwargs.get('default', False)
1352
 
        # flag defining if the new object will be a rfq
1353
 
        is_rfq = False
1354
 
        # calling super function
1355
787
        result = super(purchase_order, self)._hook_copy_name(cr, uid, ids, context=context, *args, **kwargs)
1356
 
        if default.get('rfq_ok', False):
1357
 
            is_rfq = True
1358
 
        elif 'rfq_ok' not in default:
1359
 
            for obj in self.browse(cr, uid, ids, context=context):
1360
 
                # if rfq_ok is specified as default value for new object, we base our decision on this value
1361
 
                if obj.rfq_ok:
1362
 
                    is_rfq = True
1363
 
        if is_rfq:
1364
 
            result.update(name=self.pool.get('ir.sequence').get(cr, uid, 'rfq'))
 
788
        for obj in self.browse(cr, uid, ids, context=context):
 
789
            if obj.rfq_ok:
 
790
                result.update(name=self.pool.get('ir.sequence').get(cr, uid, 'rfq'))
1365
791
        return result
1366
792
 
1367
793
    def hook_rfq_sent_check_lines(self, cr, uid, ids, context=None):
1372
798
        '''
1373
799
        res = True
1374
800
        return res
1375
 
 
 
801
        
1376
802
        
1377
803
    def rfq_sent(self, cr, uid, ids, context=None):
1378
 
        if not ids:
1379
 
            return {}
1380
 
        if isinstance(ids, (int, long)):
1381
 
            ids = [ids]
1382
804
        self.hook_rfq_sent_check_lines(cr, uid, ids, context=context)
1383
805
        for rfq in self.browse(cr, uid, ids, context=context):
1384
806
            wf_service = netsvc.LocalService("workflow")
1387
809
        self.write(cr, uid, ids, {'date_confirm': time.strftime('%Y-%m-%d')}, context=context)
1388
810
 
1389
811
        datas = {'ids': ids}
1390
 
        if len(ids) == 1:
1391
 
            # UFTP-92: give a name to report when generated from RfQ worklow sent_rfq stage
1392
 
            datas['target_filename'] = 'RFQ_' + rfq.name
1393
812
 
1394
813
        return {'type': 'ir.actions.report.xml',
1395
814
                'report_name': 'msf.purchase.quotation',
1396
815
                'datas': datas}
1397
816
 
1398
817
    def check_rfq_updated(self, cr, uid, ids, context=None):
1399
 
        tl_obj = self.pool.get('tender.line')
1400
 
        line_obj = self.pool.get('purchase.order.line')
1401
 
 
1402
818
        if isinstance(ids, (int, long)):
1403
819
            ids = [ids]
1404
820
 
1407
823
            if not rfq.valid_till:
1408
824
                raise osv.except_osv(_('Error'), _('You must specify a Valid Till date.'))
1409
825
 
1410
 
            if rfq.rfq_ok and rfq.tender_id:
1411
 
                for line in rfq.order_line:
1412
 
                    if not line.tender_line_id:
1413
 
                        tl_ids = tl_obj.search(cr, uid, [('product_id', '=', line.product_id.id), ('tender_id', '=', rfq.tender_id.id), ('line_state', '=', 'draft')], context=context)
1414
 
                        if tl_ids:
1415
 
                            tl_id = tl_ids[0]
1416
 
                        else:
1417
 
                            tl_vals = {'product_id': line.product_id.id,
1418
 
                                       'product_uom': line.product_uom.id,
1419
 
                                       'qty': line.product_qty,
1420
 
                                       'tender_id': rfq.tender_id.id,
1421
 
                                       'created_by_rfq': True}
1422
 
                            tl_id = tl_obj.create(cr, uid, tl_vals, context=context)
1423
 
                        line_obj.write(cr, uid, [line.id], {'tender_line_id': tl_id}, context=context)
1424
 
 
1425
826
            wf_service.trg_validate(uid, 'purchase.order', rfq.id, 'rfq_updated', cr)
1426
827
 
1427
 
        return {
1428
 
            'type': 'ir.actions.act_window',
1429
 
            'res_model': 'purchase.order',
1430
 
            'view_mode': 'form,tree,graph,calendar',
1431
 
            'view_type': 'form',
1432
 
            'target': 'crush',
1433
 
            'context': {'rfq_ok': True, 'search_default_draft_rfq': 1},
1434
 
            'domain': [('rfq_ok', '=', True)],
1435
 
            'res_id': rfq.id,
1436
 
        }
 
828
        return {'type': 'ir.actions.act_window',
 
829
                'res_model': 'purchase.order',
 
830
                'view_mode': 'form,tree,graph,calendar',
 
831
                'view_type': 'form',
 
832
                'target': 'crush',
 
833
                'context': {'rfq_ok': True, 'search_default_draft_rfq': 1,},
 
834
                'domain': [('rfq_ok', '=', True)],
 
835
                'res_id': rfq.id}
1437
836
        
1438
837
    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
1439
838
        """
1461
860
        if view_type == 'form':
1462
861
            if context.get('rfq_ok', False):
1463
862
                # the title of the screen depends on po type
1464
 
                form = etree.fromstring(result['arch'])
1465
 
                
1466
 
                fields = form.xpath('//form[@string="%s"]' % _('Purchase Order'))
1467
 
                for field in fields:
1468
 
                    field.set('string', _("Request for Quotation"))
1469
 
                
1470
 
                fields2 = form.xpath('//page[@string="%s"]' % _('Purchase Order'))
1471
 
                for field2 in fields2:
1472
 
                    field2.set('string', _("Request for Quotation"))
1473
 
 
1474
 
                result['arch'] = etree.tostring(form)
 
863
                arch = result['arch']
 
864
                arch = arch.replace('<form string="Purchase Order">', '<form string="Requests for Quotation">')
 
865
                result['arch'] = arch
1475
866
        
1476
867
        return result
1477
868
 
1478
 
    def wkf_act_rfq_done(self, cr, uid, ids, context=None):
1479
 
        '''
1480
 
        Set the state to done and update the price unit in the procurement order
1481
 
        '''
1482
 
        wf_service = netsvc.LocalService("workflow")
1483
 
        proc_obj = self.pool.get('procurement.order')
1484
 
        date_tools = self.pool.get('date.tools')
1485
 
        fields_tools = self.pool.get('fields.tools')
1486
 
        db_date_format = date_tools.get_db_date_format(cr, uid, context=context)
1487
 
 
1488
 
        if isinstance(ids, (int, long)):
1489
 
            ids = [ids]
1490
 
 
1491
 
        for rfq in self.browse(cr, uid, ids, context=context):
1492
 
            if rfq.from_procurement:
1493
 
                for line in rfq.order_line:
1494
 
                    if line.procurement_id:
1495
 
                        self.pool.get('procurement.order').write(cr, uid, [line.procurement_id.id], {'price_unit': line.price_unit}, context=context)
1496
 
                    elif not rfq.tender_id:
1497
 
                        prep_lt = fields_tools.get_field_from_company(cr, uid, object='sale.order', field='preparation_lead_time', context=context)
1498
 
                        rts = datetime.strptime(rfq.sale_order_id.ready_to_ship_date, db_date_format)
1499
 
                        rts = rts - relativedelta(days=prep_lt or 0)
1500
 
                        rts = rts.strftime(db_date_format)
1501
 
                        vals = {'product_id': line.product_id.id,
1502
 
                                'product_uom': line.product_uom.id,
1503
 
                                'product_uos': line.product_uom.id,
1504
 
                                'product_qty': line.product_qty,
1505
 
                                'product_uos_qty': line.product_qty,
1506
 
                                'price_unit': line.price_unit,
1507
 
                                'procure_method': 'make_to_order',
1508
 
                                'is_rfq': True,
1509
 
                                'rfq_id': rfq.id,
1510
 
                                'rfq_line_id': line.id,
1511
 
                                'is_tender': False,
1512
 
                                'tender_id': False,
1513
 
                                'tender_line_id': False,
1514
 
                                'date_planned': rts,
1515
 
                                'origin': rfq.sale_order_id.name,
1516
 
                                'supplier': rfq.partner_id.id,
1517
 
                                'name': '[%s] %s' % (line.product_id.default_code, line.product_id.name),
1518
 
                                'location_id': rfq.sale_order_id.warehouse_id.lot_stock_id.id,
1519
 
                                'po_cft': 'rfq',
1520
 
                                }
1521
 
                        proc_id = proc_obj.create(cr, uid, vals, context=context)
1522
 
                        wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_confirm', cr)
1523
 
                        wf_service.trg_validate(uid, 'procurement.order', proc_id, 'button_check', cr)
1524
 
 
1525
 
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)
1526
 
 
1527
869
purchase_order()
1528
870
 
1529
871
 
1533
875
    '''
1534
876
    _inherit = 'purchase.order.line'
1535
877
    _columns = {'tender_id': fields.related('order_id', 'tender_id', type='many2one', relation='tender', string='Tender',),
1536
 
                'tender_line_id': fields.many2one('tender.line', string='Tender Line'),
1537
878
                'rfq_ok': fields.related('order_id', 'rfq_ok', type='boolean', string='RfQ ?'),
1538
 
                'sale_order_line_id': fields.many2one('sale.order.line', string='FO line', readonly=True),
1539
879
                }
1540
880
    
1541
 
    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
1542
 
        """
1543
 
        columns for the tree
1544
 
        """
1545
 
        if context is None:
1546
 
            context = {}
1547
 
 
1548
 
        # call super
1549
 
        result = super(purchase_order_line, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
1550
 
        if view_type == 'form':
1551
 
            if context.get('rfq_ok', False):
1552
 
                # the title of the screen depends on po type
1553
 
                form = etree.fromstring(result['arch'])
1554
 
                fields = form.xpath('//form[@string="%s"]' % _('Purchase Order Line'))
1555
 
                for field in fields:
1556
 
                    field.set('string', _("Request for Quotation Line"))
1557
 
                result['arch'] = etree.tostring(form)
1558
 
        
1559
 
        return result
1560
 
 
1561
881
purchase_order_line()
1562
882
 
1563
883
 
1568
888
    _inherit = 'sale.order.line'
1569
889
    
1570
890
    _columns = {'tender_line_ids': fields.one2many('tender.line', 'sale_order_line_id', string="Tender Lines", readonly=True),}
1571
 
 
1572
 
    def copy(self, cr, uid, ids, default, context=None):
1573
 
        '''
1574
 
        Remove tender lines linked
1575
 
        '''
1576
 
        default = default or {}
1577
 
 
1578
 
        if not 'tender_line_ids' in default:
1579
 
            default['tender_line_ids'] = []
1580
 
 
1581
 
        return super(sale_order_line, self).copy(cr, uid, ids, default, context=context)
1582
891
    
1583
892
sale_order_line()
1584
893
 
1597
906
        return res
1598
907
    
1599
908
    _inherit = 'pricelist.partnerinfo'
1600
 
    _columns = {'price': fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Purchase Price Computation'), help="This price will be considered as a price for the supplier UoM if any or the default Unit of Measure of the product otherwise"),
1601
 
                'currency_id': fields.many2one('res.currency', string='Currency', required=True, domain="[('partner_currency', '=', partner_id)]", select=True),
 
909
    _columns = {'currency_id': fields.many2one('res.currency', string='Currency', required=True, domain="[('partner_currency', '=', partner_id)]"),
1602
910
                'valid_till': fields.date(string="Valid Till",),
1603
911
                'comment': fields.char(size=128, string='Comment'),
1604
912
                'purchase_order_id': fields.related('purchase_order_line_id', 'order_id', type='many2one', relation='purchase.order', string="Related RfQ", readonly=True,),
1608
916
                }
1609
917
pricelist_partnerinfo()
1610
918
 
1611
 
 
1612
 
class tender_line_cancel_wizard(osv.osv_memory):
1613
 
    _name = 'tender.line.cancel.wizard'
1614
 
 
1615
 
    _columns = {
1616
 
        'tender_line_id': fields.many2one('tender.line', string='Tender line', required=True),
1617
 
    }
1618
 
 
1619
 
 
1620
 
    def just_cancel(self, cr, uid, ids, context=None):
1621
 
        '''
1622
 
        Cancel the line 
1623
 
        '''
1624
 
        # Objects
1625
 
        line_obj = self.pool.get('tender.line')
1626
 
        tender_obj = self.pool.get('tender')
1627
 
        data_obj = self.pool.get('ir.model.data')
1628
 
        tender_wiz_obj = self.pool.get('tender.cancel.wizard')
1629
 
 
1630
 
        # Variables
1631
 
        if context is None:
1632
 
            context = {}
1633
 
 
1634
 
        if isinstance(ids, (int, long)):
1635
 
            ids = [ids]
1636
 
 
1637
 
        line_ids = []
1638
 
        tender_ids = set()
1639
 
        for wiz in self.browse(cr, uid, ids, context=context):
1640
 
            tender_ids.add(wiz.tender_line_id.tender_id.id)
1641
 
            line_ids.append(wiz.tender_line_id.id)
1642
 
 
1643
 
        if context.get('has_to_be_resourced'):
1644
 
            line_obj.write(cr, uid, line_ids, {'has_to_be_resourced': True}, context=context)
1645
 
 
1646
 
        line_obj.fake_unlink(cr, uid, line_ids, context=context)
1647
 
 
1648
 
        for tender in tender_obj.browse(cr, uid, list(tender_ids), context=context):
1649
 
            if all(x.line_state in ('cancel', 'done') for x in tender.tender_line_ids):
1650
 
                wiz_id = tender_wiz_obj.create(cr, uid, {'tender_id': tender.id}, context=context)
1651
 
                view_id = data_obj.get_object_reference(cr, uid, 'tender_flow', 'ask_tender_cancel_wizard_form_view')[1]
1652
 
                return {'type': 'ir.actions.act_window',
1653
 
                        'res_model': 'tender.cancel.wizard',
1654
 
                        'view_type': 'form',
1655
 
                        'view_mode': 'form',
1656
 
                        'view_id': [view_id],
1657
 
                        'res_id': wiz_id,
1658
 
                        'target': 'new',
1659
 
                        'context': context}
1660
 
 
1661
 
        return {'type': 'ir.actions.act_window_close'}
1662
 
 
1663
 
    def cancel_and_resource(self, cr, uid, ids, context=None):
1664
 
        '''
1665
 
        Flag the line to be re-sourced and run cancel method
1666
 
        '''
1667
 
        # Objects
1668
 
        if context is None:
1669
 
            context = {}
1670
 
 
1671
 
        context['has_to_be_resourced'] = True
1672
 
 
1673
 
        return self.just_cancel(cr, uid, ids, context=context)
1674
 
 
1675
 
tender_line_cancel_wizard()
1676
 
 
1677
 
 
1678
 
class tender_cancel_wizard(osv.osv_memory):
1679
 
    _name = 'tender.cancel.wizard'
1680
 
 
1681
 
    _columns = {
1682
 
        'tender_id': fields.many2one('tender', string='Tender', required=True),
1683
 
        'not_draft': fields.boolean(string='Tender not draft'),
1684
 
    }
1685
 
 
1686
 
    def just_cancel(self, cr, uid, ids, context=None):
1687
 
        '''
1688
 
        Just cancel the wizard and the lines
1689
 
        '''
1690
 
        # Objects
1691
 
        line_obj = self.pool.get('tender.line')
1692
 
 
1693
 
        # Variables
1694
 
        if context is None:
1695
 
            context = {}
1696
 
 
1697
 
        if isinstance(ids, (int, long)):
1698
 
            ids = [ids]
1699
 
 
1700
 
        wf_service = netsvc.LocalService("workflow")
1701
 
        line_ids = []
1702
 
        tender_ids = []
1703
 
        rfq_ids = []
1704
 
        for wiz in self.browse(cr, uid, ids, context=context):
1705
 
            tender_ids.append(wiz.tender_id.id)
1706
 
            for line in wiz.tender_id.tender_line_ids:
1707
 
                line_ids.append(line.id)
1708
 
            for rfq in wiz.tender_id.rfq_ids:
1709
 
                rfq_ids.append(rfq.id)
1710
 
 
1711
 
        if context.get('has_to_be_resourced'):
1712
 
            line_obj.write(cr, uid, line_ids, {'has_to_be_resourced': True}, context=context)
1713
 
 
1714
 
        line_obj.fake_unlink(cr, uid, line_ids, context=context)
1715
 
 
1716
 
        for rfq in rfq_ids:
1717
 
            wf_service.trg_validate(uid, 'purchase.order', rfq, 'purchase_cancel', cr)
1718
 
 
1719
 
        for tender in tender_ids:
1720
 
            wf_service.trg_validate(uid, 'tender', tender, 'tender_cancel', cr)
1721
 
 
1722
 
        return {'type': 'ir.actions.act_window_close'}
1723
 
 
1724
 
    def cancel_and_resource(self, cr, uid, ids, context=None):
1725
 
        '''
1726
 
        Flag the line to be re-sourced and run cancel method
1727
 
        '''
1728
 
        # Objects
1729
 
        if context is None:
1730
 
            context = {}
1731
 
 
1732
 
        context['has_to_be_resourced'] = True
1733
 
 
1734
 
        return self.just_cancel(cr, uid, ids, context=context)
1735
 
 
1736
 
    def close_window(self, cr, uid, ids, context=None):
1737
 
        '''
1738
 
        Just close the wizard and reload the tender
1739
 
        '''
1740
 
        return {'type': 'ir.actions.act_window_close'}
1741
 
 
1742
 
tender_cancel_wizard()
1743
 
 
1744
 
 
1745
 
 
1746
919
class ir_values(osv.osv):
1747
920
    _name = 'ir.values'
1748
921
    _inherit = 'ir.values'
1753
926
        values = super(ir_values, self).get(cr, uid, key, key2, models, meta, context, res_id_req, without_user, key2_req)
1754
927
        new_values = values
1755
928
        
1756
 
        po_accepted_values = {'client_action_multi': ['Order Follow Up',
 
929
        po_accepted_values = {'client_action_multi': ['ir_open_purchase_order_follow_up', 
1757
930
                                                      'action_view_purchase_order_group'],
1758
931
                              'client_print_multi': ['Purchase Order (Merged)', 
1759
932
                                                     'Purchase Order',
1770
943
                               'client_action_relate': [],
1771
944
                               'tree_but_action': [],
1772
945
                               'tree_but_open': []}
 
946
        
1773
947
        if context.get('purchase_order', False) and 'purchase.order' in [x[0] for x in models]:
1774
948
            new_values = []
1775
949
            for v in values:
1776
950
                if key == 'action' and v[1] in po_accepted_values[key2] \
1777
 
                or v[1] == 'Purchase Order Excel Export' \
1778
 
                or v[1] == 'Purchase Order' \
1779
 
                or v[1] == 'Purchase Order (Merged)' \
1780
 
                or v[1] == 'Allocation report' \
1781
 
                or v[1] == 'Order impact vs. Budget' :
 
951
                or v[2]['name'] == 'Purchase Order Excel Export' \
 
952
                or v[2]['name'] == 'Purchase Order' \
 
953
                or v[2]['name'] == 'Purchase Order (Merged)' \
 
954
                or v[2]['name'] == 'Allocation report' \
 
955
                or v[2]['name'] == 'Order impact vs. Budget' :
1782
956
                    new_values.append(v)
1783
957
        elif context.get('request_for_quotation', False) and 'purchase.order' in [x[0] for x in models]:
1784
958
            new_values = []
1785
959
            for v in values:
1786
960
                if key == 'action' and v[1] in rfq_accepted_values[key2] \
1787
 
                or v[1] == 'Request for Quotation' \
1788
 
                or v[1] == 'Request For Quotation Excel Export' :
 
961
                or v[2]['name'] == 'Request for Quotation' \
 
962
                or v[2]['name'] == 'Request For Quotation Excel Export' :
1789
963
                    new_values.append(v)
1790
964
 
1791
965
        return new_values
1792
966
 
1793
 
ir_values()
 
967
ir_values()
 
 
b'\\ No newline at end of file'