diff --git a/addons/purchase/test/fifo_price.yml b/addons/purchase/test/fifo_price.yml index a9993645d11..70f2e13ccc7 100644 --- a/addons/purchase/test/fifo_price.yml +++ b/addons/purchase/test/fifo_price.yml @@ -248,16 +248,29 @@ for move in self.pool.get("stock.move").browse(cr, uid, list): print move.price_unit, move.product_qty, move.qty_remaining, move.type, move.date - - Return the goods of purchase order 1 + Do a delivery of an extra 10 kg INSTEAD OF RETURN - - !python {model: stock.return.picking}: | - pick_ids = self.pool.get('purchase.order').browse(cr, uid, ref("purchase_order_fifo1")).picking_ids - return_id = self.create(cr, uid, {}, context={'active_model':'stock.picking', 'active_id': pick_ids[0].id}) - res = self.create_returns(cr, uid, [return_id], context={'active_id': pick_ids[0].id}) - return_move_id = self.pool.get("stock.move").search(cr, uid, [('move_returned_from','=', pick_ids[0].move_lines[0].id)]) - movepick_obj = self.pool.get("stock.partial.move") - movepick_id = movepick_obj.create(cr, uid, {}, context={'active_model': 'stock.move', 'active_ids': return_move_id}) - movepick_obj.do_partial(cr, uid, [movepick_id]) + !record {model: stock.picking, id: outgoing_fifo_shipment_ret}: + type: out +- + Picking needs movement from stock +- + !record {model: stock.move, id: outgoing_shipment_fifo_icecream_ret}: + picking_id: outgoing_fifo_shipment_ret + product_id: product_fifo_icecream + product_uom: product.product_uom_kgm + product_qty: 10.0 + type: out +- + I confirm outgoing shipment of 10 kg of FIFO Ice Cream. +- + !workflow {model: stock.picking, action: button_confirm, ref: outgoing_fifo_shipment_ret} +- + Process the delivery of the outgoing shipment +- + !python {model: stock.partial.picking}: | + partial_id = self.create(cr, uid, {}, context={'active_model': 'stock.picking','active_ids': [ref("outgoing_fifo_shipment_ret")], 'default_type':'out'}) + self.do_partial(cr, uid, [partial_id]) - Check rounded price is 150.0 / 1.2834 - diff --git a/addons/stock/report/report_stock_move.py b/addons/stock/report/report_stock_move.py index 127b523561d..c05cdc1c93d 100644 --- a/addons/stock/report/report_stock_move.py +++ b/addons/stock/report/report_stock_move.py @@ -232,6 +232,7 @@ class report_stock_valuation(osv.osv): _name = "report.stock.valuation" _description = "Stock Valuation Statistics" _auto = False + _order = 'date desc' _columns = { 'date': fields.datetime('Date', readonly=True), @@ -246,8 +247,8 @@ class report_stock_valuation(osv.osv): 'prodlot_id': fields.many2one('stock.production.lot', 'Lot', readonly=True), 'company_id': fields.many2one('res.company', 'Company', readonly=True), 'product_qty':fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), readonly=True), - 'value' : fields.float('Total Value', digits_compute=dp.get_precision('Account'), required=True), - 'move_value' : fields.float('Total Value', digits_compute=dp.get_precision('Account'), required=True), + 'fifo_value' : fields.float('FIFO Value', digits_compute=dp.get_precision('Account'), required=True), + 'avg_value' : fields.float('Average Value', digits_compute=dp.get_precision('Account'), required=True), 'inventory_value': fields.float('Inventory Value'), 'state': fields.selection([('draft', 'Draft'), ('waiting', 'Waiting'), ('confirmed', 'Confirmed'), ('assigned', 'Available'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Status', readonly=True, select=True, help='When the stock move is created it is in the \'Draft\' state.\n After that it is set to \'Confirmed\' state.\n If stock is available state is set to \'Avaiable\'.\n When the picking it done the state is \'Done\'.\ @@ -263,11 +264,10 @@ class report_stock_valuation(osv.osv): 'related': fields.related('match', 'picking_id', 'name', type='text', readonly=True), #'funct': fields.function(_get_properties, type='float') } - def _get_properties(self, cr, uid, ids, context=None): - products = {} - for stockval in self.browse(cr, uid, ids, context=context): - products[stockval.product_id] = True + + + def init(self, cr): tools.drop_view_if_exists(cr, 'report_stock_valuation') cr.execute(""" @@ -282,21 +282,9 @@ CREATE OR REPLACE view report_stock_valuation AS ( m.state as state, m.prodlot_id as prodlot_id, p.name as name, mm.move_in_id as match, - CASE WHEN ipcm.value_text in ('fifo','lifo') THEN coalesce(mm.price_unit_out * pu2.factor / pu.factor, 0.0) - ELSE coalesce(m.price_unit * pu2.factor / pu.factor::decimal, 0.0) END AS price_unit, - coalesce(sum(-ip.value_float * m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as value, - CASE WHEN ipcm.value_text IS NOT NULL THEN - CASE WHEN ipcm.value_text in ('fifo', 'lifo') THEN coalesce(sum(-mm.price_unit_out * mm.qty)::decimal, 0.0) - ELSE coalesce(sum(-m.price_unit * mm.qty)::decimal, 0.0) END - ELSE - CASE WHEN ipcmdef.value_text IS NOT NULL THEN - CASE WHEN ipcmdef.value_text in ('fifo', 'lifo') THEN coalesce(sum(-mm.price_unit_out * mm.qty)::decimal, 0.0) - ELSE coalesce(sum(-m.price_unit * mm.qty)::decimal, 0.0) END - ELSE - CASE WHEN ipcmdef2.value_text in ('fifo', 'lifo') THEN coalesce(sum(-mm.price_unit_out * mm.qty)::decimal, 0.0) - ELSE coalesce(sum(-m.price_unit * mm.qty)::decimal, 0.0) END - END - END as move_value, + coalesce(m.price_unit * pu2.factor / pu.factor, 0.0) as price_unit, + coalesce(sum(-mm.price_unit_out * mm.qty)::decimal, 0.0) as fifo_value, + coalesce(sum(-m.price_unit * mm.qty)::decimal, 0.0) as avg_value, coalesce(sum(-mm.qty * pu.factor / pu2.factor)::decimal, 0.0) as product_qty, l_other.usage as location_dest_type, l.usage as location_src_type, @@ -306,12 +294,7 @@ CREATE OR REPLACE view report_stock_valuation AS ( 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 ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.template,',pt.id) AND ip.company_id=m.company_id) - LEFT JOIN ir_property ipcm ON (ipcm.name='cost_method' and ipcm.res_id=CONCAT('product.template,',pt.id) AND ipcm.company_id=m.company_id) - LEFT JOIN ir_property ip_def ON (ip_def.name='standard_price' AND ip_def.res_id IS NULL AND ip_def.company_id=m.company_id) - LEFT JOIN ir_property ip_def2 ON (ip_def2.name='standard_price' AND ip_def2.res_id IS NULL AND ip_def2.company_id IS NULL) - LEFT JOIN ir_property ipcmdef ON (ipcmdef.name='cost_method' AND ipcmdef.res_id IS NULL AND ipcmdef.company_id=m.company_id) - LEFT JOIN ir_property ipcmdef2 ON (ipcmdef2.name='cost_method' AND ipcmdef2.res_id IS NULL AND ipcmdef2.company_id IS NULL) + 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) @@ -321,8 +304,7 @@ CREATE OR REPLACE view report_stock_valuation AS ( GROUP BY p.name, mm.id, mm.move_out_id, 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.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'), - pu2.factor, pu.factor, ipcm.value_text, m.qty_remaining, l_other.usage, - ipcmdef.value_text, ipcmdef2.value_text + pu2.factor, pu.factor, m.qty_remaining, l_other.usage ) UNION ALL ( SELECT -min(m.id) as id, m.date as date, @@ -334,13 +316,12 @@ CREATE OR REPLACE view report_stock_valuation AS ( m.state as state, m.prodlot_id as prodlot_id, p.name as name, 0 as match, coalesce(m.price_unit * pu2.factor / pu.factor, 0.0) as price_unit, - coalesce(sum(ip.value_float * m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as value, - coalesce(sum(m.price_unit * m.product_qty)::decimal, 0.0) as move_value, + coalesce(sum(m.price_unit * m.product_qty)::decimal, 0.0) as fifo_value, + coalesce(sum(m.price_unit * m.product_qty)::decimal, 0.0) as avg_value, coalesce(sum(m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as product_qty, l.usage as location_dest_type, l_other.usage as location_src_type, - CASE WHEN ipcm.value_text in ('fifo','lifo') THEN coalesce(sum(m.price_unit * m.qty_remaining)::decimal, 0.0) - ELSE coalesce(sum(ip.value_float * m.qty_remaining)::decimal, 0.0) END as inventory_value + coalesce(sum(m.price_unit * m.qty_remaining)::decimal, 0.0) as inventory_value FROM stock_move m LEFT JOIN stock_picking p ON (m.picking_id=p.id) @@ -350,16 +331,12 @@ CREATE OR REPLACE view report_stock_valuation AS ( 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), - ir_property ip, ir_property ipcm - WHERE m.state != 'cancel' and - ip.name='standard_price' AND (ip.res_id = CONCAT('product.template,',pt.id) or ip.res_id IS NULL) AND (ip.company_id=m.company_id OR ip.company_id IS NULL) and - ipcm.name='cost_method' AND (ipcm.res_id = CONCAT('product.template,',pt.id) or ipcm.res_id IS NULL) AND (ipcm.company_id=m.company_id OR ipcm.company_id IS NULL) + LEFT JOIN stock_location l_other ON (m.location_id=l_other.id) + WHERE m.state != 'cancel' GROUP BY p.name, 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.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'), - pu2.factor, pu.factor, m.qty_remaining, l_other.usage, ipcm.value_text, ip.value_float, ip.company_id, ipcm.company_id, ip.res_id, ipcm.res_id - order by ip.res_id ASC, ip.company_id ASC, ipcm.res_id ASC, ipcm.company_id + pu2.factor, pu.factor, m.qty_remaining, l_other.usage ) ); """) diff --git a/addons/stock/report/report_stock_move_view.xml b/addons/stock/report/report_stock_move_view.xml index 2b23eb4590f..545cfbcc170 100644 --- a/addons/stock/report/report_stock_move_view.xml +++ b/addons/stock/report/report_stock_move_view.xml @@ -208,7 +208,8 @@ - + + @@ -219,7 +220,7 @@ - + diff --git a/addons/stock/stock_fifo_lifo.py b/addons/stock/stock_fifo_lifo.py index cbaa1e15fef..421c81df337 100644 --- a/addons/stock/stock_fifo_lifo.py +++ b/addons/stock/stock_fifo_lifo.py @@ -29,6 +29,41 @@ class product_product (osv.osv): _inherit = "product.product" + #Need to change stock moves/product when changing cost method + def write(self, cr, uid, ids, vals, context=None): + if "cost_method" in vals: + move_obj = self.pool.get("stock.move") + uom_obj = self.pool.get("product.uom") + prod_obj = self.pool.get("product.product") + #TODO Need force_company in context? + if 'force_company' not in context: + company_id = self.pool.get("res.users").browse(cr, uid, uid, context=context).company_id.id + + else: + company_id = context['force_company'] + for prod in self.browse(cr, uid, ids, context=context): + if prod.cost_method == 'average': + mov_ids = move_obj.search(cr, uid, [('company_id', '=', company_id), ('state', '=', 'done'), ('qty_remaining', '>', 0.0)], context=context) + #TODO Need to convert to all prices to UoM of stock move + for move in move_obj.browse(cr, uid, mov_ids, context=context): + new_price = uom_obj._compute_price(cr, uid, move.product_uom.id, move.price_unit, prod.uom_id.id) + move.write({'price_unit': new_price}) + #We need to recalculate the average on all products from all stock moves in + if vals["cost_method"] == 'average': + #Search all done in moves + mov_ids = move_obj.search(cr, uid, [('company_id', '=', company_id), ('state', '=', 'done'), ('location_dest_id.usage', '=', 'internal'), + ('location_id.usage', '!=', 'internal')], context=context) + qty = 0.0 + total_price = 0.0 + for move in move_obj.browse(cr, uid, mov_ids, context=context): + total_price += move.product_qty * move.price_unit + qty += uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, prod.uom_id.id) + print "Qty and Total Price:", qty, total_price + if qty > 0.0: + prod_obj.write(cr, uid, [prod.id], {'standard_price': total_price / qty}, context=context) + res = super(product_product, self).write(cr, uid, ids, vals, context=context) + return res + def get_stock_matchings_fifolifo(self, cr, uid, ids, qty, fifo, product_uom_id = False, currency_id = False, context=None): ''' This method returns a list of tuples with quantities from stock in moves @@ -136,9 +171,6 @@ class stock_move(osv.osv): qty = move.product_qty for match in match_obj.browse(cr, uid, matches, context=context): qty -= match.qty -# if qty < 0: -# import pdb -# pdb.set_trace() res[move.id] = qty return res _inherit = 'stock.move'