flectra/addons/purchase/tests/test_stockvaluation.py

274 lines
11 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import time
from datetime import datetime
2018-01-16 11:34:37 +01:00
from flectra.tests.common import TransactionCase
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
class TestStockValuation(TransactionCase):
def setUp(self):
super(TestStockValuation, self).setUp()
self.supplier_location = self.env.ref('stock.stock_location_suppliers')
self.stock_location = self.env.ref('stock.stock_location_stock')
self.partner_id = self.env.ref('base.res_partner_1')
self.product1 = self.env.ref('product.product_product_8')
Account = self.env['account.account']
self.stock_input_account = Account.create({
'name': 'Stock Input',
'code': 'StockIn',
'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
})
self.stock_output_account = Account.create({
'name': 'Stock Output',
'code': 'StockOut',
'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
})
self.stock_valuation_account = Account.create({
'name': 'Stock Valuation',
'code': 'Stock Valuation',
'user_type_id': self.env.ref('account.data_account_type_current_assets').id,
})
self.stock_journal = self.env['account.journal'].create({
'name': 'Stock Journal',
'code': 'STJTEST',
'type': 'general',
})
self.product1.categ_id.write({
'property_stock_account_input_categ_id': self.stock_input_account.id,
'property_stock_account_output_categ_id': self.stock_output_account.id,
'property_stock_valuation_account_id': self.stock_valuation_account.id,
'property_stock_journal': self.stock_journal.id,
})
def test_change_unit_cost_average_1(self):
""" Confirm a purchase order and create the associated receipt, change the unit cost of the
purchase order before validating the receipt, the value of the received goods should be set
according to the last unit cost.
"""
self.product1.product_tmpl_id.cost_method = 'average'
po1 = self.env['purchase.order'].create({
'partner_id': self.partner_id.id,
'order_line': [
(0, 0, {
'name': self.product1.name,
'product_id': self.product1.id,
'product_qty': 10.0,
'product_uom': self.product1.uom_po_id.id,
'price_unit': 100.0,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}),
],
})
po1.button_confirm()
picking1 = po1.picking_ids[0]
move1 = picking1.move_lines[0]
# the unit price of the purchase order line is copied to the in move
self.assertEquals(move1.price_unit, 100)
# update the unit price on the purchase order line
po1.order_line.price_unit = 200
# the unit price on the stock move is not directly updated
self.assertEquals(move1.price_unit, 100)
# validate the receipt
res_dict = picking1.button_validate()
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id'))
wizard.process()
# the unit price of the stock move has been updated to the latest value
self.assertEquals(move1.price_unit, 200)
self.assertEquals(self.product1.stock_value, 2000)
def test_standard_price_change_1(self):
""" Confirm a purchase order and create the associated receipt, change the unit cost of the
purchase order and the standard price of the product before validating the receipt, the
value of the received goods should be set according to the last standard price.
"""
self.product1.product_tmpl_id.cost_method = 'standard'
# set a standard price
self.product1.product_tmpl_id.standard_price = 10
po1 = self.env['purchase.order'].create({
'partner_id': self.partner_id.id,
'order_line': [
(0, 0, {
'name': self.product1.name,
'product_id': self.product1.id,
'product_qty': 10.0,
'product_uom': self.product1.uom_po_id.id,
'price_unit': 11.0,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}),
],
})
po1.button_confirm()
picking1 = po1.picking_ids[0]
move1 = picking1.move_lines[0]
# the move's unit price reflects the purchase order line's cost even if it's useless when
# the product's cost method is standard
self.assertEquals(move1.price_unit, 11)
# set a new standard price
self.product1.product_tmpl_id.standard_price = 12
# the unit price on the stock move is not directly updated
self.assertEquals(move1.price_unit, 11)
# validate the receipt
res_dict = picking1.button_validate()
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id'))
wizard.process()
# the unit price of the stock move has been updated to the latest value
self.assertEquals(move1.price_unit, 12)
self.assertEquals(self.product1.stock_value, 120)
def test_change_currency_rate_average_1(self):
""" Confirm a purchase order in another currency and create the associated receipt, change
the currency rate, validate the receipt and then check that the value of the received goods
is set according to the last currency rate.
"""
usd_currency = self.env.ref('base.USD')
self.env.user.company_id.currency_id = usd_currency.id
eur_currency = self.env.ref('base.EUR')
self.product1.product_tmpl_id.cost_method = 'average'
# default currency is USD, create a purchase order in EUR
po1 = self.env['purchase.order'].create({
'partner_id': self.partner_id.id,
'currency_id': eur_currency.id,
'order_line': [
(0, 0, {
'name': self.product1.name,
'product_id': self.product1.id,
'product_qty': 10.0,
'product_uom': self.product1.uom_po_id.id,
'price_unit': 100.0,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}),
],
})
po1.button_confirm()
picking1 = po1.picking_ids[0]
move1 = picking1.move_lines[0]
# convert the price unit in the company currency
price_unit_usd = po1.currency_id.compute(po1.order_line.price_unit, po1.company_id.currency_id, round=True)
# the unit price of the move is the unit price of the purchase order line converted in
# the company's currency
self.assertAlmostEqual(move1.price_unit, price_unit_usd)
# change the rate of the currency
self.env['res.currency.rate'].create({
'name': time.strftime('%Y-%m-%d'),
'rate': 2.0,
'currency_id': eur_currency.id,
'company_id': po1.company_id.id,
})
eur_currency._compute_current_rate()
price_unit_usd_new_rate = po1.currency_id.compute(po1.order_line.price_unit, po1.company_id.currency_id, round=True)
# the new price_unit is lower than th initial because of the rate's change
self.assertLess(price_unit_usd_new_rate, price_unit_usd)
# the unit price on the stock move is not directly updated
self.assertAlmostEqual(move1.price_unit, price_unit_usd)
# validate the receipt
res_dict = picking1.button_validate()
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id'))
wizard.process()
# the unit price of the stock move has been updated to the latest value
2018-06-20 09:39:59 +02:00
self.assertEquals(round(move1.price_unit), round(price_unit_usd_new_rate))
self.assertAlmostEqual(self.product1.stock_value, price_unit_usd_new_rate * 10, delta=0.1)
def test_extra_move_fifo_1(self):
""" Check that the extra move when over processing a receipt is correctly merged back in
the original move.
"""
self.product1.product_tmpl_id.cost_method = 'fifo'
po1 = self.env['purchase.order'].create({
'partner_id': self.partner_id.id,
'order_line': [
(0, 0, {
'name': self.product1.name,
'product_id': self.product1.id,
'product_qty': 10.0,
'product_uom': self.product1.uom_po_id.id,
'price_unit': 100.0,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}),
],
})
po1.button_confirm()
picking1 = po1.picking_ids[0]
move1 = picking1.move_lines[0]
move1.quantity_done = 15
res_dict = picking1.button_validate()
self.assertEqual(res_dict['res_model'], 'stock.overprocessed.transfer')
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id'))
wizard.action_confirm()
# there should be only one move
self.assertEqual(len(picking1.move_lines), 1)
self.assertEqual(move1.price_unit, 100)
self.assertEqual(move1.product_qty, 15)
self.assertEqual(self.product1.stock_value, 1500)
def test_backorder_fifo_1(self):
""" Check that the backordered move when under processing a receipt correctly keep the
price unit of the original move.
"""
self.product1.product_tmpl_id.cost_method = 'fifo'
po1 = self.env['purchase.order'].create({
'partner_id': self.partner_id.id,
'order_line': [
(0, 0, {
'name': self.product1.name,
'product_id': self.product1.id,
'product_qty': 10.0,
'product_uom': self.product1.uom_po_id.id,
'price_unit': 100.0,
'date_planned': datetime.today().strftime(DEFAULT_SERVER_DATETIME_FORMAT),
}),
],
})
po1.button_confirm()
picking1 = po1.picking_ids[0]
move1 = picking1.move_lines[0]
move1.quantity_done = 5
res_dict = picking1.button_validate()
self.assertEqual(res_dict['res_model'], 'stock.backorder.confirmation')
wizard = self.env[(res_dict.get('res_model'))].browse(res_dict.get('res_id'))
wizard.process()
self.assertEqual(len(picking1.move_lines), 1)
self.assertEqual(move1.price_unit, 100)
self.assertEqual(move1.product_qty, 5)
picking2 = po1.picking_ids.filtered(lambda p: p.backorder_id)
move2 = picking2.move_lines[0]
self.assertEqual(len(picking2.move_lines), 1)
self.assertEqual(move2.price_unit, 100)
self.assertEqual(move2.product_qty, 5)