stock_landed_costs/tests/test_stock_landed_costs.py

212 lines
10 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.stock_landed_costs.tests.common import TestStockLandedCostsCommon
from odoo.exceptions import ValidationError
from odoo.tests import tagged
from odoo import fields
@tagged('post_install', '-at_install')
class TestStockLandedCosts(TestStockLandedCostsCommon):
def test_stock_landed_costs(self):
# In order to test the landed costs feature of stock,
# I create a landed cost, confirm it and check its account move created
# I create 2 products with different volume and gross weight and configure
# them for real_time valuation and fifo costing method
product_landed_cost_1 = self.env['product.product'].create({
'name': "LC product 1",
'weight': 10,
'volume': 1,
'categ_id': self.stock_account_product_categ.id,
'type': 'product',
})
product_landed_cost_2 = self.env['product.product'].create({
'name': "LC product 2",
'weight': 20,
'volume': 1.5,
'categ_id': self.stock_account_product_categ.id,
'type': 'product',
})
self.assertEqual(product_landed_cost_1.value_svl, 0)
self.assertEqual(product_landed_cost_1.quantity_svl, 0)
self.assertEqual(product_landed_cost_2.value_svl, 0)
self.assertEqual(product_landed_cost_2.quantity_svl, 0)
picking_default_vals = self.env['stock.picking'].default_get(list(self.env['stock.picking'].fields_get()))
# I create 2 picking moving those products
vals = dict(picking_default_vals, **{
'name': 'LC_pick_1',
'picking_type_id': self.warehouse.out_type_id.id,
'move_ids': [(0, 0, {
'product_id': product_landed_cost_1.id,
'product_uom_qty': 5,
'product_uom': self.ref('uom.product_uom_unit'),
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
})],
})
picking_landed_cost_1 = self.env['stock.picking'].new(vals)
picking_landed_cost_1._onchange_picking_type()
picking_landed_cost_1.move_ids._onchange_product_id()
picking_landed_cost_1.move_ids.name = 'move 1'
vals = picking_landed_cost_1._convert_to_write(picking_landed_cost_1._cache)
picking_landed_cost_1 = self.env['stock.picking'].create(vals)
# Confirm and assign picking
self.env.company.anglo_saxon_accounting = True
picking_landed_cost_1.action_confirm()
picking_landed_cost_1.action_assign()
picking_landed_cost_1.move_ids.quantity = 5
picking_landed_cost_1.button_validate()
vals = dict(picking_default_vals, **{
'name': 'LC_pick_2',
'picking_type_id': self.warehouse.out_type_id.id,
'move_ids': [(0, 0, {
'product_id': product_landed_cost_2.id,
'product_uom_qty': 10,
'product_uom': self.ref('uom.product_uom_unit'),
'location_id': self.warehouse.lot_stock_id.id,
'location_dest_id': self.ref('stock.stock_location_customers'),
})],
})
picking_landed_cost_2 = self.env['stock.picking'].new(vals)
picking_landed_cost_2._onchange_picking_type()
picking_landed_cost_2.move_ids._onchange_product_id()
picking_landed_cost_2.move_ids.name = 'move 2'
vals = picking_landed_cost_2._convert_to_write(picking_landed_cost_2._cache)
picking_landed_cost_2 = self.env['stock.picking'].create(vals)
# Confirm and assign picking
picking_landed_cost_2.action_confirm()
picking_landed_cost_2.action_assign()
picking_landed_cost_2.move_ids.quantity = 10
picking_landed_cost_2.button_validate()
self.assertEqual(product_landed_cost_1.value_svl, 0)
self.assertEqual(product_landed_cost_1.quantity_svl, -5)
self.assertEqual(product_landed_cost_2.value_svl, 0)
self.assertEqual(product_landed_cost_2.quantity_svl, -10)
# I create a landed cost for those 2 pickings
default_vals = self.env['stock.landed.cost'].default_get(list(self.env['stock.landed.cost'].fields_get()))
virtual_home_staging = self.env['product.product'].create({
'name': 'Virtual Home Staging',
'categ_id': self.stock_account_product_categ.id,
})
default_vals.update({
'picking_ids': [picking_landed_cost_1.id, picking_landed_cost_2.id],
'account_journal_id': self.expenses_journal,
'cost_lines': [
(0, 0, {'product_id': virtual_home_staging.id}),
(0, 0, {'product_id': virtual_home_staging.id}),
(0, 0, {'product_id': virtual_home_staging.id}),
(0, 0, {'product_id': virtual_home_staging.id})],
'valuation_adjustment_lines': [],
})
cost_lines_values = {
'name': ['equal split', 'split by quantity', 'split by weight', 'split by volume'],
'split_method': ['equal', 'by_quantity', 'by_weight', 'by_volume'],
'price_unit': [10, 150, 250, 20],
}
stock_landed_cost_1 = self.env['stock.landed.cost'].new(default_vals)
for index, cost_line in enumerate(stock_landed_cost_1.cost_lines):
cost_line.onchange_product_id()
cost_line.name = cost_lines_values['name'][index]
cost_line.split_method = cost_lines_values['split_method'][index]
cost_line.price_unit = cost_lines_values['price_unit'][index]
vals = stock_landed_cost_1._convert_to_write(stock_landed_cost_1._cache)
stock_landed_cost_1 = self.env['stock.landed.cost'].create(vals)
# I compute the landed cost using Compute button
stock_landed_cost_1.compute_landed_cost()
# I check the valuation adjustment lines
for valuation in stock_landed_cost_1.valuation_adjustment_lines:
if valuation.cost_line_id.name == 'equal split':
self.assertEqual(valuation.additional_landed_cost, 5)
elif valuation.cost_line_id.name == 'split by quantity' and valuation.move_id.name == "move 1":
self.assertEqual(valuation.additional_landed_cost, 50)
elif valuation.cost_line_id.name == 'split by quantity' and valuation.move_id.name == "move 2":
self.assertEqual(valuation.additional_landed_cost, 100)
elif valuation.cost_line_id.name == 'split by weight' and valuation.move_id.name == "move 1":
self.assertEqual(valuation.additional_landed_cost, 50)
elif valuation.cost_line_id.name == 'split by weight' and valuation.move_id.name == "move 2":
self.assertEqual(valuation.additional_landed_cost, 200)
elif valuation.cost_line_id.name == 'split by volume' and valuation.move_id.name == "move 1":
self.assertEqual(valuation.additional_landed_cost, 5)
elif valuation.cost_line_id.name == 'split by volume' and valuation.move_id.name == "move 2":
self.assertEqual(valuation.additional_landed_cost, 15)
else:
raise ValidationError('unrecognized valuation adjustment line')
# I confirm the landed cost
stock_landed_cost_1.button_validate()
# I check that the landed cost is now "Closed" and that it has an accounting entry
self.assertEqual(stock_landed_cost_1.state, "done")
self.assertTrue(stock_landed_cost_1.account_move_id)
self.assertEqual(len(stock_landed_cost_1.account_move_id.line_ids), 48)
lc_value = sum(stock_landed_cost_1.account_move_id.line_ids.filtered(lambda aml: aml.account_id.name.startswith('Expenses')).mapped('debit'))
product_value = abs(product_landed_cost_1.value_svl) + abs(product_landed_cost_2.value_svl)
self.assertEqual(lc_value, product_value)
self.assertEqual(len(picking_landed_cost_1.move_ids.stock_valuation_layer_ids), 5)
self.assertEqual(len(picking_landed_cost_2.move_ids.stock_valuation_layer_ids), 5)
def test_aml_account_selection(self):
"""
Process a PO with a landed cost, then create and post the bill. The
account of the landed cost AML should be:
- Expense if the categ valuation is manual
- Stock IN if the categ valuation is real time
"""
self.landed_cost.landed_cost_ok = True
for valuation in ['manual_periodic', 'real_time']:
self.landed_cost.categ_id.property_valuation = valuation
account_name = 'stock_input' if valuation == 'real_time' else 'expense'
account = self.landed_cost.product_tmpl_id.get_product_accounts()[account_name]
po = self.env['purchase.order'].create({
'partner_id': self.partner_a.id,
'currency_id': self.company_data['currency'].id,
'order_line': [
(0, 0, {
'name': self.product_a.name,
'product_id': self.product_a.id,
'product_qty': 1.0,
'product_uom': self.product_a.uom_po_id.id,
'price_unit': 100.0,
'taxes_id': False,
}),
(0, 0, {
'name': self.landed_cost.name,
'product_id': self.landed_cost.id,
'product_qty': 1.0,
'price_unit': 100.0,
}),
],
})
po.button_confirm()
receipt = po.picking_ids
receipt.move_ids.quantity = 1
receipt.button_validate()
po.order_line[1].qty_received = 1
po.action_create_invoice()
bill = po.invoice_ids
bill.invoice_date = fields.Date.today()
bill._post()
landed_cost_aml = bill.invoice_line_ids.filtered(lambda l: l.product_id == self.landed_cost)
self.assertEqual(bill.state, 'posted', 'Incorrect value with valuation %s' % valuation)
self.assertEqual(landed_cost_aml.account_id, account, 'Incorrect value with valuation %s' % valuation)