#
##############################################################################
-import time
from osv import fields,osv
import netsvc
-import mx.DateTime
-from mx.DateTime import RelativeDateTime, today, DateTime, localtime
-from tools import config
+from datetime import datetime
+from dateutil.relativedelta import relativedelta
from tools.translate import _
import decimal_precision as dp
_name = 'mrp.repair'
_description = 'Repair Order'
- def _amount_untaxed(self, cr, uid, ids, field_name, arg, context):
+ def _amount_untaxed(self, cr, uid, ids, field_name, arg, context=None):
""" Calculates untaxed amount.
@param self: The object pointer
@param cr: The current row, from the database cursor,
@param field_name: Name of field.
@param arg: Argument
@param context: A standard dictionary for contextual values
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
res = {}
cur_obj = self.pool.get('res.currency')
- for repair in self.browse(cr, uid, ids):
+
+ for repair in self.browse(cr, uid, ids, context=context):
res[repair.id] = 0.0
for line in repair.operations:
res[repair.id] += line.price_subtotal
res[repair.id] = cur_obj.round(cr, uid, cur, res[repair.id])
return res
- def _amount_tax(self, cr, uid, ids, field_name, arg, context):
+ def _amount_tax(self, cr, uid, ids, field_name, arg, context=None):
""" Calculates taxed amount.
@param field_name: Name of field.
@param arg: Argument
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
res = {}
+ #return {}.fromkeys(ids, 0)
cur_obj = self.pool.get('res.currency')
tax_obj = self.pool.get('account.tax')
- for repair in self.browse(cr, uid, ids):
+ for repair in self.browse(cr, uid, ids, context=context):
val = 0.0
cur = repair.pricelist_id.currency_id
for line in repair.operations:
res[repair.id] = cur_obj.round(cr, uid, cur, val)
return res
- def _amount_total(self, cr, uid, ids, field_name, arg, context):
+ def _amount_total(self, cr, uid, ids, field_name, arg, context=None):
""" Calculates total amount.
@param field_name: Name of field.
@param arg: Argument
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
res = {}
- untax = self._amount_untaxed(cr, uid, ids, field_name, arg, context)
- tax = self._amount_tax(cr, uid, ids, field_name, arg, context)
+ untax = self._amount_untaxed(cr, uid, ids, field_name, arg, context=context)
+ tax = self._amount_tax(cr, uid, ids, field_name, arg, context=context)
cur_obj = self.pool.get('res.currency')
for id in ids:
- repair = self.browse(cr, uid, [id])[0]
+ repair = self.browse(cr, uid, id, context=context)
cur = repair.pricelist_id.currency_id
res[id] = cur_obj.round(cr, uid, cur, untax.get(id, 0.0) + tax.get(id, 0.0))
return res
+ def _get_default_address(self, cr, uid, ids, field_name, arg, context=None):
+ res = {}
+ partner_obj = self.pool.get('res.partner')
+ for data in self.browse(cr, uid, ids, context=context):
+ adr_id = False
+ if data.partner_id:
+ adr_id = partner_obj.address_get(cr, uid, [data.partner_id.id], ['default'])['default']
+ res[data.id] = adr_id
+ return res
+
+ def _get_lines(self, cr, uid, ids, context=None):
+ if context is None:
+ context = {}
+ result = {}
+ for line in self.pool.get('mrp.repair.line').browse(cr, uid, ids, context=context):
+ result[line.repair_id.id] = True
+ return result.keys()
+
_columns = {
'name': fields.char('Repair Reference',size=24, required=True),
'product_id': fields.many2one('product.product', string='Product to Repair', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'partner_id' : fields.many2one('res.partner', 'Partner', select=True, help='This field allow you to choose the parner that will be invoiced and delivered'),
'address_id': fields.many2one('res.partner.address', 'Delivery Address', domain="[('partner_id','=',partner_id)]"),
+ 'default_address_id': fields.function(_get_default_address, method=True, type="many2one", relation="res.partner.address"),
'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, domain="[('product_id','=',product_id)]"),
'state': fields.selection([
('draft','Quotation'),
('invoice_except','Invoice Exception'),
('done','Done'),
('cancel','Cancel')
- ], 'Repair State', readonly=True,
+ ], 'State', readonly=True,
help=' * The \'Draft\' state is used when a user is encoding a new and unconfirmed repair order. \
\n* The \'Confirmed\' state is used when a user confirms the repair order. \
\n* The \'Ready to Repair\' state is used to start to repairing, user can start repairing only after repair order is confirmed. \
'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."),
'invoiced': fields.boolean('Invoiced', readonly=True),
'repaired': fields.boolean('Repaired', readonly=True),
- 'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount'),
- 'amount_tax': fields.function(_amount_tax, method=True, string='Taxes'),
- 'amount_total': fields.function(_amount_total, method=True, string='Total'),
+ 'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount',
+ store={
+ 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10),
+ 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
+ }),
+ 'amount_tax': fields.function(_amount_tax, method=True, string='Taxes',
+ store={
+ 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10),
+ 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
+ }),
+ 'amount_total': fields.function(_amount_total, method=True, string='Total',
+ store={
+ 'mrp.repair': (lambda self, cr, uid, ids, c={}: ids, ['operations'], 10),
+ 'mrp.repair.line': (_get_lines, ['price_unit', 'price_subtotal', 'product_id', 'tax_id', 'product_uom_qty', 'product_uom'], 10),
+ }),
}
_defaults = {
})
return super(mrp_repair, self).copy(cr, uid, id, default, context)
-
def onchange_product_id(self, cr, uid, ids, product_id=None):
""" On change of product sets some values.
@param product_id: Changed product
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
return {'value': {
'prodlot_id': False,
destination location, partner and partner address.
@param prod_id: Id of product in current record.
@param move_id: Changed move.
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
data = {}
data['value'] = {}
if move_id:
move = self.pool.get('stock.move').browse(cr, uid, move_id)
product = self.pool.get('product.product').browse(cr, uid, prod_id)
- date = move.date_planned
- limit = mx.DateTime.strptime(date, '%Y-%m-%d %H:%M:%S') + RelativeDateTime(months=product.warranty)
+ limit = datetime.strptime(move.date_expected, '%Y-%m-%d %H:%M:%S') + relativedelta(months=int(product.warranty))
data['value']['guarantee_limit'] = limit.strftime('%Y-%m-%d')
data['value']['location_id'] = move.location_dest_id.id
data['value']['location_dest_id'] = move.location_dest_id.id
return True
def onchange_partner_id(self, cr, uid, ids, part, address_id):
- """ On change of partner sets the values of partner address,
+ """ On change of partner sets the values of partner address,
partner invoice address and pricelist.
@param part: Changed id of partner.
@param address_id: Address id from current record.
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
part_obj = self.pool.get('res.partner')
pricelist_obj = self.pool.get('product.pricelist')
destination location, move and guarantee limit.
@param lot: Changed id of production lot.
@param product_id: Product id from current record.
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
- prodlot_obj = self.pool.get('stock.production.lot')
move_obj = self.pool.get('stock.move')
data = {}
data['value'] = {
if not lot:
return data
- lot_info = prodlot_obj.browse(cr, uid, lot)
move_ids = move_obj.search(cr, uid, [('prodlot_id', '=', lot)])
if not len(move_ids):
def action_cancel_draft(self, cr, uid, ids, *args):
""" Cancels repair order when it is in 'Draft' state.
@param *arg: Arguments
- @return: True
+ @return: True
"""
if not len(ids):
return False
""" Repair order state is set to 'To be invoiced' when invoice method
is 'Before repair' else state becomes 'Confirmed'.
@param *arg: Arguments
- @return: True
+ @return: True
"""
mrp_line_obj = self.pool.get('mrp.repair.line')
for o in self.browse(cr, uid, ids):
def action_cancel(self, cr, uid, ids, context=None):
""" Cancels repair order.
- @return: True
+ @return: True
"""
- ok=True
mrp_line_obj = self.pool.get('mrp.repair.line')
- for repair in self.browse(cr, uid, ids):
- mrp_line_obj.write(cr, uid, [l.id for l in repair.operations], {'state': 'cancel'})
+ for repair in self.browse(cr, uid, ids, context=context):
+ mrp_line_obj.write(cr, uid, [l.id for l in repair.operations], {'state': 'cancel'}, context=context)
self.write(cr,uid,ids,{'state':'cancel'})
return True
def action_invoice_create(self, cr, uid, ids, group=False, context=None):
""" Creates invoice(s) for repair order.
@param group: It is set to true when group invoice is to be generated.
- @return: Invoice Ids.
+ @return: Invoice Ids.
"""
res = {}
invoices_group = {}
inv_obj = self.pool.get('account.invoice')
repair_line_obj = self.pool.get('mrp.repair.line')
repair_fee_obj = self.pool.get('mrp.repair.fee')
- for repair in self.browse(cr, uid, ids, context=context):
+ for repair in self.browse(cr, uid, ids, context=context):
res[repair.id] = False
if repair.state in ('draft','cancel') or repair.invoice_id:
continue
name = operation.name
if operation.product_id.property_account_income:
- account_id = operation.product_id.property_account_income
+ account_id = operation.product_id.property_account_income.id
elif operation.product_id.categ_id.property_account_income_categ:
account_id = operation.product_id.categ_id.property_account_income_categ.id
else:
'invoice_id': inv_id,
'name': name,
'origin': repair.name,
- 'account_id': account_id,
+ 'account_id': account_id,
'quantity': operation.product_uom_qty,
'invoice_line_tax_id': [(6,0,[x.id for x in operation.tax_id])],
'uos_id': operation.product_uom.id,
'price_unit': operation.price_unit,
'price_subtotal': operation.product_uom_qty*operation.price_unit,
'product_id': operation.product_id and operation.product_id.id or False
- })
+ })
repair_line_obj.write(cr, uid, [operation.id], {'invoiced': True, 'invoice_line_id': invoice_line_id})
for fee in repair.fees_lines:
if fee.to_invoice == True:
name = repair.name + '-' + fee.name
else:
name = fee.name
+ if not fee.product_id:
+ raise osv.except_osv(_('Warning !'), _('No product defined on Fees!'))
+
+ if fee.product_id.property_account_income:
+ account_id = fee.product_id.property_account_income.id
+ elif fee.product_id.categ_id.property_account_income_categ:
+ account_id = fee.product_id.categ_id.property_account_income_categ.id
+ else:
+ raise osv.except_osv(_('Error !'), _('No account defined for product "%s".') % fee.product_id.name)
+
invoice_fee_id = inv_line_obj.create(cr, uid, {
'invoice_id': inv_id,
'name': name,
'origin': repair.name,
- 'account_id': a,
+ 'account_id': account_id,
'quantity': fee.product_uom_qty,
'invoice_line_tax_id': [(6,0,[x.id for x in fee.tax_id])],
'uos_id': fee.product_uom.id,
'product_id': fee.product_id and fee.product_id.id or False,
'price_unit': fee.price_unit,
'price_subtotal': fee.product_uom_qty*fee.price_unit
- })
+ })
repair_fee_obj.write(cr, uid, [fee.id], {'invoiced': True, 'invoice_line_id': invoice_fee_id})
res[repair.id] = inv_id
- #self.action_invoice_end(cr, uid, ids)
return res
def action_repair_ready(self, cr, uid, ids, context=None):
""" Writes repair order state to 'Ready'
- @return: True
+ @return: True
"""
- self.write(cr, uid, ids, {'state': 'ready'})
+ for repair in self.browse(cr, uid, ids, context=context):
+ self.pool.get('mrp.repair.line').write(cr, uid, [l.id for
+ l in repair.operations], {'state': 'confirmed'}, context=context)
+ self.write(cr, uid, [repair.id], {'state': 'ready'})
return True
def action_invoice_cancel(self, cr, uid, ids, context=None):
""" Writes repair order state to 'Exception in invoice'
- @return: True
+ @return: True
"""
self.write(cr, uid, ids, {'state': 'invoice_except'})
return True
def action_repair_start(self, cr, uid, ids, context=None):
""" Writes repair order state to 'Under Repair'
- @return: True
+ @return: True
"""
- self.write(cr, uid, ids, {'state': 'under_repair'})
+ repair_line = self.pool.get('mrp.repair.line')
+ for repair in self.browse(cr, uid, ids, context=context):
+ repair_line.write(cr, uid, [l.id for
+ l in repair.operations], {'state': 'confirmed'}, context=context)
+ repair.write({'state': 'under_repair'})
return True
def action_invoice_end(self, cr, uid, ids, context=None):
""" Writes repair order state to 'Ready' if invoice method is Before repair.
- @return: True
+ @return: True
"""
- for order in self.browse(cr, uid, ids):
+ repair_line = self.pool.get('mrp.repair.line')
+ for order in self.browse(cr, uid, ids, context=context):
val = {}
if (order.invoice_method == 'b4repair'):
val['state'] = 'ready'
+ repair_line.write(cr, uid, [l.id for
+ l in order.operations], {'state': 'confirmed'}, context=context)
else:
- #val['state'] = 'done'
pass
- self.write(cr, uid, [order.id], val)
+ self.write(cr, uid, [order.id], val, context=context)
return True
def action_repair_end(self, cr, uid, ids, context=None):
- """ Writes repair order state to 'To be invoiced' if invoice method is
+ """ Writes repair order state to 'To be invoiced' if invoice method is
After repair else state is set to 'Ready'.
- @return: True
+ @return: True
"""
- for order in self.browse(cr, uid, ids):
+ for order in self.browse(cr, uid, ids, context=context):
val = {}
val['repaired'] = True
if (not order.invoiced and order.invoice_method=='after_repair'):
elif (not order.invoiced and order.invoice_method=='b4repair'):
val['state'] = 'ready'
else:
- #val['state'] = 'done'
pass
self.write(cr, uid, [order.id], val)
return True
def wkf_repair_done(self, cr, uid, ids, *args):
- res = self.action_repair_done(cr, uid, ids)
+ self.action_repair_done(cr, uid, ids)
return True
def action_repair_done(self, cr, uid, ids, context=None):
""" Creates stock move and picking for repair order.
- @return: Picking ids.
+ @return: Picking ids.
"""
res = {}
move_obj = self.pool.get('stock.move')
repair_line_obj = self.pool.get('mrp.repair.line')
seq_obj = self.pool.get('ir.sequence')
pick_obj = self.pool.get('stock.picking')
- company = self.pool.get('res.users').browse(cr, uid, uid).company_id
for repair in self.browse(cr, uid, ids, context=context):
for move in repair.operations:
move_id = move_obj.create(cr, uid, {
'tracking_id': False,
'state': 'done',
})
- repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id})
-
+ repair_line_obj.write(cr, uid, [move.id], {'move_id': move_id, 'state': 'done'}, context=context)
if repair.deliver_bool:
pick_name = seq_obj.get(cr, uid, 'stock.picking.out')
picking = pick_obj.create(cr, uid, {
'invoice_state': 'none',
'type': 'out',
})
- wf_service.trg_validate(uid, 'stock.picking', picking, 'button_confirm', cr)
-
move_id = move_obj.create(cr, uid, {
'name': repair.name,
'picking_id': picking,
'product_id': repair.product_id.id,
'product_qty': 1.0,
'product_uom': repair.product_id.uom_id.id,
- #'product_uos_qty': line.product_uom_qty,
- #'product_uos': line.product_uom.id,
'prodlot_id': repair.prodlot_id and repair.prodlot_id.id or False,
'address_id': repair.address_id and repair.address_id.id or False,
'location_id': repair.location_id.id,
'location_dest_id': repair.location_dest_id.id,
'tracking_id': False,
- 'state': 'assigned', # FIXME done ?
+ 'state': 'assigned',
})
+ wf_service.trg_validate(uid, 'stock.picking', picking, 'button_confirm', cr)
self.write(cr, uid, [repair.id], {'state': 'done', 'picking_id': picking})
res[repair.id] = picking
else:
class ProductChangeMixin(object):
- def product_id_change(self, cr, uid, ids, pricelist, product, uom=False,
+ def product_id_change(self, cr, uid, ids, pricelist, product, uom=False,
product_uom_qty=0, partner_id=False, guarantee_limit=False):
""" On change of product it sets product quantity, tax account, name,
uom of product, unit price and price subtotal.
'message':
"Couldn't find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist."
- }
+ }
else:
result.update({'price_unit': price, 'price_subtotal': price*product_uom_qty})
default.update( {'invoice_line_id': False, 'move_id': False, 'invoiced': False, 'state': 'draft'})
return super(mrp_repair_line, self).copy_data(cr, uid, id, default, context)
- def _amount_line(self, cr, uid, ids, field_name, arg, context):
+ def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
""" Calculates amount.
@param field_name: Name of field.
@param arg: Argument
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
res = {}
cur_obj=self.pool.get('res.currency')
- for line in self.browse(cr, uid, ids):
+ for line in self.browse(cr, uid, ids, context=context):
res[line.id] = line.to_invoice and line.price_unit * line.product_uom_qty or 0
cur = line.repair_id.pricelist_id.currency_id
res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])
"""
if not type:
return {'value': {
- 'location_id': False,
- 'location_dest_id': False
- }
+ 'location_id': False,
+ 'location_dest_id': False
+ }
}
- produc_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Production')])[0]
- if type == 'add':
- stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0]
- to_invoice = False
- if guarantee_limit and today() > mx.DateTime.strptime(guarantee_limit, '%Y-%m-%d'):
- to_invoice=True
+
+ product_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Production')])[0]
+ if type != 'add':
return {'value': {
- 'to_invoice': to_invoice,
- 'location_id': stock_id,
- 'location_dest_id': produc_id
- }
- }
- return {'value': {
'to_invoice': False,
- 'location_id': produc_id,
+ 'location_id': product_id,
'location_dest_id': False
+ }
+ }
+
+ stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0]
+ to_invoice = (guarantee_limit and
+ datetime.strptime(guarantee_limit, '%Y-%m-%d') < datetime.now())
+ return {'value': {
+ 'to_invoice': to_invoice,
+ 'location_id': stock_id,
+ 'location_dest_id': product_id
}
}
class mrp_repair_fee(osv.osv, ProductChangeMixin):
_name = 'mrp.repair.fee'
_description = 'Repair Fees Line'
-
+
def copy_data(self, cr, uid, id, default=None, context=None):
if not default: default = {}
default.update({'invoice_line_id': False, 'invoiced': False})
return super(mrp_repair_fee, self).copy_data(cr, uid, id, default, context)
-
- def _amount_line(self, cr, uid, ids, field_name, arg, context):
+
+ def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
""" Calculates amount.
@param field_name: Name of field.
@param arg: Argument
- @return: Dictionary of values.
+ @return: Dictionary of values.
"""
res = {}
cur_obj = self.pool.get('res.currency')
- for line in self.browse(cr, uid, ids):
+ for line in self.browse(cr, uid, ids, context=context):
res[line.id] = line.to_invoice and line.price_unit * line.product_uom_qty or 0
cur = line.repair_id.pricelist_id.currency_id
res[line.id] = cur_obj.round(cr, uid, cur, res[line.id])