from operator import itemgetter
from itertools import groupby
-from openerp.osv import fields, osv
+from openerp.osv import fields, osv, orm
from openerp.tools.translate import _
from openerp import netsvc
from openerp import tools
-from openerp.tools import float_compare
+from openerp.tools import float_compare, DEFAULT_SERVER_DATETIME_FORMAT
import openerp.addons.decimal_precision as dp
import logging
_logger = logging.getLogger(__name__)
_parent_order = 'posz,name'
_order = 'parent_left'
+ # TODO: implement name_search() in a way that matches the results of name_get!
+
def name_get(self, cr, uid, ids, context=None):
# always return the full hierarchical name
res = self._complete_name(cr, uid, ids, 'complete_name', None, context=context)
if location.chained_location_type == 'customer':
if partner:
result = partner.property_stock_customer
+ else:
+ loc_id = self.pool['res.partner'].default_get(cr, uid, ['property_stock_customer'], context=context)['property_stock_customer']
+ result = self.pool['stock.location'].browse(cr, uid, loc_id, context=context)
elif location.chained_location_type == 'fixed':
result = location.chained_location_id
if result:
uom_rounding = self.pool.get('product.product').browse(cr, uid, product_id, context=context).uom_id.rounding
if context.get('uom'):
uom_rounding = uom_obj.browse(cr, uid, context.get('uom'), context=context).rounding
+
locations_ids = self.search(cr, uid, [('location_id', 'child_of', ids)])
- #Fetch only those locations in which this product has ever processed(in or out)
- cr.execute("""SELECT l.id FROM stock_location l WHERE l.id in %s AND
- EXISTS (SELECT 1 FROM stock_move m WHERE m.product_id = %s
- AND ((state = 'done' AND m.location_dest_id = l.id)
- OR
- (state in ('done','assigned') AND m.location_id = l.id)))
- """, (tuple(locations_ids), product_id,))
- locations_ids = [i for i in cr.fetchall()]
+ if locations_ids:
+ # Fetch only the locations in which this product has ever been processed (in or out)
+ cr.execute("""SELECT l.id FROM stock_location l WHERE l.id in %s AND
+ EXISTS (SELECT 1 FROM stock_move m WHERE m.product_id = %s
+ AND ((state = 'done' AND m.location_dest_id = l.id)
+ OR (state in ('done','assigned') AND m.location_id = l.id)))
+ """, (tuple(locations_ids), product_id,))
+ locations_ids = [i for (i,) in cr.fetchall()]
for id in locations_ids:
if lock:
try:
_name = "stock.picking"
_inherit = ['mail.thread']
_description = "Picking List"
+ _order = "id desc"
def _set_maximum_date(self, cr, uid, ids, name, value, arg, context=None):
""" Calculates planned date if it is greater than 'value'.
ids = [ids]
for pick in self.browse(cr, uid, ids, context=context):
sql_str = """update stock_move set
- date='%s'
+ date_expected='%s'
where
picking_id=%d """ % (value, pick.id)
-
if pick.max_date:
- sql_str += " and (date='" + pick.max_date + "' or date>'" + value + "')"
+ sql_str += " and (date_expected='" + pick.max_date + "')"
cr.execute(sql_str)
return True
ids = [ids]
for pick in self.browse(cr, uid, ids, context=context):
sql_str = """update stock_move set
- date='%s'
+ date_expected='%s'
where
picking_id=%s """ % (value, pick.id)
if pick.min_date:
- sql_str += " and (date='" + pick.min_date + "' or date<'" + value + "')"
+ sql_str += " and (date_expected='" + pick.min_date + "')"
cr.execute(sql_str)
return True
def create(self, cr, user, vals, context=None):
if ('name' not in vals) or (vals.get('name')=='/'):
- seq_obj_name = self._name
+ seq_obj_name = 'stock.picking.%s' % vals.get('type', 'internal')
vals['name'] = self.pool.get('ir.sequence').get(cr, user, seq_obj_name)
new_id = super(stock_picking, self).create(cr, user, vals, context)
return new_id
),
'min_date': fields.function(get_min_max_date, fnct_inv=_set_minimum_date, multi="min_max_date",
store=True, type='datetime', string='Scheduled Time', select=1, help="Scheduled time for the shipment to be processed"),
- 'date': fields.datetime('Time', help="Creation time, usually the time of the order.", select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
+ 'date': fields.datetime('Creation Date', help="Creation date, usually the time of the order.", select=True, states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'date_done': fields.datetime('Date of Transfer', help="Date of Completion", states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}),
'max_date': fields.function(get_min_max_date, fnct_inv=_set_maximum_date, multi="min_max_date",
store=True, type='datetime', string='Max. Expected Date', select=2),
default = {}
default = default.copy()
picking_obj = self.browse(cr, uid, id, context=context)
- move_obj = self.pool.get('stock.move')
if ('name' not in default) or (picking_obj.name == '/'):
seq_obj_name = 'stock.picking.' + picking_obj.type
default['name'] = self.pool.get('ir.sequence').get(cr, uid, seq_obj_name)
if 'invoice_state' not in default and picking_obj.invoice_state == 'invoiced':
default['invoice_state'] = '2binvoiced'
res = super(stock_picking, self).copy(cr, uid, id, default, context)
- if res:
- picking_obj = self.browse(cr, uid, res, context=context)
- for move in picking_obj.move_lines:
- move_obj.write(cr, uid, [move.id], {'tracking_id': False, 'prodlot_id': False, 'move_history_ids2': [(6, 0, [])], 'move_history_ids': [(6, 0, [])]})
return res
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
@return: True
"""
pickings = self.browse(cr, uid, ids, context=context)
- self.write(cr, uid, ids, {'state': 'confirmed'})
+ to_update = []
+ for pick in pickings:
+ if pick.state != 'confirmed':
+ to_update.append(pick.id)
+ if to_update:
+ self.write(cr, uid, to_update, {'state': 'confirmed'})
todo = []
for picking in pickings:
for r in picking.move_lines:
""" Cancels picking and moves.
@return: True
"""
- wf_service = netsvc.LocalService("workflow")
for pick in self.browse(cr, uid, ids):
move_ids = [x.id for x in pick.move_lines]
self.pool.get('stock.move').cancel_assign(cr, uid, move_ids)
- wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
return True
def action_assign_wkf(self, cr, uid, ids, context=None):
""" Changes picking state to assigned.
@return: True
"""
- self.write(cr, uid, ids, {'state': 'assigned'})
+ to_update = []
+ for pick in self.browse(cr, uid, ids, context=context):
+ if pick.state != 'assigned':
+ to_update.append(pick.id)
+ if to_update:
+ self.write(cr, uid, to_update, {'state': 'assigned'})
return True
def test_finished(self, cr, uid, ids):
if all([x.state != 'waiting' for x in pick.move_lines]):
return True
for move in pick.move_lines:
+ if (move.state) == 'waiting':
+ move.check_assign()
if (move.state in ('confirmed', 'draft')) and (mt == 'one'):
return False
if (mt == 'direct') and (move.state == 'assigned') and (move.product_qty):
if isinstance(partner, int):
partner = partner_obj.browse(cr, uid, [partner], context=context)[0]
if not partner:
- raise osv.except_osv(_('Error, no partner !'),
+ raise osv.except_osv(_('Error, no partner!'),
_('Please put a partner on the picking list if you want to generate invoice.'))
if not inv_type:
inv_type = self._get_invoice_type(picking)
+ invoice_vals = self._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context)
if group and partner.id in invoices_group:
invoice_id = invoices_group[partner.id]
invoice = invoice_obj.browse(cr, uid, invoice_id)
invoice_vals_group = self._prepare_invoice_group(cr, uid, picking, partner, invoice, context=context)
invoice_obj.write(cr, uid, [invoice_id], invoice_vals_group, context=context)
else:
- invoice_vals = self._prepare_invoice(cr, uid, picking, partner, inv_type, journal_id, context=context)
invoice_id = invoice_obj.create(cr, uid, invoice_vals, context=context)
invoices_group[partner.id] = invoice_id
res[picking.id] = invoice_id
context['currency_id'] = move_currency_id
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
- if product.id in product_avail:
- product_avail[product.id] += qty
- else:
+ if product.id not in product_avail:
+ # keep track of stock on hand including processed lines not yet marked as done
product_avail[product.id] = product.qty_available
if qty > 0:
new_price = currency_obj.compute(cr, uid, product_currency,
- move_currency_id, product_price)
+ move_currency_id, product_price, round=False)
new_price = uom_obj._compute_price(cr, uid, product_uom, new_price,
product.uom_id.id)
- if product.qty_available <= 0:
+ if product_avail[product.id] <= 0:
+ product_avail[product.id] = 0
new_std_price = new_price
else:
# Get the standard price
{'price_unit': product_price,
'price_currency_id': product_currency})
+ product_avail[product.id] += qty
+
+
for move in too_few:
product_qty = move_product_qty[move.id]
self.action_move(cr, uid, [new_picking], context=context)
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr)
wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
- delivered_pack_id = new_picking
+ delivered_pack_id = pick.id
back_order_name = self.browse(cr, uid, delivered_pack_id, context=context).name
- self.message_post(cr, uid, ids, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
+ self.message_post(cr, uid, new_picking, body=_("Back order <em>%s</em> has been <b>created</b>.") % (back_order_name), context=context)
else:
self.action_move(cr, uid, [pick.id], context=context)
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
"* Waiting Availability: This state is reached when the procurement resolution is not straight forward. It may need the scheduler to run, a component to me manufactured...\n"\
"* Available: When products are reserved, it is set to \'Available\'.\n"\
"* Done: When the shipment is processed, the state is \'Done\'."),
- 'price_unit': fields.float('Unit Price', digits_compute= dp.get_precision('Account'), help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"),
+ 'price_unit': fields.float('Unit Price', digits_compute= dp.get_precision('Product Price'), help="Technical field used to record the product cost set by the user during a picking confirmation (when average price costing method is used)"),
'price_currency_id': fields.many2one('res.currency', 'Currency for average price', help="Technical field used to record the currency chosen by the user during a picking confirmation (when average price costing method is used)"),
'company_id': fields.many2one('res.company', 'Company', required=True, select=True),
'backorder_id': fields.related('picking_id','backorder_id',type='many2one', relation="stock.picking", string="Back Order of", select=True),
elif picking_type == 'out':
location_xml_id = 'stock_location_customers'
if location_xml_id:
- location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id)
+ try:
+ location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id)
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [location_id], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ location_id = False
+
return location_id
def _default_location_source(self, cr, uid, context=None):
elif picking_type in ('out', 'internal'):
location_xml_id = 'stock_location_stock'
if location_xml_id:
- location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id)
+ try:
+ location_model, location_id = mod_obj.get_object_reference(cr, uid, 'stock', location_xml_id)
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [location_id], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ location_id = False
+
return location_id
def _default_destination_address(self, cr, uid, context=None):
for move in self.browse(cr, uid, ids, context=context):
if move.state == 'done':
if frozen_fields.intersection(vals):
- raise osv.except_osv(_('Operation forbidden !'),
+ raise osv.except_osv(_('Operation Forbidden!'),
_('Quantities, Units of Measure, Products and Locations cannot be modified on stock moves that have already been processed (except by the Administrator).'))
return super(stock_move, self).write(cr, uid, ids, vals, context=context)
- def copy(self, cr, uid, id, default=None, context=None):
+ def copy_data(self, cr, uid, id, default=None, context=None):
if default is None:
default = {}
default = default.copy()
- default.update({'move_history_ids2': [], 'move_history_ids': []})
- return super(stock_move, self).copy(cr, uid, id, default, context=context)
+ default.setdefault('tracking_id', False)
+ default.setdefault('prodlot_id', False)
+ default.setdefault('move_history_ids', [])
+ default.setdefault('move_history_ids2', [])
+ return super(stock_move, self).copy_data(cr, uid, id, default, context=context)
def _auto_init(self, cursor, context=None):
res = super(stock_move, self)._auto_init(cursor, context=context)
result = {
'product_qty': 0.00
}
- warning = {}
if (not product_id) or (product_uos_qty <=0.0):
result['product_uos_qty'] = 0.0
product_obj = self.pool.get('product.product')
uos_coeff = product_obj.read(cr, uid, product_id, ['uos_coeff'])
-
- # Warn if the quantity was decreased
- for move in self.read(cr, uid, ids, ['product_uos_qty']):
- if product_uos_qty < move['product_uos_qty']:
- warning.update({
- 'title': _('Warning: No Back Order'),
- 'message': _("By changing the quantity here, you accept the "
- "new quantity as complete: OpenERP will not "
- "automatically generate a Back Order.") })
- break
+
+ # No warning if the quantity was decreased to avoid double warnings:
+ # The clients should call onchange_quantity too anyway
if product_uos and product_uom and (product_uom != product_uos):
result['product_qty'] = product_uos_qty / uos_coeff['uos_coeff']
else:
result['product_qty'] = product_uos_qty
- return {'value': result, 'warning': warning}
+ return {'value': result}
def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False,
loc_dest_id=False, partner_id=False):
"""
if not prod_id:
return {}
- lang = False
+ user = self.pool.get('res.users').browse(cr, uid, uid)
+ lang = user and user.lang or False
if partner_id:
addr_rec = self.pool.get('res.partner').browse(cr, uid, partner_id)
if addr_rec:
elif type == 'out':
location_source_id = 'stock_location_stock'
location_dest_id = 'stock_location_customers'
- source_location = mod_obj.get_object_reference(cr, uid, 'stock', location_source_id)
- dest_location = mod_obj.get_object_reference(cr, uid, 'stock', location_dest_id)
+ try:
+ source_location = mod_obj.get_object_reference(cr, uid, 'stock', location_source_id)
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [source_location[1]], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ source_location = False
+ try:
+ dest_location = mod_obj.get_object_reference(cr, uid, 'stock', location_dest_id)
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [dest_location[1]], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ dest_location = False
return {'value':{'location_id': source_location and source_location[1] or False, 'location_dest_id': dest_location and dest_location[1] or False}}
def onchange_date(self, cr, uid, ids, date, date_expected, context=None):
if context is None:
context = {}
seq_obj = self.pool.get('ir.sequence')
- for picking, todo in self._chain_compute(cr, uid, moves, context=context).items():
- ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
- if picking:
- # name of new picking according to its type
- new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
- pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
- # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order
- old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
- if old_ptype != picking.type:
- old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
- self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context)
- else:
- pickid = False
- for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo:
- new_id = move_obj.copy(cr, uid, move.id, {
- 'location_id': move.location_dest_id.id,
- 'location_dest_id': loc.id,
- 'date': time.strftime('%Y-%m-%d'),
- 'picking_id': pickid,
- 'state': 'waiting',
- 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
- 'move_history_ids': [],
- 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
- 'move_history_ids2': []}
- )
- move_obj.write(cr, uid, [move.id], {
- 'move_dest_id': new_id,
- 'move_history_ids': [(4, new_id)]
- })
- new_moves.append(self.browse(cr, uid, [new_id])[0])
- if pickid:
- wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
+ for picking, chained_moves in self._chain_compute(cr, uid, moves, context=context).items():
+ # We group the moves by automatic move type, so it creates different pickings for different types
+ moves_by_type = {}
+ for move in chained_moves:
+ moves_by_type.setdefault(move[1][1], []).append(move)
+ for todo in moves_by_type.values():
+ ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0])
+ if picking:
+ # name of new picking according to its type
+ if ptype == 'internal':
+ new_pick_name = seq_obj.get(cr, uid,'stock.picking')
+ else :
+ new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype)
+ pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context)
+ # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order
+ old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id)
+ if old_ptype != picking.type:
+ old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype)
+ self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context)
+ else:
+ pickid = False
+ for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo:
+ new_id = move_obj.copy(cr, uid, move.id, {
+ 'location_id': move.location_dest_id.id,
+ 'location_dest_id': loc.id,
+ 'date': time.strftime('%Y-%m-%d'),
+ 'picking_id': pickid,
+ 'state': 'waiting',
+ 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) ,
+ 'move_history_ids': [],
+ 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'),
+ 'move_history_ids2': []}
+ )
+ move_obj.write(cr, uid, [move.id], {
+ 'move_dest_id': new_id,
+ 'move_history_ids': [(4, new_id)]
+ })
+ new_moves.append(self.browse(cr, uid, [new_id])[0])
+ if pickid:
+ wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr)
if new_moves:
new_moves += self.create_chained_picking(cr, uid, new_moves, context)
return new_moves
# fix for bug lp:707031
# called write of related picking because changing move availability does
# not trigger workflow of picking in order to change the state of picking
+ seen = set()
wf_service = netsvc.LocalService('workflow')
for move in self.browse(cr, uid, ids, context):
- if move.picking_id:
+ if move.picking_id and move.picking_id.id not in seen:
wf_service.trg_write(uid, 'stock.picking', move.picking_id.id, cr)
+ seen.add(move.picking_id.id)
return True
#
done.append(move.id)
pickings[move.picking_id.id] = 1
r = res.pop(0)
- product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, ids, move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty']
+ product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, [move.id], move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty']
cr.execute('update stock_move set location_id=%s, product_qty=%s, product_uos_qty=%s where id=%s', (r[1], r[0],product_uos_qty, move.id))
while res:
r = res.pop(0)
+ product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, [move.id], move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty']
move_id = self.copy(cr, uid, move.id, {'product_uos_qty': product_uos_qty, 'product_qty': r[0], 'location_id': r[1]})
done.append(move_id)
if done:
if move.picking_id:
pickings.add(move.picking_id.id)
if move.move_dest_id and move.move_dest_id.state == 'waiting':
- self.write(cr, uid, [move.move_dest_id.id], {'state': 'assigned'})
+ self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}, context=context)
if context.get('call_unlink',False) and move.move_dest_id.picking_id:
wf_service = netsvc.LocalService("workflow")
wf_service.trg_write(uid, 'stock.picking', move.move_dest_id.picking_id.id, cr)
- self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False})
+ self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False}, context=context)
if not context.get('call_unlink',False):
for pick in self.pool.get('stock.picking').browse(cr, uid, list(pickings), context=context):
if all(move.state == 'cancel' for move in pick.move_lines):
- self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'})
+ self.pool.get('stock.picking').write(cr, uid, [pick.id], {'state': 'cancel'}, context=context)
wf_service = netsvc.LocalService("workflow")
for id in ids:
# if product is set to average price and a specific value was entered in the picking wizard,
# we use it
- if move.product_id.cost_method == 'average' and move.price_unit:
+ if move.location_dest_id.usage != 'internal' and move.product_id.cost_method == 'average':
+ reference_amount = qty * move.product_id.standard_price
+ elif move.product_id.cost_method == 'average' and move.price_unit:
reference_amount = qty * move.price_unit
reference_currency_id = move.price_currency_id.id or reference_currency_id
{
'journal_id': j_id,
'line_id': move_lines,
- 'ref': move.picking_id and move.picking_id.name})
-
+ 'ref': move.picking_id and move.picking_id.name}, context=context)
def action_done(self, cr, uid, ids, context=None):
""" Makes the move done and if all moves are done, it will finish the picking.
picking_ids.append(move.picking_id.id)
if move.move_dest_id.id and (move.state != 'done'):
# Downstream move should only be triggered if this move is the last pending upstream move
- other_upstream_move_ids = self.search(cr, uid, [('id','!=',move.id),('state','not in',['done','cancel']),
+ other_upstream_move_ids = self.search(cr, uid, [('id','not in',move_ids),('state','not in',['done','cancel']),
('move_dest_id','=',move.move_dest_id.id)], context=context)
if not other_upstream_move_ids:
self.write(cr, uid, [move.id], {'move_history_ids': [(4, move.move_dest_id.id)]})
if todo:
self.action_confirm(cr, uid, todo, context=context)
- self.write(cr, uid, move_ids, {'state': 'done', 'date': time.strftime('%Y-%m-%d %H:%M:%S')}, context=context)
+ self.write(cr, uid, move_ids, {'state': 'done', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
for id in move_ids:
wf_service.trg_trigger(uid, 'stock.move', id, cr)
# fix credit line:
credit_line_vals['credit'] = cur_obj.compute(cr, uid, reference_currency_id, src_main_currency_id, reference_amount, context=context)
if (not src_acct.currency_id) or src_acct.currency_id.id == reference_currency_id:
- credit_line_vals.update(currency_id=reference_currency_id, amount_currency=reference_amount)
+ credit_line_vals.update(currency_id=reference_currency_id, amount_currency=-reference_amount)
if reference_currency_id != dest_main_currency_id:
# fix debit line:
debit_line_vals['debit'] = cur_obj.compute(cr, uid, reference_currency_id, dest_main_currency_id, reference_amount, context=context)
quantity = move.product_qty
uos_qty = quantity / move_qty * move.product_uos_qty
- if quantity_rest > 0:
+ if float_compare(quantity_rest, 0, precision_rounding=move.product_id.uom_id.rounding):
default_val = {
'product_qty': quantity,
'product_uos_qty': uos_qty,
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
if qty > 0:
new_price = currency_obj.compute(cr, uid, product_currency,
- move_currency_id, product_price)
+ move_currency_id, product_price, round=False)
new_price = uom_obj._compute_price(cr, uid, product_uom, new_price,
product.uom_id.id)
if product.qty_available <= 0:
}
def _default_stock_location(self, cr, uid, context=None):
- stock_location = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_stock')
- return stock_location.id
+ try:
+ location_model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [location_id], 'read', context=context)
+ except (orm.except_orm, ValueError):
+ location_id = False
+ return location_id
_defaults = {
'location_id': _default_stock_location
}
def _default_lot_input_stock_id(self, cr, uid, context=None):
- lot_input_stock = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_stock')
- return lot_input_stock.id
+ try:
+ lot_input_stock_model, lot_input_stock_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [lot_input_stock_id], 'read', context=context)
+ except (ValueError, orm.except_orm):
+ # the user does not have read access on the location or it does not exists
+ lot_input_stock_id = False
+ return lot_input_stock_id
def _default_lot_output_id(self, cr, uid, context=None):
- lot_output = self.pool.get('ir.model.data').get_object(cr, uid, 'stock', 'stock_location_output')
- return lot_output.id
+ try:
+ lot_output_model, lot_output_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_output')
+ with tools.mute_logger('openerp.osv.orm'):
+ self.pool.get('stock.location').check_access_rule(cr, uid, [lot_output_id], 'read', context=context)
+ except (ValueError, orm.except_orm):
+ # the user does not have read access on the location or it does not exists
+ lot_output_id = False
+ return lot_output_id
_defaults = {
'company_id': lambda self, cr, uid, c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.inventory', context=c),
_table = "stock_picking"
_description = "Incoming Shipments"
+ def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
+ return self.pool.get('stock.picking').search(cr, user, args, offset, limit, order, context, count)
+
+ def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
+ return self.pool.get('stock.picking').read(cr, uid, ids, fields=fields, context=context, load=load)
+
+ def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
+ return self.pool['stock.picking'].read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
+
def check_access_rights(self, cr, uid, operation, raise_exception=True):
#override in order to redirect the check of acces rights on the stock.picking object
return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
#instead of it's own workflow (which is not existing)
return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+ def message_post(self, *args, **kwargs):
+ """Post the message on stock.picking to be able to see it in the form view when using the chatter"""
+ return self.pool.get('stock.picking').message_post(*args, **kwargs)
+
+ def message_subscribe(self, *args, **kwargs):
+ """Send the subscribe action on stock.picking model as it uses _name in request"""
+ return self.pool.get('stock.picking').message_subscribe(*args, **kwargs)
+
+ def message_unsubscribe(self, *args, **kwargs):
+ """Send the unsubscribe action on stock.picking model to match with subscribe"""
+ return self.pool.get('stock.picking').message_unsubscribe(*args, **kwargs)
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ # merge defaults from stock.picking with possible defaults defined on stock.picking.in
+ defaults = self.pool['stock.picking'].default_get(cr, uid, fields_list, context=context)
+ in_defaults = super(stock_picking_in, self).default_get(cr, uid, fields_list, context=context)
+ defaults.update(in_defaults)
+ return defaults
+
_columns = {
'backorder_id': fields.many2one('stock.picking.in', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
'state': fields.selection(
_table = "stock_picking"
_description = "Delivery Orders"
+ def search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False):
+ return self.pool.get('stock.picking').search(cr, user, args, offset, limit, order, context, count)
+
+ def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
+ return self.pool.get('stock.picking').read(cr, uid, ids, fields=fields, context=context, load=load)
+
+ def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
+ return self.pool['stock.picking'].read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
+
def check_access_rights(self, cr, uid, operation, raise_exception=True):
#override in order to redirect the check of acces rights on the stock.picking object
return self.pool.get('stock.picking').check_access_rights(cr, uid, operation, raise_exception=raise_exception)
#instead of it's own workflow (which is not existing)
return self.pool.get('stock.picking')._workflow_signal(cr, uid, ids, signal, context=context)
+ def message_post(self, *args, **kwargs):
+ """Post the message on stock.picking to be able to see it in the form view when using the chatter"""
+ return self.pool.get('stock.picking').message_post(*args, **kwargs)
+
+ def message_subscribe(self, *args, **kwargs):
+ """Send the subscribe action on stock.picking model as it uses _name in request"""
+ return self.pool.get('stock.picking').message_subscribe(*args, **kwargs)
+
+ def message_unsubscribe(self, *args, **kwargs):
+ """Send the unsubscribe action on stock.picking model to match with subscribe"""
+ return self.pool.get('stock.picking').message_unsubscribe(*args, **kwargs)
+
+ def default_get(self, cr, uid, fields_list, context=None):
+ # merge defaults from stock.picking with possible defaults defined on stock.picking.out
+ defaults = self.pool['stock.picking'].default_get(cr, uid, fields_list, context=context)
+ out_defaults = super(stock_picking_out, self).default_get(cr, uid, fields_list, context=context)
+ defaults.update(out_defaults)
+ return defaults
+
_columns = {
'backorder_id': fields.many2one('stock.picking.out', 'Back Order of', states={'done':[('readonly', True)], 'cancel':[('readonly',True)]}, help="If this shipment was split, then this field links to the shipment which contains the already processed part.", select=True),
'state': fields.selection(