*improvement and bugfixes
[odoo/odoo.git] / addons / mrp_repair / mrp_repair.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution   
5 #    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import time
24 from osv import fields,osv
25 import netsvc
26 import mx.DateTime
27 from mx.DateTime import RelativeDateTime, today, DateTime, localtime
28 from tools import config
29 class mrp_repair(osv.osv):
30     _name = 'mrp.repair'
31     _description = 'Repairs Order'   
32     
33     def _amount_untaxed(self, cr, uid, ids, field_name, arg, context):
34         res = {}
35         cur_obj=self.pool.get('res.currency')
36         for repair in self.browse(cr, uid, ids):
37             res[repair.id] = 0.0
38             for line in repair.operations:
39                 res[repair.id] += line.price_subtotal
40             for line in repair.fees_lines:
41                 res[repair.id] += line.price_subtotal
42             cur = repair.pricelist_id.currency_id
43             res[repair.id] = cur_obj.round(cr, uid, cur, res[repair.id])
44         return res
45
46     def _amount_tax(self, cr, uid, ids, field_name, arg, context):
47         res = {}
48         cur_obj=self.pool.get('res.currency')
49         for repair in self.browse(cr, uid, ids):
50             val = 0.0
51             cur=repair.pricelist_id.currency_id
52             for line in repair.operations:
53                 if line.to_invoice:
54                     for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
55                         val+= c['amount']
56             for line in repair.fees_lines:
57                 if line.to_invoice:
58                     for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
59                         val+= c['amount']
60             res[repair.id]=cur_obj.round(cr, uid, cur, val)
61         return res
62
63     def _amount_total(self, cr, uid, ids, field_name, arg, context):
64         res = {}
65         untax = self._amount_untaxed(cr, uid, ids, field_name, arg, context)
66         tax = self._amount_tax(cr, uid, ids, field_name, arg, context)
67         cur_obj=self.pool.get('res.currency')
68         for id in ids:
69             repair=self.browse(cr, uid, [id])[0]
70             cur=repair.pricelist_id.currency_id
71             res[id] = cur_obj.round(cr, uid, cur, untax.get(id, 0.0) + tax.get(id, 0.0))
72         return res
73
74     _columns = {
75         'name' : fields.char('Repair Ref',size=24, required=True),
76         'product_id': fields.many2one('product.product', string='Product to Repair', required=True, readonly=True, states={'draft':[('readonly',False)]}),
77         'partner_id' : fields.many2one('res.partner', 'Partner', select=True, help='This field allow you to choose the parner that will be invoiced and delivered'),
78         'address_id': fields.many2one('res.partner.address', 'Delivery Address', domain="[('partner_id','=',partner_id)]"),
79         'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, domain="[('product_id','=',product_id)]"),
80         'state': fields.selection([
81             ('draft','Quotation'),
82             ('confirmed','Confirmed'),
83             ('ready','Ready to Repair'),
84             ('under_repair','Under Repair'),
85             ('2binvoiced','To be Invoiced'),
86             ('invoice_except','Invoice Exception'),
87             ('done','Done'),
88             ('cancel','Cancel')
89             ], 'Repair State', readonly=True, help="Gives the state of the Repair Order"),
90         'location_id': fields.many2one('stock.location', 'Current Location', required=True, select=True, readonly=True, states={'draft':[('readonly',False)]}),
91         'location_dest_id': fields.many2one('stock.location', 'Delivery Location', readonly=True, states={'draft':[('readonly',False)]}),
92         'move_id': fields.many2one('stock.move', 'Move',required=True, domain="[('product_id','=',product_id)]", readonly=True, states={'draft':[('readonly',False)]}),
93         'guarantee_limit': fields.date('Guarantee limit', help="The garantee limit is computed as: last move date + warranty defined on selected product. If the current date is below the garantee limit, each operation and fee you will add will be set as 'not to invoiced' by default. Note that you can change manually afterwards."),
94         'operations' : fields.one2many('mrp.repair.line', 'repair_id', 'Operation Lines', readonly=True, states={'draft':[('readonly',False)]}),
95         'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', help='The pricelist comes from the selected partner, by default.'),
96         'partner_invoice_id':fields.many2one('res.partner.address', 'Invoice to',  domain="[('partner_id','=',partner_id)]"),
97         'invoice_method':fields.selection([
98             ("none","No Invoice"),
99             ("b4repair","Before Repair"),
100             ("after_repair","After Repair")
101            ], "Invoice Method", 
102             select=True, required=True, states={'draft':[('readonly',False)]}, readonly=True, help='This field allow you to change the workflow of the repair order. If value selected is different from \'No Invoice\', it also allow you to select the pricelist and invoicing address.'),
103         'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True),
104         'picking_id': fields.many2one('stock.picking', 'Packing',readonly=True),
105         'fees_lines' : fields.one2many('mrp.repair.fee', 'repair_id', 'Fees Lines', readonly=True, states={'draft':[('readonly',False)]}),
106         'internal_notes' : fields.text('Internal Notes'),
107         'quotation_notes' : fields.text('Quotation Notes'),
108         'deliver_bool': fields.boolean('Deliver', help="Check this box if you want to manage the delivery once the product is repaired. If cheked, it will create a packing with selected product. Note that you can select the locations in the Info tab, if you have the extended view."),
109         'invoiced': fields.boolean('Invoiced', readonly=True),
110         'repaired' : fields.boolean('Repaired', readonly=True),
111         'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount'),
112         'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'),
113         'amount_total': fields.function(_amount_total, method=True, string='Total'),
114     }
115     
116     _defaults = {
117         'state': lambda *a: 'draft',
118         'deliver_bool': lambda *a: True,
119         'name': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'mrp.repair'),
120         'invoice_method': lambda *a: 'none',
121         'pricelist_id': lambda self, cr, uid,context : self.pool.get('product.pricelist').search(cr,uid,[('type','=','sale')])[0]
122     }
123     
124     def copy(self, cr, uid, id, default=None, context=None):
125         if not default:
126             default = {}   
127         default.update({
128             'state':'draft',
129             'repaired':False,
130             'invoiced':False,
131             'invoice_id': False,
132             'picking_id': False,
133             'name': self.pool.get('ir.sequence').get(cr, uid, 'mrp.repair'),
134         })
135         return super(mrp_repair, self).copy(cr, uid, id, default, context)
136
137     
138     def onchange_product_id(self, cr, uid, ids, product_id=None):
139         return {'value': {
140                     'prodlot_id': False, 
141                     'move_id': False, 
142                     'guarantee_limit' :False, 
143                     'location_id':  False, 
144                     'location_dest_id': False,
145                 }
146         }
147     
148     def onchange_move_id(self, cr, uid, ids, prod_id=False, move_id=False):
149         data = {}
150         data['value'] = {}
151         if not prod_id:
152             return data
153         if move_id:
154             move =  self.pool.get('stock.move').browse(cr, uid, move_id)
155             product = self.pool.get('product.product').browse(cr, uid, prod_id)
156             date = move.date_planned
157             limit = mx.DateTime.strptime(date, '%Y-%m-%d %H:%M:%S') + RelativeDateTime(months=product.warranty)
158             data['value']['guarantee_limit'] = limit.strftime('%Y-%m-%d')
159             data['value']['location_id'] = move.location_dest_id.id
160             data['value']['location_dest_id'] = move.location_dest_id.id
161             if move.address_id:
162                 data['value']['partner_id'] = move.address_id.partner_id and move.address_id.partner_id.id
163             else:
164                 data['value']['partner_id'] = False
165             data['value']['address_id'] = move.address_id and move.address_id.id
166             d = self.onchange_partner_id(cr, uid, ids, data['value']['partner_id'], data['value']['address_id'])
167             data['value'].update(d['value'])
168         return data
169     
170     def button_dummy(self, cr, uid, ids, context=None):
171         return True
172
173     def onchange_partner_id(self, cr, uid, ids, part, address_id):
174         if not part:
175             return {'value': {
176                         'address_id': False,
177                         'partner_invoice_id': False,
178                         'pricelist_id': self.pool.get('product.pricelist').search(cr,uid,[('type','=','sale')])[0]
179                     }
180             }
181         addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['delivery', 'invoice', 'default'])
182         partner = self.pool.get('res.partner').browse(cr, uid, part)
183         pricelist = partner.property_product_pricelist and partner.property_product_pricelist.id or False
184         return {'value': {
185                     'address_id': address_id or addr['delivery'], 
186                     'partner_invoice_id': addr['invoice'],
187                     'pricelist_id': pricelist
188                 }
189         }
190
191     def onchange_lot_id(self, cr, uid, ids, lot, product_id):
192         data = {}
193         data['value'] = {
194             'location_id': False,
195             'location_dest_id': False,
196             'move_id': False,
197             'guarantee_limit': False
198         }
199
200         if not lot:
201             return data
202         lot_info = self.pool.get('stock.production.lot').browse(cr, uid, lot)
203         move_ids = self.pool.get('stock.move').search(cr, uid, [('prodlot_id', '=', lot)])
204         
205         if not len(move_ids):
206             return data
207
208         def get_last_move(lst_move):
209             while lst_move.move_dest_id and lst_move.move_dest_id.state == 'done':
210                 lst_move = lst_move.move_dest_id
211             return lst_move
212
213         move_id = move_ids[0]
214         move = get_last_move(self.pool.get('stock.move').browse(cr, uid, move_id))
215         data['value']['move_id'] = move.id
216         d = self.onchange_move_id(cr, uid, ids, product_id, move.id)
217         data['value'].update(d['value'])
218         return data
219         
220     def action_cancel_draft(self, cr, uid, ids, *args):
221         if not len(ids):
222             return False
223         mrp_line_obj = self.pool.get('mrp.repair.line')
224         for repair in self.browse(cr, uid, ids):
225             mrp_line_obj.write(cr, uid, [l.id for l in repair.operations], {'state': 'draft'})
226         self.write(cr, uid, ids, {'state':'draft'})
227         wf_service = netsvc.LocalService("workflow")
228         for id in ids:
229             wf_service.trg_create(uid, 'mrp.repair', id, cr)
230         return True
231
232     def action_confirm(self, cr, uid, ids, *args):
233         mrp_line_obj = self.pool.get('mrp.repair.line')
234         for o in self.browse(cr, uid, ids):
235             if (o.invoice_method == 'b4repair'):
236                 self.write(cr, uid, [o.id], {'state': '2binvoiced'})
237             else:
238                 self.write(cr, uid, [o.id], {'state': 'confirmed'})   
239                 mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'})
240         return True
241     
242     def action_cancel(self, cr, uid, ids, context=None):
243         ok=True
244         mrp_line_obj = self.pool.get('mrp.repair.line')
245         for repair in self.browse(cr, uid, ids):
246             mrp_line_obj.write(cr, uid, [l.id for l in repair.operations], {'state': 'cancel'})
247         self.write(cr,uid,ids,{'state':'cancel'})
248         return True
249
250     def wkf_invoice_create(self, cr, uid, ids, *args):
251         return self.action_invoice_create(cr, uid, ids)
252
253     def action_invoice_create(self, cr, uid, ids, group=False, context=None):
254         res={}        
255         invoices_group = {}
256         for repair in self.browse(cr, uid, ids, context=context):
257             res[repair.id]=False
258             if repair.state in ('draft','cancel') or repair.invoice_id:
259                 continue
260             if not (repair.partner_id.id and repair.partner_invoice_id.id):
261                 raise osv.except_osv('No partner !','You have to select a partner in the repair form ! ')
262             comment=repair.quotation_notes
263             if (repair.invoice_method != 'none'):
264                 if group and repair.partner_invoice_id.id in invoices_group:
265                     inv_id= invoices_group[repair.partner_invoice_id.id]
266                     invoice=invoice_obj.browse(cr, uid,inv_id)      
267                     invoice_vals = {
268                         'name': invoice.name +', '+repair.name,
269                         'origin': invoice.origin+', '+repair.name,    
270                         'comment':(comment and (invoice.comment and invoice.comment+"\n"+comment or comment)) or (invoice.comment and invoice.comment or ''),
271                     }
272                     invoice_obj.write(cr, uid, [inv_id],invoice_vals,context=context)
273                 else:
274                     a = repair.partner_id.property_account_receivable.id
275                     inv = {
276                         'name': repair.name,
277                         'origin':repair.name,
278                         'type': 'out_invoice',
279                         'account_id': a,
280                         'partner_id': repair.partner_id.id,
281                         'address_invoice_id': repair.address_id.id,
282                         'currency_id': repair.pricelist_id.currency_id.id,
283                         'comment': repair.quotation_notes,
284                     }
285                     inv_obj = self.pool.get('account.invoice')
286                     inv_id = inv_obj.create(cr, uid, inv)
287                     invoices_group[repair.partner_invoice_id.id] = inv_id 
288                 self.write(cr, uid, repair.id , {'invoiced':True,'invoice_id' : inv_id}) 
289                                 
290                 for operation in repair.operations:
291                     if operation.to_invoice == True:
292                         if group:
293                             name = repair.name + '-' + operation.name
294                         else:
295                             name = operation.name
296                         invoice_line_id=self.pool.get('account.invoice.line').create(cr, uid, {
297                             'invoice_id': inv_id, 
298                             'name': name,
299                             'origin':repair.name,
300                             'account_id': a,
301                             'quantity' : operation.product_uom_qty,
302                             'invoice_line_tax_id': [(6,0,[x.id for x in operation.tax_id])],
303                             'uos_id' : operation.product_uom.id,
304                             'price_unit' : operation.price_unit,
305                             'price_subtotal' : operation.product_uom_qty*operation.price_unit,
306                             'product_id' : operation.product_id and operation.product_id.id or False
307                             })
308                         self.pool.get('mrp.repair.line').write(cr, uid, [operation.id], {'invoiced':True,'invoice_line_id':invoice_line_id})
309                 for fee in repair.fees_lines:
310                     if fee.to_invoice == True:
311                         if group:
312                             name = repair.name + '-' + fee.name
313                         else:
314                             name = fee.name
315                         invoice_fee_id=self.pool.get('account.invoice.line').create(cr, uid, {
316                             'invoice_id': inv_id,
317                             'name': name,
318                             'origin':repair.name,
319                             'account_id': a,
320                             'quantity': fee.product_uom_qty,
321                             'invoice_line_tax_id': [(6,0,[x.id for x in fee.tax_id])],
322                             'uos_id': fee.product_uom.id,
323                             'product_id': fee.product_id and fee.product_id.id or False,
324                             'price_unit': fee.price_unit,
325                             'price_subtotal': fee.product_uom_qty*fee.price_unit
326                             })
327                         self.pool.get('mrp.repair.fee').write(cr, uid, [fee.id], {'invoiced':True,'invoice_line_id':invoice_fee_id})
328                 res[repair.id]=inv_id
329         #self.action_invoice_end(cr, uid, ids)
330         return res
331
332     def action_repair_ready(self, cr, uid, ids, context=None):
333         self.write(cr, uid, ids, {'state':'ready'})
334         return True
335
336     def action_invoice_cancel(self, cr, uid, ids, context=None):
337         self.write(cr, uid, ids, {'state':'invoice_except'})
338         return True
339
340     def action_repair_start(self, cr, uid, ids, context=None):
341         self.write(cr, uid, ids, {'state':'under_repair'})
342         return True
343     
344     def action_invoice_end(self, cr, uid, ids, context=None):
345         for order in self.browse(cr, uid, ids):
346             val = {}             
347             if (order.invoice_method=='b4repair'):
348                 val['state'] = 'ready'
349             else:
350                 #val['state'] = 'done'
351                 pass
352             self.write(cr, uid, [order.id], val)
353         return True     
354
355     def action_repair_end(self, cr, uid, ids, context=None):
356         for order in self.browse(cr, uid, ids):
357             val = {}
358             val['repaired']=True
359             if (not order.invoiced and order.invoice_method=='after_repair'):
360                 val['state'] = '2binvoiced'
361             elif (not order.invoiced and order.invoice_method=='b4repair'):
362                 val['state'] = 'ready'
363             else:
364                 #val['state'] = 'done'
365                 pass
366             self.write(cr, uid, [order.id], val)
367         return True     
368
369     def wkf_repair_done(self, cr, uid, ids, *args):
370         res=self.action_repair_done(cr,uid,ids)
371         return True
372         
373     def action_repair_done(self, cr, uid, ids, context=None):
374         res = {}    
375         company = self.pool.get('res.users').browse(cr, uid, uid).company_id
376         for repair in self.browse(cr, uid, ids, context=context): 
377             #TODO: create the moves add/remove
378             for move in repair.operations:
379                 move_id = self.pool.get('stock.move').create(cr, uid, {
380                     'name': move.name,
381                     'product_id': move.product_id.id,
382                     'product_qty': move.product_uom_qty,
383                     'product_uom': move.product_uom.id,
384                     'address_id': repair.address_id and repair.address_id.id or False,
385                     'location_id': move.location_id.id,
386                     'location_dest_id': move.location_dest_id.id,
387                     'tracking_id': False,
388                     'state': 'assigned',
389                 })
390                 self.pool.get('mrp.repair.line').write(cr, uid, [move.id], {'move_id': move_id})
391
392             if repair.deliver_bool:
393                 picking = self.pool.get('stock.picking').create(cr, uid, {
394                     'origin': repair.name,
395                     'state': 'draft',
396                     'move_type': 'one',
397                     'address_id': repair.address_id and repair.address_id.id or False,
398                     'note': repair.internal_notes,
399                     'invoice_state': 'none',
400                     'type': 'out',  # FIXME delivery ?
401                 })
402                 wf_service = netsvc.LocalService("workflow")
403                 wf_service.trg_validate(uid, 'stock.picking', picking, 'button_confirm', cr)
404
405                 move_id = self.pool.get('stock.move').create(cr, uid, {
406                     'name': repair.name,
407                     'picking_id': picking,
408                     'product_id': repair.product_id.id,
409                     'product_qty': 1.0,
410                     'product_uom': repair.product_id.uom_id.id,
411                     #'product_uos_qty': line.product_uom_qty,
412                     #'product_uos': line.product_uom.id,
413                     'prodlot_id': repair.prodlot_id and repair.prodlot_id.id or False,
414                     'address_id': repair.address_id and repair.address_id.id or False,
415                     'location_id': repair.location_id.id,
416                     'location_dest_id': repair.location_dest_id.id,
417                     'tracking_id': False,
418                     'state': 'assigned',    # FIXME done ?
419                 })
420                 self.write(cr, uid, [repair.id], {'state':'done', 'picking_id':picking})
421                 res[repair.id] = picking
422             else:
423                 self.write(cr, uid, [repair.id], {'state':'done'})
424         return res
425         
426            
427 mrp_repair()
428
429
430 class ProductChangeMixin(object):
431     def product_id_change(self, cr, uid, ids, pricelist, product, uom=False, product_uom_qty=0, partner_id=False, guarantee_limit=False):
432         result = {}
433         warning = {}       
434         print "here we are"
435         if not product_uom_qty:
436             product_uom_qty = 1
437         result['product_uom_qty'] = product_uom_qty 
438
439         if product:
440             product_obj =  self.pool.get('product.product').browse(cr, uid, product)
441             if partner_id:
442                 partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
443                 result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, partner, product_obj.taxes_id)
444
445             result['name'] = product_obj.partner_ref
446             result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id or False
447             if not pricelist:
448                 warning={
449                     'title':'No Pricelist !',
450                     'message':
451                         'You have to select a pricelist in the Repair form !\n'
452                         'Please set one before choosing a product.'
453                 }
454             else:
455                 price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
456                             product, product_uom_qty, partner_id, {'uom': uom,})[pricelist]
457             
458                 if price is False:
459                      warning={
460                         'title':'No valid pricelist line found !',
461                         'message':
462                             "Couldn't find a pricelist line matching this product and quantity.\n"
463                             "You have to change either the product, the quantity or the pricelist."
464                     }
465                 else:
466                     result.update({'price_unit': price, 'price_subtotal' :price*product_uom_qty})
467         
468         return {'value': result, 'warning': warning}
469      
470
471 class mrp_repair_line(osv.osv, ProductChangeMixin):
472     _name = 'mrp.repair.line'
473     _description = 'Repair Operations Lines'
474     
475     def copy(self, cr, uid, id, default=None, context=None):
476         if not default: default = {}
477         default.update( {'invoice_line_id':False,'move_id':False,'invoiced':False,'state':'draft'})
478         return super(mrp_repair_line, self).copy(cr, uid, id, default, context)
479     
480     def _amount_line(self, cr, uid, ids, field_name, arg, context):
481         res = {}
482         cur_obj=self.pool.get('res.currency')
483         for line in self.browse(cr, uid, ids):
484             res[line.id] = line.to_invoice and line.price_unit * line.product_uom_qty or 0
485             cur = line.repair_id.pricelist_id.currency_id
486             res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
487         return res
488
489     _columns = {
490         'name' : fields.char('Description',size=64,required=True),
491         'repair_id': fields.many2one('mrp.repair', 'Repair Order Ref',ondelete='cascade', select=True),
492         'type': fields.selection([('add','Add'),('remove','Remove')],'Type', required=True),
493         'to_invoice': fields.boolean('To Invoice'),
494         'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok','=',True)], required=True),
495         'invoiced': fields.boolean('Invoiced',readonly=True),
496         'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
497         'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',digits=(16, int(config['price_accuracy']))),  
498         'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
499         'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True),
500         'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
501         'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
502         'location_id': fields.many2one('stock.location', 'Source Location', required=True, select=True),
503         'location_dest_id': fields.many2one('stock.location', 'Dest. Location', required=True, select=True),      
504         'move_id': fields.many2one('stock.move', 'Inventory Move', readonly=True),
505         'state': fields.selection([('draft','Draft'),('confirmed','Confirmed'),('done','Done'),('cancel','Canceled')], 'Status', required=True, readonly=True),
506     }
507     _defaults = {
508      'state': lambda *a: 'draft',
509      'product_uom_qty':lambda *a:1,
510     }
511      
512     def onchange_operation_type(self, cr, uid, ids, type, guarantee_limit):
513         if not type:
514             return {'value': {
515                         'location_id': False,
516                         'location_dest_id': False
517                     }
518             }
519         produc_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Production')])[0]
520         if type == 'add':
521             stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0]
522             to_invoice=False
523             if guarantee_limit and today() > mx.DateTime.strptime(guarantee_limit, '%Y-%m-%d'):
524                 to_invoice=True
525             return {'value': {
526                         'to_invoice': to_invoice,
527                         'location_id': stock_id,
528                         'location_dest_id' : produc_id
529                     }
530             }
531         return {'value': {
532                 'to_invoice': False,
533                 'location_id': produc_id,
534                 'location_dest_id':False
535             }
536         }
537
538 mrp_repair_line()
539
540 class mrp_repair_fee(osv.osv, ProductChangeMixin):
541     _name = 'mrp.repair.fee'
542     _description = 'Repair Fees line'
543     def copy(self, cr, uid, id, default=None, context=None):
544         if not default: default = {}
545         default.update( {'invoice_line_id':False,'invoiced':False})
546         return super(mrp_repair_fee, self).copy(cr, uid, id, default, context)
547     def _amount_line(self, cr, uid, ids, field_name, arg, context):
548         res = {}
549         cur_obj=self.pool.get('res.currency')
550         for line in self.browse(cr, uid, ids):
551             res[line.id] = line.to_invoice and line.price_unit * line.product_uom_qty or 0
552             cur = line.repair_id.pricelist_id.currency_id
553             res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
554         return res
555
556     _columns = {
557         'repair_id': fields.many2one('mrp.repair', 'Repair Order Ref', required=True, ondelete='cascade', select=True),
558         'name': fields.char('Description', size=64, select=True,required=True),
559         'product_id': fields.many2one('product.product', 'Product'),
560         'product_uom_qty': fields.float('Quantity', digits=(16,2), required=True),
561         'price_unit': fields.float('Unit Price', required=True),
562         'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
563         'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',digits=(16, int(config['price_accuracy']))),
564         'tax_id': fields.many2many('account.tax', 'repair_fee_line_tax', 'repair_fee_line_id', 'tax_id', 'Taxes'),
565         'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
566         'to_invoice': fields.boolean('To Invoice'),
567         'invoiced': fields.boolean('Invoiced',readonly=True),
568     }
569     _defaults = {
570         'to_invoice': lambda *a: True,
571     }
572     
573 mrp_repair_fee()
574 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: