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