[IMP] Change inventory report with quants, add putaway strategies
bzr revid: jco@openerp.com-20130625144059-vejvwrbdmttay94s
This commit is contained in:
parent
58b2b57fa3
commit
11b680869f
|
@ -216,40 +216,71 @@ class report_stock_inventory(osv.osv):
|
|||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_stock_inventory')
|
||||
cr.execute("""
|
||||
CREATE OR REPLACE view report_stock_inventory AS (
|
||||
|
||||
SELECT
|
||||
m.id as id, m.date as date,
|
||||
to_char(m.date, 'YYYY') as year,
|
||||
to_char(m.date, 'MM') as month,
|
||||
m.partner_id as partner_id, m.location_dest_id as location_id,
|
||||
m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type, l.scrap_location as scrap_location,
|
||||
m.company_id,
|
||||
m.state as state, m.prodlot_id as prodlot_id,
|
||||
coalesce(sum(m.price_unit * m.qty_remaining)::decimal, 0.0) as value,
|
||||
coalesce(sum(m.qty_remaining * pu.factor / pu2.factor)::decimal, 0.0) as product_qty,
|
||||
p.name as ref,
|
||||
l.usage as location_dest_type,
|
||||
l_other.usage as location_src_type
|
||||
FROM
|
||||
stock_move m
|
||||
LEFT JOIN stock_picking p ON (m.picking_id=p.id)
|
||||
LEFT JOIN product_product pp ON (m.product_id=pp.id)
|
||||
LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
|
||||
LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
|
||||
LEFT JOIN product_uom pu2 ON (m.product_uom=pu2.id)
|
||||
LEFT JOIN product_uom u ON (m.product_uom=u.id)
|
||||
LEFT JOIN stock_location l ON (m.location_dest_id=l.id)
|
||||
LEFT JOIN stock_location l_other ON (m.location_id=l_other.id)
|
||||
WHERE m.state != 'cancel'
|
||||
GROUP BY
|
||||
m.id, m.product_id, m.product_uom, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
|
||||
m.prodlot_id, m.date, m.state, l.usage, l_other.usage, l.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'), p.name
|
||||
);
|
||||
CREATE OR REPLACE view report_stock_inventory AS (
|
||||
SELECT
|
||||
sq.id as id, sq.in_date as date,
|
||||
to_char(sq.in_date, 'YYYY') as year,
|
||||
to_char(sq.in_date, 'MM') as month,
|
||||
m.partner_id as partner_id, sq.location_id as location_id,
|
||||
sq.product_id as product_id, pt.categ_id as product_categ_id, location.usage as location_type, location.scrap_location as scrap_location,
|
||||
sq.company_id,
|
||||
m.state as state, sq.prodlot_id as prodlot_id,
|
||||
sq.price_unit * sq.qty as value,
|
||||
sq.qty as product_qty,
|
||||
p.name as ref,
|
||||
location_dest.usage as location_dest_type,
|
||||
location.usage as location_src_type
|
||||
FROM stock_quant sq
|
||||
LEFT JOIN quant_move_rel qm ON (qm.quant_id = sq.id)
|
||||
LEFT JOIN stock_move m ON (qm.move_id = m.id)
|
||||
LEFT JOIN stock_picking p ON (m.picking_id=p.id)
|
||||
LEFT JOIN stock_location location ON (m.location_id = location.id)
|
||||
LEFT JOIN stock_location location_dest ON (m.location_dest_id = location_dest.id)
|
||||
LEFT JOIN product_template pt ON (sq.product_id=pt.id)
|
||||
WHERE location_dest.usage = 'internal' and location.usage <> 'internal'
|
||||
GROUP BY
|
||||
sq.id, sq.product_id, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
|
||||
sq.prodlot_id, sq.in_date, m.state, location.usage, location_dest.usage, location.scrap_location, sq.company_id, to_char(sq.in_date, 'YYYY'), to_char(sq.in_date, 'MM'), p.name
|
||||
);
|
||||
""")
|
||||
|
||||
|
||||
|
||||
#
|
||||
# CREATE OR REPLACE view report_stock_inventory AS (
|
||||
#
|
||||
# SELECT
|
||||
# m.id as id, m.date as date,
|
||||
# to_char(m.date, 'YYYY') as year,
|
||||
# to_char(m.date, 'MM') as month,
|
||||
# m.partner_id as partner_id, m.location_dest_id as location_id,
|
||||
# m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type, l.scrap_location as scrap_location,
|
||||
# m.company_id,
|
||||
# m.state as state, m.prodlot_id as prodlot_id,
|
||||
# coalesce(sum(m.price_unit * m.qty_remaining)::decimal, 0.0) as value,
|
||||
# coalesce(sum(m.qty_remaining * pu.factor / pu2.factor)::decimal, 0.0) as product_qty,
|
||||
# p.name as ref,
|
||||
# l.usage as location_dest_type,
|
||||
# l_other.usage as location_src_type
|
||||
# FROM
|
||||
# stock_move m
|
||||
# LEFT JOIN stock_picking p ON (m.picking_id=p.id)
|
||||
# LEFT JOIN product_product pp ON (m.product_id=pp.id)
|
||||
# LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
|
||||
# LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
|
||||
# LEFT JOIN product_uom pu2 ON (m.product_uom=pu2.id)
|
||||
# LEFT JOIN product_uom u ON (m.product_uom=u.id)
|
||||
# LEFT JOIN stock_location l ON (m.location_dest_id=l.id)
|
||||
# LEFT JOIN stock_location l_other ON (m.location_id=l_other.id)
|
||||
# WHERE m.state != 'cancel'
|
||||
# GROUP BY
|
||||
# m.id, m.product_id, m.product_uom, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
|
||||
# m.prodlot_id, m.date, m.state, l.usage, l_other.usage, l.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'), p.name
|
||||
# );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class report_stock_valuation(osv.osv):
|
||||
_name = "report.stock.valuation"
|
||||
|
|
|
@ -212,6 +212,8 @@ class stock_location(osv.osv):
|
|||
"this account will be used to hold the value of products being moved out of this location "
|
||||
"and into an internal location, instead of the generic Stock Output Account set on the product. "
|
||||
"This has no effect for internal locations."),
|
||||
'quant_ids': fields.one2many('stock.quant', 'location_id', 'Quants associated with this location'),
|
||||
'destination_move_ids': fields.one2many('stock.move', 'location_dest_id', 'Destination moves'),
|
||||
}
|
||||
_defaults = {
|
||||
'active': True,
|
||||
|
@ -628,7 +630,7 @@ class stock_quant(osv.osv):
|
|||
product_uom_price = uom_obj._compute_price(cr, uid, move.product_uom.id, move.price_unit, move.product_id.uom_id.id)
|
||||
qty_to_go = product_uom_qty
|
||||
if neg_quants:
|
||||
recres = self.reconcile_negative_quants(cr, uid, neg_quants, move, qty_to_go, product_uom_price, context)
|
||||
recres = self.reconcile_negative_quants(cr, uid, neg_quants, move, qty_to_go, product_uom_price, context=context)
|
||||
product_uom_qty = recres['amount']
|
||||
quants_rec += recres['refreshed_quants']
|
||||
if product_uom_qty > 0.0:
|
||||
|
@ -638,9 +640,10 @@ class stock_quant(osv.osv):
|
|||
'price_unit': product_uom_price,
|
||||
'history_ids': [(4, move.id)],
|
||||
'in_date': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'prodlot_id': move.prodlot_id.id,
|
||||
'company_id': move.company_id.id,
|
||||
}
|
||||
quant_id = self.pool.get("stock.quant").create(cr, uid, vals, context=context)
|
||||
print "Negative quants, ", quants_rec,self.filter_quants_with_out_history(cr, uid, quants_rec, context=context)
|
||||
return self.filter_quants_with_out_history(cr, uid, quants_rec, context=context)
|
||||
|
||||
|
||||
|
@ -693,10 +696,12 @@ class stock_quant(osv.osv):
|
|||
:param location_id: child_of this location_id
|
||||
:param product_id: id of product
|
||||
:param qty in UoM of product
|
||||
:TODOparam prodlot_id
|
||||
:returns: tuples of (quant_id, qty)
|
||||
"""
|
||||
#TODO Normally, you should check the removal strategy now
|
||||
#But we will assume it is FIFO for the moment
|
||||
#Will need to create search string beforehand
|
||||
if self.pool.get('stock.location').get_removal_strategy(cr, uid, location_id, product_id, context=context) == 'lifo':
|
||||
possible_quants = self.search(cr, uid, [('location_id', 'child_of', location_id), ('product_id','=',product_id),
|
||||
('qty', '>', 0.0), ('reservation_id', '=', False)], order = 'in_date desc, id desc', context=context)
|
||||
|
@ -1063,7 +1068,7 @@ class stock_picking(osv.osv):
|
|||
@return: True
|
||||
"""
|
||||
for picking in self.browse(cr, uid, ids, context=context):
|
||||
self.pool.get('stock.move').action_assign(cr, uid, [move.id for move in picking.move_lines], context=context)
|
||||
self.pool.get('stock.move').action_assign(cr, uid, [move.id for move in picking.move_lines])
|
||||
self.write(cr, uid, ids, {'state': 'assigned'})
|
||||
return True
|
||||
|
||||
|
@ -2323,6 +2328,10 @@ class stock_move(osv.osv):
|
|||
new_moves += self.create_chained_picking(cr, uid, new_moves, context)
|
||||
return new_moves
|
||||
|
||||
|
||||
def splitforputaway (self, cr, uid, ids, context=None):
|
||||
return True
|
||||
|
||||
def action_confirm(self, cr, uid, ids, context=None):
|
||||
""" Confirms stock move.
|
||||
@return: List of ids.
|
||||
|
@ -2381,6 +2390,7 @@ class stock_move(osv.osv):
|
|||
pickings = {}
|
||||
quant_obj = self.pool.get("stock.quant")
|
||||
uom_obj = self.pool.get("product.uom")
|
||||
print "check assign ", ids
|
||||
if context is None:
|
||||
context = {}
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
|
@ -2389,13 +2399,17 @@ class stock_move(osv.osv):
|
|||
done.append(move.id)
|
||||
pickings[move.picking_id.id] = 1
|
||||
continue
|
||||
print "move state:", move.state
|
||||
if move.state in ('confirmed', 'waiting'):
|
||||
# Important: we must pass lock=True to _product_reserve() to avoid race conditions and double reservations
|
||||
# res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True)
|
||||
|
||||
#Convert UoM qty -> check rounding now in product_reserver
|
||||
|
||||
#Split for source locations
|
||||
qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
|
||||
res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, context=context)
|
||||
print res2
|
||||
#Should group quants by location:
|
||||
quants = {}
|
||||
qtys = {}
|
||||
|
@ -2428,7 +2442,10 @@ class stock_move(osv.osv):
|
|||
r = res.pop(0)
|
||||
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)
|
||||
|
||||
|
||||
self.splitforputaway(cr, uid, [move.id], context=context)
|
||||
|
||||
|
||||
if done:
|
||||
count += len(done)
|
||||
self.write(cr, uid, done, {'state': 'assigned'})
|
||||
|
@ -2646,7 +2663,6 @@ class stock_move(osv.osv):
|
|||
for move in self.browse(cr, uid, ids, context=context):
|
||||
#Split according to pack wizard if necessary
|
||||
res[move.id] = [x.id for x in move.reserved_quant_ids]
|
||||
print "Get quants", move.reserved_quant_ids
|
||||
return res
|
||||
|
||||
|
||||
|
@ -2661,10 +2677,8 @@ class stock_move(osv.osv):
|
|||
uom_obj = self.pool.get("product.uom")
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
product_qty = 0.0
|
||||
print "Reserved quants", move.reserved_quant_ids
|
||||
for quant in move.reserved_quant_ids:
|
||||
product_qty += quant.qty
|
||||
print "quantity to SUM, ", quant.qty, product_qty
|
||||
qty_from_move = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
|
||||
#Check if the entire quantity has been transformed in to quants
|
||||
if qty_from_move > product_qty:
|
||||
|
@ -2675,10 +2689,8 @@ class stock_move(osv.osv):
|
|||
product_qty = 0.0
|
||||
for quant in move.reserved_quant_ids:
|
||||
product_qty += quant.qty
|
||||
print "QTYFROMMOVE", qty_from_move, product_qty
|
||||
if qty_from_move <= product_qty:
|
||||
create_neg_quant = False
|
||||
print create_neg_quant
|
||||
if create_neg_quant:
|
||||
#To solve this, we should create a negative quant at destination and a positive quant at the source
|
||||
vals_neg = {
|
||||
|
@ -3058,7 +3070,6 @@ class stock_move(osv.osv):
|
|||
quants_dict = quant_obj.get_out_moves_from_quants(cr, uid, quants, context=context)
|
||||
for out_mov in self.browse(cr, uid, quants_dict.keys(), context=context):
|
||||
quants_from_move = quant_obj.search(cr, uid, [('history_ids', 'in', out_mov.id), ('propagated_from_id', '=', False)], context=context)
|
||||
print "Quants from move", quants_from_move
|
||||
out_qty_converted = uom_obj._compute_qty(cr, uid, out_mov.product_uom.id, out_mov.product_qty, move.product_uom.id, round=False)
|
||||
amount = 0.0
|
||||
total_price = 0.0
|
||||
|
|
|
@ -136,14 +136,12 @@ class product_product(osv.osv):
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class product_category(osv.osv):
|
||||
_inherit = 'product.category'
|
||||
_columns = {
|
||||
#'route_ids': fields.many2many('stock.route', 'product_catg_id', 'route_id', 'Routes'),
|
||||
'removal_strategy_ids': fields.many2many('product.removal', 'product_catg_id', 'removal_strat_id' 'Removal Strategies'),
|
||||
'putaway_strategy_ids': fields.many2many('product.putaway', 'product_catg_id', 'putaway_strat_id', 'Put Away Strategies'),
|
||||
'removal_strategy_ids': fields.one2many('product.removal', 'product_categ_id', 'Removal Strategies'),
|
||||
'putaway_strategy_ids': fields.one2many('product.putaway', 'product_categ_id', 'Put Away Strategies'),
|
||||
}
|
||||
|
||||
|
||||
|
@ -161,6 +159,26 @@ class stock_move(osv.osv):
|
|||
res = super(stock_move,self).action_cancel(cr,uid,ids,context)
|
||||
return res
|
||||
|
||||
def splitforputaway (self, cr, uid, ids, context=None):
|
||||
'''
|
||||
Splits this move in order to do the put away
|
||||
'''
|
||||
putaway_obj = self.pool.get("product.putaway")
|
||||
location_obj = self.pool.get("stock.location")
|
||||
print "SPLIT FOR PUTAWAY"
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
putaways = putaway_obj.search(cr, uid, [('product_categ_id','=', move.product_id.categ_id.id), ('location_id', '=', move.location_dest_id.id)], context=context)
|
||||
print putaways
|
||||
if putaways:
|
||||
#Search for locations for PutAway
|
||||
locs = location_obj.search(cr, uid, [('id', 'child_of', move.location_dest_id.id), ('id', '!=', move.location_dest_id.id), ('quant_ids', '=', False),
|
||||
('destination_move_ids', '=', False)], context=context)
|
||||
if locs:
|
||||
self.write(cr, uid, [move.id], {'location_dest_id': locs[0]}, context=context)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def _prepare_chained_picking(self, cr, uid, picking_name, picking, picking_type, moves_todo, context=None):
|
||||
res = super(stock_move, self)._prepare_chained_picking(cr, uid, picking_name, picking, picking_type, moves_todo, context=context)
|
||||
res.update({'invoice_state': moves_todo[0][1][6] or 'none'})
|
||||
|
@ -169,8 +187,8 @@ class stock_move(osv.osv):
|
|||
class stock_location(osv.osv):
|
||||
_inherit = 'stock.location'
|
||||
_columns = {
|
||||
'removal_strategy_ids': fields.many2many('product.removal', 'location_id', 'removal_strat_id' 'Removal Strategies'),
|
||||
'putaway_strategy_ids': fields.many2many('product.putaway', 'location_id', 'putaway_strat_id', 'Put Away Strategies'),
|
||||
'removal_strategy_ids': fields.one2many('product.removal', 'location_id', 'Removal Strategies'),
|
||||
'putaway_strategy_ids': fields.one2many('product.putaway', 'location_id', 'Put Away Strategies'),
|
||||
}
|
||||
|
||||
|
||||
|
@ -183,7 +201,7 @@ class stock_location(osv.osv):
|
|||
product = self.pool.get("product.product").browse(cr, uid, product_id, context=context)
|
||||
strats = self.pool.get('product.removal').search(cr, uid, [('location_id','=',id), ('product_categ_id','child_of', product.categ_id.id)], context=context) #Also child_of for location???
|
||||
if not strats:
|
||||
strat = product.categ_id.removal_strategy
|
||||
strat = product.categ_id.removal_strategy
|
||||
else:
|
||||
strat = strats[0]
|
||||
return strat or product.categ_id.removal_strategy or 'fifo'
|
||||
|
|
|
@ -97,5 +97,32 @@
|
|||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="product_category_form_view_inherit" model="ir.ui.view">
|
||||
<field name="name">product.category.form</field>
|
||||
<field name="model">product.category</field>
|
||||
<field name="inherit_id" ref="product.product_category_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="parent" position="after">
|
||||
<separator name="Strategy"/>
|
||||
<group name="Strategies">
|
||||
<field name = "putaway_strategy_ids">
|
||||
<tree string="Put Away strategies" editable="top">
|
||||
<field name="location_id"/>
|
||||
<field name="method"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name = "removal_strategy_ids" >
|
||||
<tree string="Removal strategies" editable="top">
|
||||
<field name="location_id"/>
|
||||
<field name="method"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
Loading…
Reference in New Issue