Merge pull request #3601 from odoo-dev/8.0-wmsstagingx-jco
WMS STAGING X - scheduler cursor and company_id - digits in transfer wizard - delivery putting carrier on picking from sale and correctly invoicing it - inventory import: imported lines should not be deleted - average price correction for twice same product / variants - recreate picking from sale order - manual purchase order: picking type by default should depend on user's company
This commit is contained in:
commit
124b0a3f5d
|
@ -53,10 +53,6 @@ class sale_order(osv.Model):
|
||||||
result['value']['carrier_id'] = dtype
|
result['value']['carrier_id'] = dtype
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _prepare_order_picking(self, cr, uid, order, context=None):
|
|
||||||
result = super(sale_order, self)._prepare_order_picking(cr, uid, order, context=context)
|
|
||||||
result.update(carrier_id=order.carrier_id.id)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _delivery_unset(self, cr, uid, ids, context=None):
|
def _delivery_unset(self, cr, uid, ids, context=None):
|
||||||
sale_obj = self.pool['sale.order.line']
|
sale_obj = self.pool['sale.order.line']
|
||||||
|
@ -92,4 +88,4 @@ class sale_order(osv.Model):
|
||||||
'price_unit': grid_obj.get_price(cr, uid, grid.id, order, time.strftime('%Y-%m-%d'), context),
|
'price_unit': grid_obj.get_price(cr, uid, grid.id, order, time.strftime('%Y-%m-%d'), context),
|
||||||
'tax_id': [(6, 0, taxes_ids)],
|
'tax_id': [(6, 0, taxes_ids)],
|
||||||
'is_delivery': True
|
'is_delivery': True
|
||||||
})
|
})
|
|
@ -120,9 +120,10 @@ class stock_picking(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
|
def _create_invoice_from_picking(self, cr, uid, picking, vals, context=None):
|
||||||
|
invoice_obj = self.pool.get('account.invoice')
|
||||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||||
invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
|
invoice_id = super(stock_picking, self)._create_invoice_from_picking(cr, uid, picking, vals, context=context)
|
||||||
invoice = self.browse(cr, uid, invoice_id, context=context)
|
invoice = invoice_obj.browse(cr, uid, invoice_id, context=context)
|
||||||
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
|
invoice_line = self._prepare_shipping_invoice_line(cr, uid, picking, invoice, context=context)
|
||||||
if invoice_line:
|
if invoice_line:
|
||||||
invoice_line_obj.create(cr, uid, invoice_line)
|
invoice_line_obj.create(cr, uid, invoice_line)
|
||||||
|
@ -170,6 +171,24 @@ class stock_move(osv.osv):
|
||||||
'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of Measure (Unit of Measure) is the unit of measurement for Weight",),
|
'weight_uom_id': fields.many2one('product.uom', 'Unit of Measure', required=True,readonly="1",help="Unit of Measure (Unit of Measure) is the unit of measurement for Weight",),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def action_confirm(self, cr, uid, ids, context=None):
|
||||||
|
"""
|
||||||
|
Pass the carrier to the picking from the sales order
|
||||||
|
(Should also work in case of Phantom BoMs when on explosion the original move is deleted)
|
||||||
|
"""
|
||||||
|
procs_to_check = []
|
||||||
|
for move in self.browse(cr, uid, ids, context=context):
|
||||||
|
if move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.carrier_id:
|
||||||
|
procs_to_check += [move.procurement_id]
|
||||||
|
res = super(stock_move, self).action_confirm(cr, uid, ids, context=context)
|
||||||
|
pick_obj = self.pool.get("stock.picking")
|
||||||
|
for proc in procs_to_check:
|
||||||
|
pickings = list(set([x.picking_id.id for x in proc.move_ids if x.picking_id and not x.picking_id.carrier_id]))
|
||||||
|
if pickings:
|
||||||
|
pick_obj.write(cr, uid, pickings, {'carrier_id': proc.sale_line_id.order_id.carrier_id.id}, context=context)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def _get_default_uom(self, cr, uid, context=None):
|
def _get_default_uom(self, cr, uid, context=None):
|
||||||
uom_categ_id = self.pool.get('ir.model.data').xmlid_to_res_id(cr, uid, 'product.product_uom_categ_kgm')
|
uom_categ_id = self.pool.get('ir.model.data').xmlid_to_res_id(cr, uid, 'product.product_uom_categ_kgm')
|
||||||
return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id),('factor','=',1)])[0]
|
return self.pool.get('product.uom').search(cr, uid, [('category_id', '=', uom_categ_id),('factor','=',1)])[0]
|
||||||
|
|
|
@ -150,7 +150,20 @@ class purchase_order(osv.osv):
|
||||||
|
|
||||||
def _get_picking_in(self, cr, uid, context=None):
|
def _get_picking_in(self, cr, uid, context=None):
|
||||||
obj_data = self.pool.get('ir.model.data')
|
obj_data = self.pool.get('ir.model.data')
|
||||||
return obj_data.get_object_reference(cr, uid, 'stock','picking_type_in') and obj_data.get_object_reference(cr, uid, 'stock','picking_type_in')[1] or False
|
type_obj = self.pool.get('stock.picking.type')
|
||||||
|
user_obj = self.pool.get('res.users')
|
||||||
|
company_id = user_obj.browse(cr, uid, uid, context=context).company_id.id
|
||||||
|
pick_type = obj_data.get_object_reference(cr, uid, 'stock', 'picking_type_in') and obj_data.get_object_reference(cr, uid, 'stock', 'picking_type_in')[1] or False
|
||||||
|
if pick_type:
|
||||||
|
type = type_obj.browse(cr, uid, pick_type, context=context)
|
||||||
|
if type and type.warehouse_id and type.warehouse_id.company_id.id == company_id:
|
||||||
|
return pick_type
|
||||||
|
types = type_obj.search(cr, uid, [('code', '=', 'incoming'), ('warehouse_id.company_id', '=', company_id)], context=context)
|
||||||
|
if not types:
|
||||||
|
types = type_obj.search(cr, uid, [('code', '=', 'incoming'), ('warehouse_id', '=', False)], context=context)
|
||||||
|
if not types:
|
||||||
|
raise osv.except_osv(_('Error!'), _("Make sure you have at least an incoming picking type defined"))
|
||||||
|
return types[0]
|
||||||
|
|
||||||
def _get_picking_ids(self, cr, uid, ids, field_names, args, context=None):
|
def _get_picking_ids(self, cr, uid, ids, field_names, args, context=None):
|
||||||
res = {}
|
res = {}
|
||||||
|
|
|
@ -712,10 +712,11 @@ class sale_order(osv.osv):
|
||||||
line.refresh()
|
line.refresh()
|
||||||
#run again procurement that are in exception in order to trigger another move
|
#run again procurement that are in exception in order to trigger another move
|
||||||
proc_ids += [x.id for x in line.procurement_ids if x.state in ('exception', 'cancel')]
|
proc_ids += [x.id for x in line.procurement_ids if x.state in ('exception', 'cancel')]
|
||||||
|
procurement_obj.reset_to_confirmed(cr, uid, proc_ids, context=context)
|
||||||
elif sale_line_obj.need_procurement(cr, uid, [line.id], context=context):
|
elif sale_line_obj.need_procurement(cr, uid, [line.id], context=context):
|
||||||
if (line.state == 'done') or not line.product_id:
|
if (line.state == 'done') or not line.product_id:
|
||||||
continue
|
continue
|
||||||
vals = self._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context)
|
vals = self._prepare_order_line_procurement(cr, uid, order, line, group_id=order.procurement_group_id.id, context=context)
|
||||||
proc_id = procurement_obj.create(cr, uid, vals, context=context)
|
proc_id = procurement_obj.create(cr, uid, vals, context=context)
|
||||||
proc_ids.append(proc_id)
|
proc_ids.append(proc_id)
|
||||||
#Confirm procurement order such that rules will be applied on it
|
#Confirm procurement order such that rules will be applied on it
|
||||||
|
|
|
@ -59,7 +59,7 @@ Some statistics by journals are provided.
|
||||||
],
|
],
|
||||||
'demo': ['sale_journal_demo.xml'],
|
'demo': ['sale_journal_demo.xml'],
|
||||||
'test': [ ],
|
'test': [ ],
|
||||||
'installable': True,
|
'installable': False,
|
||||||
'auto_install': False,
|
'auto_install': False,
|
||||||
}
|
}
|
||||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||||
|
|
|
@ -38,17 +38,11 @@
|
||||||
<xpath expr="//field[@name='order_line']/tree//field[@name='product_uom_qty']" position="replace">
|
<xpath expr="//field[@name='order_line']/tree//field[@name='product_uom_qty']" position="replace">
|
||||||
<field context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
<field context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||||
name="product_uom_qty"
|
name="product_uom_qty"
|
||||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position, True, parent.warehouse_id, context)"/>
|
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,False,name,parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position, True, parent.warehouse_id, context)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="replace">
|
<xpath expr="//field[@name='order_line']/form//field[@name='product_uos_qty']" position="replace">
|
||||||
<field name="product_id"
|
<field context="{'partner_id':parent.partner_id, 'quantity':product_uos_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
name="product_uos_qty" class="oe_inline"
|
||||||
groups="base.group_user"
|
|
||||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position, False, parent.warehouse_id, context)"/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_uom_qty']" position="replace">
|
|
||||||
<field context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
|
||||||
name="product_uom_qty" class="oe_inline"
|
|
||||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position, True, parent.warehouse_id, context)"/>
|
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position, True, parent.warehouse_id, context)"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ class procurement_order(osv.osv):
|
||||||
@param context: A standard dictionary for contextual values
|
@param context: A standard dictionary for contextual values
|
||||||
@return: Dictionary of values
|
@return: Dictionary of values
|
||||||
'''
|
'''
|
||||||
super(procurement_order, self).run_scheduler(cr, uid, use_new_cursor=use_new_cursor, context=context)
|
super(procurement_order, self).run_scheduler(cr, uid, use_new_cursor=use_new_cursor, company_id=company_id, context=context)
|
||||||
if context is None:
|
if context is None:
|
||||||
context = {}
|
context = {}
|
||||||
try:
|
try:
|
||||||
|
@ -283,7 +283,7 @@ class procurement_order(osv.osv):
|
||||||
move_obj = self.pool.get('stock.move')
|
move_obj = self.pool.get('stock.move')
|
||||||
|
|
||||||
#Minimum stock rules
|
#Minimum stock rules
|
||||||
self._procure_orderpoint_confirm(cr, SUPERUSER_ID, use_new_cursor=False, company_id=company_id, context=context)
|
self._procure_orderpoint_confirm(cr, SUPERUSER_ID, use_new_cursor=use_new_cursor, company_id=company_id, context=context)
|
||||||
|
|
||||||
#Search all confirmed stock_moves and try to assign them
|
#Search all confirmed stock_moves and try to assign them
|
||||||
confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed')], limit=None, order='priority desc, date_expected asc', context=context)
|
confirmed_ids = move_obj.search(cr, uid, [('state', '=', 'confirmed')], limit=None, order='priority desc, date_expected asc', context=context)
|
||||||
|
|
|
@ -2640,13 +2640,27 @@ class stock_inventory(osv.osv):
|
||||||
def prepare_inventory(self, cr, uid, ids, context=None):
|
def prepare_inventory(self, cr, uid, ids, context=None):
|
||||||
inventory_line_obj = self.pool.get('stock.inventory.line')
|
inventory_line_obj = self.pool.get('stock.inventory.line')
|
||||||
for inventory in self.browse(cr, uid, ids, context=context):
|
for inventory in self.browse(cr, uid, ids, context=context):
|
||||||
#clean the existing inventory lines before redoing an inventory proposal
|
# If there are inventory lines already (e.g. from import), respect those and set their theoretical qty
|
||||||
line_ids = [line.id for line in inventory.line_ids]
|
line_ids = [line.id for line in inventory.line_ids]
|
||||||
inventory_line_obj.unlink(cr, uid, line_ids, context=context)
|
if not line_ids:
|
||||||
#compute the inventory lines and create them
|
#compute the inventory lines and create them
|
||||||
vals = self._get_inventory_lines(cr, uid, inventory, context=context)
|
vals = self._get_inventory_lines(cr, uid, inventory, context=context)
|
||||||
for product_line in vals:
|
for product_line in vals:
|
||||||
inventory_line_obj.create(cr, uid, product_line, context=context)
|
inventory_line_obj.create(cr, uid, product_line, context=context)
|
||||||
|
else:
|
||||||
|
# On import calculate theoretical quantity
|
||||||
|
quant_obj = self.pool.get("stock.quant")
|
||||||
|
for line in inventory.line_ids:
|
||||||
|
dom = [('company_id', '=', line.company_id.id), ('location_id', 'child_of', line.location_id.id), ('lot_id', '=', line.prod_lot_id.id),
|
||||||
|
('product_id','=', line.product_id.id), ('owner_id', '=', line.partner_id.id)]
|
||||||
|
if line.package_id:
|
||||||
|
dom += [('package_id', '=', line.package_id.id)]
|
||||||
|
quants = quant_obj.search(cr, uid, dom, context=context)
|
||||||
|
tot_qty = 0
|
||||||
|
for quant in quant_obj.browse(cr, uid, quants, context=context):
|
||||||
|
tot_qty += quant.qty
|
||||||
|
inventory_line_obj.write(cr, uid, [line.id], {'theoretical_qty': tot_qty}, context=context)
|
||||||
|
|
||||||
return self.write(cr, uid, ids, {'state': 'confirm', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
|
return self.write(cr, uid, ids, {'state': 'confirm', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
|
||||||
|
|
||||||
def _get_inventory_lines(self, cr, uid, inventory, context=None):
|
def _get_inventory_lines(self, cr, uid, inventory, context=None):
|
||||||
|
@ -2712,7 +2726,7 @@ class stock_inventory_line(osv.osv):
|
||||||
'company_id': fields.related('inventory_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, select=True, readonly=True),
|
'company_id': fields.related('inventory_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, select=True, readonly=True),
|
||||||
'prod_lot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"),
|
'prod_lot_id': fields.many2one('stock.production.lot', 'Serial Number', domain="[('product_id','=',product_id)]"),
|
||||||
'state': fields.related('inventory_id', 'state', type='char', string='Status', readonly=True),
|
'state': fields.related('inventory_id', 'state', type='char', string='Status', readonly=True),
|
||||||
'theoretical_qty': fields.float('Theoretical Quantity', readonly=True),
|
'theoretical_qty': fields.float('Theoretical Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), readonly=True),
|
||||||
'partner_id': fields.many2one('res.partner', 'Owner'),
|
'partner_id': fields.many2one('res.partner', 'Owner'),
|
||||||
'product_name': fields.related('product_id', 'name', type='char', string='Product Name', store={
|
'product_name': fields.related('product_id', 'name', type='char', string='Product Name', store={
|
||||||
'product.product': (_get_product_name_change, ['name', 'default_code'], 20),
|
'product.product': (_get_product_name_change, ['name', 'default_code'], 20),
|
||||||
|
|
|
@ -1093,7 +1093,7 @@
|
||||||
</group>
|
</group>
|
||||||
<group string="Locations" groups="stock.group_locations">
|
<group string="Locations" groups="stock.group_locations">
|
||||||
<field name="location_id" domain="[('usage','<>','view')]"/>
|
<field name="location_id" domain="[('usage','<>','view')]"/>
|
||||||
<field name="location_dest_id" domain="[('usage','=','internal')]"/>
|
<field name="location_dest_id" domain="[('usage','<>','view')]"/>
|
||||||
</group>
|
</group>
|
||||||
<group name="quants_grp" string="Reserved Quants" colspan="4" groups="base.group_no_one">
|
<group name="quants_grp" string="Reserved Quants" colspan="4" groups="base.group_no_one">
|
||||||
<field name="reserved_quant_ids"/>
|
<field name="reserved_quant_ids"/>
|
||||||
|
@ -1662,7 +1662,7 @@
|
||||||
<field name="model">stock.quant</field>
|
<field name="model">stock.quant</field>
|
||||||
<field eval="10" name="priority"/>
|
<field eval="10" name="priority"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Quants">
|
<form string="Quants" create="false" edit="false">
|
||||||
<div class="oe_right oe_button_box">
|
<div class="oe_right oe_button_box">
|
||||||
<button name="action_view_quant_history" type="object" string="Quant History"/>
|
<button name="action_view_quant_history" type="object" string="Quant History"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -133,7 +133,7 @@ class stock_transfer_details_items(models.TransientModel):
|
||||||
packop_id = fields.Many2one('stock.pack.operation', 'Operation')
|
packop_id = fields.Many2one('stock.pack.operation', 'Operation')
|
||||||
product_id = fields.Many2one('product.product', 'Product')
|
product_id = fields.Many2one('product.product', 'Product')
|
||||||
product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure')
|
product_uom_id = fields.Many2one('product.uom', 'Product Unit of Measure')
|
||||||
quantity = fields.Float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), default = 1.0)
|
quantity = fields.Float('Quantity', digits=dp.get_precision('Product Unit of Measure'), default = 1.0)
|
||||||
package_id = fields.Many2one('stock.quant.package', 'Source package', domain="['|', ('location_id', 'child_of', sourceloc_id), ('location_id','=',False)]")
|
package_id = fields.Many2one('stock.quant.package', 'Source package', domain="['|', ('location_id', 'child_of', sourceloc_id), ('location_id','=',False)]")
|
||||||
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
|
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
|
||||||
sourceloc_id = fields.Many2one('stock.location', 'Source Location', required=True)
|
sourceloc_id = fields.Many2one('stock.location', 'Source Location', required=True)
|
||||||
|
|
|
@ -282,17 +282,25 @@ class stock_move(osv.osv):
|
||||||
|
|
||||||
def product_price_update_before_done(self, cr, uid, ids, context=None):
|
def product_price_update_before_done(self, cr, uid, ids, context=None):
|
||||||
product_obj = self.pool.get('product.product')
|
product_obj = self.pool.get('product.product')
|
||||||
|
tmpl_dict = {}
|
||||||
for move in self.browse(cr, uid, ids, context=context):
|
for move in self.browse(cr, uid, ids, context=context):
|
||||||
#adapt standard price on incomming moves if the product cost_method is 'average'
|
#adapt standard price on incomming moves if the product cost_method is 'average'
|
||||||
if (move.location_id.usage == 'supplier') and (move.product_id.cost_method == 'average'):
|
if (move.location_id.usage == 'supplier') and (move.product_id.cost_method == 'average'):
|
||||||
product = move.product_id
|
product = move.product_id
|
||||||
product_avail = product.qty_available
|
prod_tmpl_id = move.product_id.product_tmpl_id.id
|
||||||
if product.qty_available <= 0:
|
qty_available = move.product_id.product_tmpl_id.qty_available
|
||||||
|
if tmpl_dict.get(prod_tmpl_id):
|
||||||
|
product_avail = qty_available + tmpl_dict[prod_tmpl_id]
|
||||||
|
else:
|
||||||
|
tmpl_dict[prod_tmpl_id] = 0
|
||||||
|
product_avail = qty_available
|
||||||
|
if product_avail <= 0:
|
||||||
new_std_price = move.price_unit
|
new_std_price = move.price_unit
|
||||||
else:
|
else:
|
||||||
# Get the standard price
|
# Get the standard price
|
||||||
amount_unit = product.standard_price
|
amount_unit = product.standard_price
|
||||||
new_std_price = ((amount_unit * product_avail) + (move.price_unit * move.product_qty)) / (product_avail + move.product_qty)
|
new_std_price = ((amount_unit * product_avail) + (move.price_unit * move.product_qty)) / (product_avail + move.product_qty)
|
||||||
|
tmpl_dict[prod_tmpl_id] += move.product_qty
|
||||||
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
|
# Write the standard price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
|
||||||
product_obj.write(cr, SUPERUSER_ID, [product.id], {'standard_price': new_std_price}, context=context)
|
product_obj.write(cr, SUPERUSER_ID, [product.id], {'standard_price': new_std_price}, context=context)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue