Hi, I am working on a module and it requires to update the product stock on clicking a button which calls a function for making picking from the form. I want to know a simple code for updating the stock table directly from the user input values.
Here's the code: from osv import osv, fields import time from datetime import datetime import pooler import decimal_precision as dp
class mass_return(osv.osv):
_name = 'mass.return'
_description = 'Mass Return of products'
_inherit = 'product.template'
def _line_total_amount(self, cr, uid, ids, field_name, arg,context):
res={}
for line in self.browse(cr,uid,ids):
res[line.id] = line.unit_sale_price*line.product_uom_qty
return res
def address_get(self, cr, uid, ids):
address_obj = self.pool.get('res.partner.address')
address_ids = address_obj.search(cr, uid, [('partner_id', 'in', ids)])
res = list((addr['id']) for addr in address_ids)
adr = dict(res)
# get the id of the (first) default address if there is one,
# otherwise get the id of the first address in the list
if res:
default_address = adr.get('default', res[0][1])
else:
default_address = False
result = {}
return result
def onchange_partner_id(self, cr, uid, ids, part):
if not part:
return {'value': {'partner_address':False}}
addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
part = self.pool.get('res.partner').browse(cr, uid, part)
pricelist = part.property_product_pricelist and part.property_product_pricelist.id or False
val = {
'partner_address': addr['contact'],
}
if pricelist:
val['pricelist_id'] = pricelist
return {'value': val}
def onchange_pricelist_id(self, cr, uid, ids, pricelist_id, return_lines, context={}):
if (not pricelist_id) or (not return_lines):
return {}
warning = {
'title': _('Pricelist Warning!'),
'message' : _('If you change the pricelist of this order (and eventually the currency), prices of existing order lines will not be updated.')
}
return {'warning': warning}
def _product_lst_price(self, cr, uid, ids):
res = {}
product_uom_obj = self.pool.get('product.uom')
for id in ids:
res.setdefault(id, 0.0)
for product in self.browse(cr, uid, ids, context=context):
if 'uom' in context:
uom = product.uos_id or product.uom_id
res[product.id] = product_uom_obj._compute_price(cr, uid,
uom.id, product.list_price, context['uom'])
else:
res[product.id] = product.list_price
res[product.id] = (res[product.id] or 0.0) * (product.price_margin or 1.0) + product.price_extra
return res
def _compute_price(self, cr, uid, from_uom_id, price, to_uom_id=False):
if not from_uom_id or not price or not to_uom_id:
return price
uoms = self.browse(cr, uid, [from_uom_id, to_uom_id])
if uoms[0].id == from_uom_id:
from_unit, to_unit = uoms[0], uoms[-1]
else:
from_unit, to_unit = uoms[-1], uoms[0]
if from_unit.category_id.id <> to_unit.category_id.id:
return price
amount = price * from_unit.factor
if to_uom_id:
amount = amount / to_unit.factor
return amount
def price_get(self, cr, uid, ids,product_id,context=None):
if context is None:
context = {}
pricetype_obj = self.pool.get('product.price.type')
price_type_id = pricetype_obj.search(cr, uid, [('field','=',ptype)])[0]
res = {}
product_uom_obj = self.pool.get('product.uom')
for product in self.browse(cr, uid, ids, context=context):
res[product.id] = product[ptype] or 0.0
if ptype == 'list_price':
res[product.id] = (res[product.id] * (product.price_margin or 1.0)) + \
product.price_extra
if 'uom' in context:
uom = product.uom_id or product.uos_id
res[product.id] = product_uom_obj._compute_price(cr, uid,
uom.id, res[product.id], context['uom'])
# Convert from price_type currency to asked one
if 'currency_id' in context:
# Take the price_type currency from the product field
# This is right cause a field cannot be in more than one currency
res[product.id] = self.pool.get('res.currency').compute(cr, uid, price_type_currency_id,
context['currency_id'], res[product.id],context=context)
return res
def _get_returns(self, cr, uid, ids, context=None):
result = {}
for line in self.pool.get('mass.return.line').browse(cr, uid, ids, context=context):
result[line.return_id.id] = True
return result.keys()
def product_id_change(self,cr,uid,ids,prod):
if not prod:
return{'value':{'unit_sale_price':False,'product_uom':False}}
price_unit=self.pool.get('product.product').price_get(cr,uid,[prod],['list_price'])
prod=self.pool.get('product.product').browse(cr,uid,prod)
product_uom_=self.pool.get('product.product').browse(cr,uid,prod)
val = {
'unit_sale_price':price_unit['list_price'],
'product_uom':product_uom_['name']
}
return {'value':val}
def _get_uom_id(self, cr, uid, *args):
try:
proxy = self.pool.get('ir.model.data')
result = proxy.get_object_reference(cr, uid, 'product', 'product_uom_unit')
return result[1]
except Exception, ex:
return False
def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,uom=False, partner_id=False,flag=False, context=None):
context = context or {}
if not partner_id:
raise osv.except_osv(_('No Customer Defined !'), _('You have to select a customer in the form !\nPlease set one customer before choosing a product.'))
warning={}
product_uom_obj = self.pool.get('product.uom')
partner_obj = self.pool.get('res.partner')
product_obj = self.pool.get('product.product')
context_partner={'partner_id':partner_id}
if not product:
return {'domain':{'product_uom': []}}
uom2 = False
if uom:
uom2 = product_uom_obj.browse(cr, uid, uom)
if product_obj.uom_id.category_id.id != uom2.category_id.id:
uom = False
if not flag:
result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner_id)[0][1]
domain = {}
if not pricelist:
warn_msg = _('You have to select a pricelist or a customer in the sales form !\n'
'Please set one before choosing a product.')
warning_msgs += _("No Pricelist ! : ") + warn_msg +"\n\n"
else:
price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist],
product, qty or 1.0, partner_id, {
'uom': uom or result.get('product_uom'),
'date': date_order,
})[pricelist]
if price is False:
warn_msg = _("Couldn't find a pricelist line matching this product and quantity.\n"
"You have to change either the product, the quantity or the pricelist.")
##
warning_msgs += _("No valid pricelist line found ! :") + warn_msg +"\n\n"
else:
result.update({'price_unit': price})
if warning_msgs:
warning = {
'title': _('Configuration Error !'),
'message' : warning_msgs
}
return {'value': result, 'domain': domain, 'warning': warning}
_columns ={
'return_id':fields.integer('Return ID', readonly=True),
'name':fields.char('Reason', size=128),
'description': fields.text('Description'),
'number': fields.char('Number', size=128, help="Company internal claim unique number"),
'partner_id':fields.many2one('res.partner', 'Partner'),
'partner_address': fields.many2one('res.partner.address', 'Partner Contact', \
domain="[('partner_id','=',partner_id)]"
),
'partner_phone': fields.char('Phone', size=64),
'origin': fields.selection([('none','Not specified'),
('legal','Legal retractation'),
('cancellation','Order cancellation'),
('damaged','Damaged delivered product'),
('error','Shipping error'),
('exchange','Exchange request'),
('lost','Lost during transport'),
('other','Other')], 'Return Subject', help="To describe the line product problem"),
'active': fields.boolean('Active'),
'cause': fields.text('Root Cause'),
'return_date':fields.datetime('Date'),
'prodlot_id': fields.many2one('stock.production.lot', 'Lot',help="The serial/lot of the returned product"),
'company_id': fields.many2one('res.company', 'Company'),
'product_id':fields.many2one('product.product', 'Product',help="Returned product"),
'product_uom_qty': fields.float('Quantity (UoM)', digits_compute= dp.get_precision('Product UoS')),
'product_uom': fields.many2one('product.uom', 'Unit of Measure '),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist',help="Pricelist for current sales order."),
'unit_sale_price' :fields.float('Unit Price', digits_compute= dp.get_precision('Sale Price'),help="Unit sale price of the product."),
'subtotal':fields.function(_line_total_amount, string='Subtotal', type="float",digits_compute= dp.get_precision('Account'), store=True),
'return_location' : fields.many2one('stock.location', 'Dest. Location',help="Location where the system will stock the returned products.", select=True),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', help='The invoice line related to the returned product'),
}
_defaults={
'number': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'mass.return'),
}
def cancel(self, cr, uid, ids, context=None):
if context is None:
context = {}
data = context and context.get('active_ids', []) or []
return self.pool.get('mass.return').mass_return_cancel(cr, uid, data, context)
def button_compute(self, cr, uid, ids, context=None, set_total=False):
for line in self.browse(cr, uid, ids, context=context):
if set_total:
self.pool.get('mass.return').write(cr, uid, [line.id], {'subtotal': line.subtotal})
return True
def button_confirm(self, cr, uid, ids, context=None):
return self.write(cr, uid, ids, {'state': 'confirmed'})
##class make_picking(osv.osv): ##
_name= 'make.picking'
_columns={
'return_location' : fields.many2one('stock.location', 'Source Location',help="Location where the returned products are sent.", required=True),
'return_ids' : fields.many2many('mass.return', 'return_picking', 'return_picking_id', 'Return lines'),
}
def action_make_picking(self,cr,uid,ids,context=None):
print "context", context
partner_id = 0
for picking in self.browse(cr, uid,ids):
return_id = self.pool.get('mass.return').browse(cr, uid, context['active_id'])
partner_id = return_id.partner_id.id
# location type
location = -1
if return_id.return_type == "customer":
location = return_id.partner_id.property_stock_customer.id
else:
location = return_id.partner_id.property_stock_supplier.id
# create picking
picking_id = self.pool.get('stock.picking').create(cr, uid, {
'origin': return_id.id,
'type': 'in',
'move_type': 'one', # direct
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'address_id': return_id.partner_address_id.id,
'location_dest_id': picking.return_location.id,
'return_id': return_id.id,
})
# Create picking lines
for picking_line in picking.return_id:
move_id = self.pool.get('stock.move').create(cr, uid, {
'name' : picking_line.product_id.name_template, # Motif : crm id ? stock_picking_id ?
'priority': '0',
#'create_date':
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'product_id': picking_line.product_id.id,
'quantity': picking_line.product_uom_qty,
'product_uom': picking_line.product_id.uom_id.id,
'address_id': return_id.partner_address_id.id,
# 'price_currency_id': return_id.company_id.currency_id.id, # from invoice ???
'location_dest_id': picking.return_location.id,
})
return {
'name': 'Customer Picking IN',
'view_type': 'form',
'view_mode': 'tree,form',
'view_xml_id': 'mass_return_picking_in_form',
'view_name' :'mass_return_picking_in_form',
'domain' : "[('type', '=', 'in'),('partner_id','=',%s)]"%partner_id,
'res_model': 'stock.picking',
'type': 'ir.actions.act_window',
}
def button_return(self, cr, uid, ids, context=None):
if context is None:
context = {}
data = context and context.get('active_ids', []) or []
return self.pool.get('mass.return').action_make_picking(cr, uid, data, context)
def _get_dest_loc(self, cr, uid,context):
return self.pool.get('stock.warehouse').read(cr, uid, [1],['lot_input_id'])[0]['lot_input_id'][0]
_defaults = {
'return_location' : _get_dest_loc,
}
# If "Cancel" button pressed
def action_cancel(self,cr,uid,ids,conect=None):
return {'type': 'ir.actions.act_window_close',}
mass_return()
XML:
<openerp>
<data>
<record model="ir.ui.view" id="mass_return_tree">
<field name="name">Mass Return Tree</field>
<field name="model">mass.return</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Returned lines">
<field name="name"/>
<field name="partner_id"/>
<field name="return_date"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="mass_return_form_view">
<field name="name">Mass Return Form</field>
<field name="model">mass.return</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Mass Returns">
<field name="name"/>
<field name="return_date"/>
<field name="origin"/>
<field name="number"/>
<group name="Partner" colspan="4" col="3">
<separator name="Partner" colspan="4"/>
<field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
<field name="partner_address"/>
<field name="partner_phone"/>
</group>
<group name="Return Product" colspan="4" col="4">
<separator name="Return Product" colspan="8"/>
<field name="product_id" on_change="product_id_change(product_id,product_uom_qty,parent.partner_id,unit_sale_price,context)"/>
<field name="product_uom_qty"/>
<field name="product_uom"/>
<field name="unit_sale_price"/>
<field name="subtotal"/>
<field name="return_location"/>
</group>
<group col="4" colspan="4">
<separator colspan="4"/>
<button name="button_compute" string="Compute" icon="gtk-execute" type="object"/>
<button name="case_cancel" string="Cancel" special="cancel" type="object" icon="gtk-cancel" />
<button name="button_return" string="Return" type="object" icon="gtk-ok" />
<button name="refund" string="Refund" type="object" icon="gtk-ok" />
</group>
</form>
</field>
</record>
<!-- <record model="ir.ui.view" id="make_picking_form_view">
<field name="name">Mass Return Picking Form</field>
<field name="model">make.picking</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Picking">
<field name="return_location"/>
<button name="action_make_picking" string="OK" type="object" icon="gtk_ok"/>
<button name="action_cancel" string="Cancel" type="object" icon="gtk_cancel"/>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="action_make_picking_form">
<field name="name">Make Picking</field>
<field name="res_model">make.picking</field>
</record> -->
<record model="ir.actions.act_window" id="action_mass_return_form">
<field name="name">Mass Returns</field>
<field name="res_model">mass.return</field>
</record>
<record id="action_return_cancel" model="ir.actions.act_window">
<field name="name">Cancel Return</field>
<field name="res_model">mass.return</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem name="Mass Return" id="menu_mass_return" parent="base.menu_aftersale" sequence="3" action="action_mass_return_form" />
</data>
</openerp>