19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:29:53 +01:00
parent 6e54c1af6c
commit 3ca647e428
1087 changed files with 132065 additions and 108499 deletions

View file

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_frontend
from . import test_pos_mrp_flow

View file

@ -0,0 +1,123 @@
from odoo.addons.point_of_sale.tests.common import CommonPosTest
from odoo.fields import Command
class CommonPosMrpTest(CommonPosTest):
@classmethod
def setUpClass(self):
super().setUpClass()
self.mrp_create_product_category(self)
self.mrp_edit_product_template(self)
self.mrp_create_bom(self)
def mrp_edit_product_template(self):
self.product_product_kit_one = self.ten_dollars_no_tax.product_variant_id
self.product_product_kit_two = self.twenty_dollars_no_tax.product_variant_id
self.product_product_kit_three = self.product_product_kit_two.copy()
self.product_product_kit_four = self.product_product_kit_two.copy()
self.product_product_comp_one = self.ten_dollars_with_10_incl.product_variant_id
self.product_product_comp_two = self.ten_dollars_with_15_incl.product_variant_id
self.product_product_comp_three = self.twenty_dollars_with_10_incl.product_variant_id
self.product_product_comp_four = self.twenty_dollars_with_15_incl.product_variant_id
self.product_product_kit_one.write({
'is_storable': True,
'categ_id': self.category_fifo.id,
})
self.product_product_kit_two.write({
'is_storable': True,
'categ_id': self.category_fifo.id,
})
self.product_product_kit_three.write({
'is_storable': True,
'categ_id': self.category_fifo.id,
})
self.product_product_kit_four.write({
'is_storable': True,
'categ_id': self.category_fifo.id,
})
self.product_product_comp_one.product_tmpl_id.write({
'standard_price': 10,
})
self.product_product_comp_two.product_tmpl_id.write({
'standard_price': 10,
})
self.product_product_comp_three.product_tmpl_id.write({
'standard_price': 10,
})
self.product_product_comp_four.product_tmpl_id.write({
'standard_price': 10,
})
def mrp_create_product_category(self):
self.category_average = self.env['product.category'].create({
'name': 'Category for average cost',
'property_cost_method': 'average',
})
self.category_fifo = self.env['product.category'].create({
'name': 'Category for kit',
'property_cost_method': 'fifo',
})
self.category_fifo_realtime = self.env['product.category'].create({
'name': 'Category for kit',
'property_cost_method': 'fifo',
'property_valuation': 'real_time',
})
def mrp_create_bom(self):
self.bom_one_line = self.env['mrp.bom'].create({
'product_tmpl_id': self.product_product_kit_one.product_tmpl_id.id,
'product_qty': 1,
'type': 'phantom',
'bom_line_ids': [
Command.create({
'product_id': self.product_product_comp_one.id,
'product_qty': 1
}),
],
})
self.bom_two_lines = self.env['mrp.bom'].create({
'product_tmpl_id': self.product_product_kit_two.product_tmpl_id.id,
'product_qty': 1,
'type': 'phantom',
'bom_line_ids': [
Command.create({
'product_id': self.product_product_comp_one.id,
'product_qty': 1
}),
Command.create({
'product_id': self.product_product_comp_two.id,
'product_qty': 1
}),
],
})
self.bom_two_lines_of_kits = self.env['mrp.bom'].create({
'product_tmpl_id': self.product_product_kit_three.product_tmpl_id.id,
'product_qty': 1,
'type': 'phantom',
'bom_line_ids': [
Command.create({
'product_id': self.product_product_kit_one.id,
'product_qty': 1
}),
Command.create({
'product_id': self.product_product_kit_two.id,
'product_qty': 1
}),
],
})
self.bom_two_lines_of_kits_with_qty = self.env['mrp.bom'].create({
'product_tmpl_id': self.product_product_kit_four.product_tmpl_id.id,
'product_qty': 1,
'type': 'phantom',
'bom_line_ids': [
Command.create({
'product_id': self.product_product_kit_one.id,
'product_qty': 2
}),
Command.create({
'product_id': self.product_product_kit_two.id,
'product_qty': 3
}),
],
})

View file

@ -0,0 +1,82 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.point_of_sale.tests.test_frontend import TestPointOfSaleHttpCommon
from odoo.tests import tagged
from odoo import Command
@tagged('post_install', '-at_install')
class TestUi(TestPointOfSaleHttpCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Ensure minimum rights (avoid new groups added through modules installation)
group_internal_user = cls.env.ref('base.group_user')
group_pos_user = cls.env.ref('point_of_sale.group_pos_user')
cls.pos_user.group_ids = [Command.set([group_internal_user.id, group_pos_user.id])]
cls.basic_kit, cls.finished, cls.component_a, cls.component_b = cls.env['product.product'].create([{
'name': name,
'type': 'consu',
'is_storable': True,
'available_in_pos': True,
'list_price': 10.0,
'standard_price': 1.0,
'taxes_id': False,
} for name in ['Basic Kit', 'Finished', 'Component A', 'Component B']])
cls.simple_kit_bom, cls.finished_bom = cls.env['mrp.bom'].create([{
'product_tmpl_id': product.product_tmpl_id.id,
'product_qty': 1.0,
'type': bom_type,
'bom_line_ids': [
Command.create({
'product_id': cls.component_a.id,
'product_qty': 1,
}),
Command.create({
'product_id': cls.component_b.id,
'product_qty': 1,
}),
],
} for product, bom_type in [
(cls.basic_kit, 'phantom'),
(cls.finished, 'normal'),
]])
def test_ship_later_kit_and_mto_manufactured_product(self):
"""
Ship Later PoS. Sell a kit and a manufactured product. Before selling
them, the PoS user reads their product information. The second one has
both MTO and manufacture routes. Once sold, the delivery should contain
the manufactured product and the kit's components. Thanks to the routes,
there should also be a MO for the manufactured product.
"""
self.main_pos_config.write({
'ship_later': True,
})
mto_route = self.env.ref('stock.route_warehouse0_mto')
manu_route = self.env.ref('mrp.route_warehouse0_manufacture')
manu_route.product_selectable = True
mto_route.active = True
self.finished.route_ids = [Command.set((mto_route | manu_route).ids)]
customer = self.env['res.partner'].search([('email', '=', 'partner.full@example.com')], limit=1)
customer.name = "AAAA Super Customer"
self.main_pos_config.with_user(self.pos_user).open_ui()
url = "/pos/ui/%d" % self.main_pos_config.id
self.start_tour(url, 'test_ship_later_kit_and_mto_manufactured_product', login="pos_user")
picking = self.env['stock.picking'].search([('partner_id', '=', self.partner_full.id)], limit=1)
self.assertRecordValues(picking.move_ids, [
{'product_id': self.finished.id, 'product_qty': 1.0},
{'product_id': self.component_a.id, 'product_qty': 1.0},
{'product_id': self.component_b.id, 'product_qty': 1.0},
])
finished_sm = picking.move_ids[0]
self.assertEqual(finished_sm.move_orig_ids.production_id.product_id, self.finished)

View file

@ -1,447 +1,415 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from unittest import skip
import odoo
from odoo.addons.point_of_sale.tests.common import TestPointOfSaleCommon
from odoo import fields
from odoo.tests.common import Form
from odoo.addons.pos_mrp.tests.common import CommonPosMrpTest
from odoo import Command, fields
@odoo.tests.tagged('post_install', '-at_install')
class TestPosMrp(TestPointOfSaleCommon):
class TestPosMrp(CommonPosMrpTest):
def test_bom_kit_order_total_cost(self):
#create a product category that use fifo
category = self.env['product.category'].create({
'name': 'Category for kit',
'property_cost_method': 'fifo',
order, _ = self.create_backend_pos_order({
'line_data': [
{'product_id': self.product_product_kit_one.id}
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
self.kit = self.env['product.product'].create({
'name': 'Kit Product',
'available_in_pos': True,
'type': 'product',
'lst_price': 10.0,
'categ_id': category.id,
})
self.component_a = self.env['product.product'].create({
'name': 'Comp A',
'type': 'product',
'available_in_pos': True,
'lst_price': 10.0,
'standard_price': 5.0,
})
self.component_b = self.env['product.product'].create({
'name': 'Comp B',
'type': 'product',
'available_in_pos': True,
'lst_price': 10.0,
'standard_price': 10.0,
})
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.kit
bom_product_form.product_tmpl_id = self.kit.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_a
bom_line.product_qty = 1.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_b
bom_line.product_qty = 1.0
self.bom_a = bom_product_form.save()
self.pos_config.open_ui()
order = self.env['pos.order'].create({
'session_id': self.pos_config.current_session_id.id,
'lines': [(0, 0, {
'name': self.kit.name,
'product_id': self.kit.id,
'price_unit': self.kit.lst_price,
'qty': 1,
'tax_ids': [[6, False, []]],
'price_subtotal': self.kit.lst_price,
'price_subtotal_incl': self.kit.lst_price,
})],
'pricelist_id': self.pos_config.pricelist_id.id,
'amount_paid': self.kit.lst_price,
'amount_total': self.kit.lst_price,
'amount_tax': 0.0,
'amount_return': 0.0,
'to_invoice': False,
})
payment_context = {"active_ids": order.ids, "active_id": order.id}
order_payment = self.PosMakePayment.with_context(**payment_context).create({
'amount': order.amount_total,
'payment_method_id': self.cash_payment_method.id
})
order_payment.with_context(**payment_context).check()
self.pos_config.current_session_id.action_pos_session_closing_control()
pos_order = self.env['pos.order'].search([], order='id desc', limit=1)
self.assertEqual(pos_order.lines[0].total_cost, 15.0)
self.pos_config_usd.current_session_id.action_pos_session_closing_control()
self.assertEqual(order.lines[0].total_cost, 10.0)
@skip('Temporary to fast merge new valuation')
def test_bom_kit_with_kit_invoice_valuation(self):
# create a product category that use fifo
category = self.env['product.category'].create({
'name': 'Category for kit',
'property_cost_method': 'fifo',
'property_valuation': 'real_time',
self.product_product_kit_one.categ_id = self.category_fifo_realtime
self.product_product_kit_two.categ_id = self.category_fifo_realtime
self.product_product_kit_three.categ_id = self.category_fifo_realtime
self.product_product_kit_four.categ_id = self.category_fifo_realtime
order, _ = self.create_backend_pos_order({
'order_data': {
'to_invoice': True,
'partner_id': self.partner_moda.id,
},
'line_data': [
{'product_id': self.product_product_kit_three.id},
{'product_id': self.product_product_kit_four.id}
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
self.kit = self.env['product.product'].create({
'name': 'Final Kit',
'available_in_pos': True,
'categ_id': category.id,
'taxes_id': False,
'type': 'product',
})
self.kit_2 = self.env['product.product'].create({
'name': 'Final Kit 2',
'available_in_pos': True,
'categ_id': category.id,
'taxes_id': False,
'type': 'product',
})
self.subkit1 = self.env['product.product'].create({
'name': 'Subkit 1',
'available_in_pos': True,
'categ_id': category.id,
'taxes_id': False,
})
self.subkit2 = self.env['product.product'].create({
'name': 'Subkit 2',
'available_in_pos': True,
'categ_id': category.id,
'taxes_id': False,
})
self.component_a = self.env['product.product'].create({
'name': 'Comp A',
'available_in_pos': True,
'standard_price': 5.0,
'categ_id': category.id,
'taxes_id': False,
})
self.component_b = self.env['product.product'].create({
'name': 'Comp B',
'available_in_pos': True,
'standard_price': 5.0,
'categ_id': category.id,
'taxes_id': False,
})
self.component_c = self.env['product.product'].create({
'name': 'Comp C',
'available_in_pos': True,
'standard_price': 5.0,
'categ_id': category.id,
'taxes_id': False,
})
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.subkit1
bom_product_form.product_tmpl_id = self.subkit1.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_a
bom_line.product_qty = 1.0
self.bom_a = bom_product_form.save()
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.subkit2
bom_product_form.product_tmpl_id = self.subkit2.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_b
bom_line.product_qty = 1.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_c
bom_line.product_qty = 1.0
self.bom_b = bom_product_form.save()
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.kit
bom_product_form.product_tmpl_id = self.kit.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.subkit1
bom_line.product_qty = 1.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.subkit2
bom_line.product_qty = 1.0
self.final_bom = bom_product_form.save()
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.kit_2
bom_product_form.product_tmpl_id = self.kit_2.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.subkit1
bom_line.product_qty = 2.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.subkit2
bom_line.product_qty = 3.0
self.final_bom = bom_product_form.save()
self.pos_config.open_ui()
order_data = {'data':
{'to_invoice': True,
'amount_paid': 2.0,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 2.0,
'creation_date': fields.Datetime.to_string(fields.Datetime.now()),
'fiscal_position_id': False,
'pricelist_id': self.pos_config.available_pricelist_ids[0].id,
'lines': [[0,
0,
{'discount': 0,
'pack_lot_ids': [],
'price_unit': 2,
'product_id': self.kit.id,
'price_subtotal': 2,
'price_subtotal_incl': 2,
'qty': 1,
'tax_ids': [(6, 0, self.kit.taxes_id.ids)]}],
[0,
0,
{'discount': 0,
'pack_lot_ids': [],
'price_unit': 2,
'product_id': self.kit_2.id,
'price_subtotal': 2,
'price_subtotal_incl': 2,
'qty': 1,
'tax_ids': [(6, 0, self.kit_2.taxes_id.ids)]}]],
'name': 'Order 00042-003-0014',
'partner_id': self.partner1.id,
'pos_session_id': self.pos_config.current_session_id.id,
'sequence_number': 2,
'statement_ids': [[0,
0,
{'amount': 2.0,
'name': fields.Datetime.now(),
'payment_method_id': self.cash_payment_method.id}]],
'uid': '00042-003-0014',
'user_id': self.env.uid},
}
order = self.env['pos.order'].create_from_ui([order_data])
order = self.env['pos.order'].browse(order[0]['id'])
self.assertEqual(order.lines.filtered(lambda l: l.product_id == self.kit).total_cost, 15.0)
accounts = self.kit.product_tmpl_id.get_product_accounts()
self.assertEqual(order.lines.filtered(
lambda l: l.product_id == self.product_product_kit_three).total_cost, 30.0)
accounts = self.product_product_kit_three.product_tmpl_id.get_product_accounts()
debit_interim_account = accounts['stock_output']
credit_expense_account = accounts['expense']
invoice_accounts = order.account_move.line_ids.mapped('account_id.id')
self.assertTrue(debit_interim_account.id in invoice_accounts)
self.assertTrue(credit_expense_account.id in invoice_accounts)
expense_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == credit_expense_account.id)
self.assertEqual(expense_line.filtered(lambda l: l.product_id == self.kit).credit, 0.0)
self.assertEqual(expense_line.filtered(lambda l: l.product_id == self.kit).debit, 15.0)
self.assertEqual(expense_line.filtered(
lambda l: l.product_id == self.product_product_kit_three).credit, 0.0)
self.assertEqual(expense_line.filtered(
lambda l: l.product_id == self.product_product_kit_three).debit, 30.0)
interim_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == debit_interim_account.id)
self.assertEqual(interim_line.filtered(lambda l: l.product_id == self.kit).credit, 15.0)
self.assertEqual(interim_line.filtered(lambda l: l.product_id == self.kit).debit, 0.0)
self.pos_config.current_session_id.action_pos_session_closing_control()
self.assertEqual(interim_line.filtered(
lambda l: l.product_id == self.product_product_kit_three).credit, 30.0)
self.assertEqual(interim_line.filtered(
lambda l: l.product_id == self.product_product_kit_three).debit, 0.0)
self.pos_config_usd.current_session_id.action_pos_session_closing_control()
@skip('Temporary to fast merge new valuation')
def test_bom_kit_different_uom_invoice_valuation(self):
"""This test make sure that when a kit is made of product using UoM A but the bom line uses UoM B
the price unit is correctly computed on the invoice lines.
"""
self.env.user.groups_id += self.env.ref('uom.group_uom')
self.env.user.group_ids += self.env.ref('uom.group_uom')
# Edit kit product and component product
self.product_product_kit_one.categ_id = self.category_fifo_realtime
self.product_product_comp_one.standard_price = 12000
self.product_product_comp_one.uom_id = self.env.ref('uom.product_uom_dozen').id
# Edit kit product quantity
self.bom_one_line.bom_line_ids[0].product_qty = 6.0
self.bom_one_line.bom_line_ids[0].product_uom_id = self.env.ref('uom.product_uom_unit').id
self.bom_one_line.product_qty = 2.0
order, _ = self.create_backend_pos_order({
'order_data': {
'to_invoice': True,
'partner_id': self.partner_moda.id,
},
'line_data': [
{'product_id': self.product_product_kit_one.id, 'qty': 2},
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
accounts = self.product_product_kit_one.product_tmpl_id.get_product_accounts()
expense_line = order.account_move.line_ids.filtered(
lambda l: l.account_id.id == accounts['expense'].id)
interim_line = order.account_move.line_ids.filtered(
lambda l: l.account_id.id == accounts['stock_output'].id)
expense_line = expense_line.filtered(lambda l: l.product_id == self.product_product_kit_one)
interim_line = interim_line.filtered(lambda l: l.product_id == self.product_product_kit_one)
self.assertEqual(expense_line.debit, 6000.0)
self.assertEqual(interim_line.credit, 6000.0)
def test_bom_kit_order_total_cost_with_shared_component(self):
self.bom_one_line.product_tmpl_id.categ_id = self.category_average
self.bom_two_lines.product_tmpl_id.categ_id = self.category_average
kit_1 = self.bom_one_line.product_tmpl_id.product_variant_id
kit_2 = self.bom_two_lines.product_tmpl_id.product_variant_id
order, _ = self.create_backend_pos_order({
'line_data': [
{'product_id': kit_1.id},
{'product_id': kit_2.id}
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
self.pos_config_usd.current_session_id.action_pos_session_closing_control()
self.assertRecordValues(order.lines, [
{'product_id': kit_1.id, 'total_cost': 10.0},
{'product_id': kit_2.id, 'total_cost': 20.0},
])
def test_bom_nested_kit_order_total_cost_with_shared_component(self):
self.bom_one_line.product_tmpl_id.categ_id = self.category_average
self.bom_two_lines.product_tmpl_id.categ_id = self.category_average
self.ten_dollars_with_5_incl.standard_price = 30.0
self.twenty_dollars_with_5_incl.standard_price = 50.0
kit_1 = self.bom_one_line.copy()
kit_2 = self.bom_one_line.copy()
kit_2.product_tmpl_id = self.ten_dollars_with_5_incl
kit_3 = self.bom_one_line.copy()
kit_3.product_tmpl_id = self.twenty_dollars_with_5_incl
kit_3.bom_line_ids[0].product_id = kit_1.product_tmpl_id.product_variant_id
order, _ = self.create_backend_pos_order({
'line_data': [
{'product_id': kit_3.product_tmpl_id.product_variant_id.id},
{'product_id': kit_2.product_tmpl_id.product_variant_id.id}
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
self.assertRecordValues(order.lines, [
{'product_id': kit_3.product_tmpl_id.product_variant_id.id, 'total_cost': 50.0},
{'product_id': kit_2.product_tmpl_id.product_variant_id.id, 'total_cost': 30.0},
])
def test_never_variant_bom_product_picking(self):
self.attribute_1 = self.env['product.attribute'].create({
'name': 'Color',
'create_variant': 'no_variant',
'sequence': 1,
})
# Create attribute values
self.value_1_1 = self.env['product.attribute.value'].create({
'name': 'Red',
'attribute_id': self.attribute_1.id,
'sequence': 1,
})
self.value_1_2 = self.env['product.attribute.value'].create({
'name': 'Blue',
'attribute_id': self.attribute_1.id,
'sequence': 2,
})
# Create the configurable product with attributes
self.configurable_product = self.env['product.product'].create({
'name': 'Configurable Chair',
'is_storable': True,
'available_in_pos': True,
'list_price': 100,
})
ptal = self.env['product.template.attribute.line'].create([{
'product_tmpl_id': self.configurable_product.product_tmpl_id.id,
'attribute_id': self.attribute_1.id,
'value_ids': [Command.set([self.value_1_1.id, self.value_1_2.id])],
}])
# Create the component products
self.component_common = self.env['product.product'].create({
'name': 'Common Frame',
'is_storable': True,
'list_price': 50,
})
self.component_red = self.env['product.product'].create({
'name': 'Red Cushion',
'is_storable': True,
'list_price': 20,
})
self.component_blue = self.env['product.product'].create({
'name': 'Blue Cushion',
'is_storable': True,
'list_price': 20,
})
# Create BOM for the configurable product
self.bom = self.env['mrp.bom'].create({
'product_tmpl_id': self.configurable_product.product_tmpl_id.id,
'product_qty': 1.0,
'type': 'phantom', # Kit type
'bom_line_ids': [
Command.create({
'product_id': self.component_common.id,
'product_qty': 1.0,
}),
Command.create({
'product_id': self.component_red.id,
'product_qty': 1.0,
'bom_product_template_attribute_value_ids': [
Command.link(self.configurable_product.product_tmpl_id.attribute_line_ids[0].product_template_value_ids[0].id)
],
}),
Command.create({
'product_id': self.component_blue.id,
'product_qty': 1.0,
'bom_product_template_attribute_value_ids': [
Command.link(self.configurable_product.product_tmpl_id.attribute_line_ids[0].product_template_value_ids[1].id)
],
}),
],
})
self.pos_config_usd.open_ui()
current_session = self.pos_config_usd.current_session_id
pos_order_data = {
'amount_paid': 100,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 100,
'date_order': fields.Datetime.to_string(fields.Datetime.now()),
'fiscal_position_id': False,
'lines': [
Command.create({
'attribute_value_ids': [ptal.product_template_value_ids[0].id],
'discount': 0,
'pack_lot_ids': [],
'price_unit': 100.0,
'product_id': self.configurable_product.id,
'price_subtotal': 100.0,
'price_subtotal_incl': 100.0,
'qty': 1,
'tax_ids': [],
}),
Command.create({
'attribute_value_ids': [ptal.product_template_value_ids[1].id],
'discount': 0,
'pack_lot_ids': [],
'price_unit': 100.0,
'product_id': self.configurable_product.id,
'price_subtotal': 100.0,
'price_subtotal_incl': 100.0,
'qty': 1,
'tax_ids': [],
}),
],
'name': 'Order 12345-123-1234',
'partner_id': False,
'session_id': current_session.id,
'sequence_number': 2,
'payment_ids': [
Command.create({
'amount': 100,
'name': fields.Datetime.now(),
'payment_method_id': self.cash_payment_method.id
})
],
'uuid': '12345-123-1234',
'last_order_preparation_change': '{}',
'user_id': self.env.uid
}
self.env['pos.order'].sync_from_ui([pos_order_data])['pos.order'][0]['id']
self.assertEqual(len(current_session.picking_ids.move_line_ids), 4)
def test_bom_variant_exclusive_bom_lines(self):
"""This test make sure that the cost is correctly computed when a product has a BoM with lines linked
to specific variant."""
category = self.env['product.category'].create({
'name': 'Category for kit',
'property_cost_method': 'fifo',
'property_valuation': 'real_time',
})
self.kit = self.env['product.product'].create({
'name': 'Final Kit',
'available_in_pos': True,
attribute_size = self.env['product.attribute'].create({
'name': 'Size',
'create_variant': 'always',
'value_ids': [Command.create({'name': 'S'}), Command.create({'name': 'L'})],
})
product_test = self.env['product.template'].create({
'name': 'Test product',
'categ_id': category.id,
'taxes_id': False,
'type': 'product',
})
self.component_a = self.env['product.product'].create({
'name': 'Comp A',
'is_storable': True,
'available_in_pos': True,
'standard_price': 12000.0,
'categ_id': category.id,
'taxes_id': False,
'uom_id': self.env.ref('uom.product_uom_dozen').id,
'attribute_line_ids': [Command.create({
'attribute_id': attribute_size.id,
'value_ids': [Command.set(attribute_size.value_ids.ids)],
})],
})
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = self.kit
bom_product_form.product_tmpl_id = self.kit.product_tmpl_id
bom_product_form.product_qty = 2.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = self.component_a
bom_line.product_qty = 6.0
bom_line.product_uom_id = self.env.ref('uom.product_uom_unit')
self.bom_a = bom_product_form.save()
self.pos_config.open_ui()
order_data = {'data':
{'to_invoice': True,
'amount_paid': 2.0,
'amount_return': 0,
'amount_tax': 0,
'amount_total': 2.0,
'creation_date': fields.Datetime.to_string(fields.Datetime.now()),
'fiscal_position_id': False,
'pricelist_id': self.pos_config.available_pricelist_ids[0].id,
'lines': [[0,
0,
{'discount': 0,
'pack_lot_ids': [],
'price_unit': 2,
'product_id': self.kit.id,
'price_subtotal': 2,
'price_subtotal_incl': 2,
'qty': 2,
'tax_ids': []}],
],
'name': 'Order 00042-003-0014',
'partner_id': self.partner1.id,
'pos_session_id': self.pos_config.current_session_id.id,
'sequence_number': 2,
'statement_ids': [[0,
0,
{'amount': 2.0,
'name': fields.Datetime.now(),
'payment_method_id': self.cash_payment_method.id}]],
'uid': '00042-003-0014',
'user_id': self.env.uid},
}
order = self.env['pos.order'].create_from_ui([order_data])
order = self.env['pos.order'].browse(order[0]['id'])
accounts = self.kit.product_tmpl_id.get_product_accounts()
expense_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == accounts['expense'].id)
self.assertEqual(expense_line.filtered(lambda l: l.product_id == self.kit).debit, 6000.0)
interim_line = order.account_move.line_ids.filtered(lambda l: l.account_id.id == accounts['stock_output'].id)
self.assertEqual(interim_line.filtered(lambda l: l.product_id == self.kit).credit, 6000.0)
def test_bom_kit_order_total_cost_with_shared_component(self):
category = self.env['product.category'].create({
'name': 'Category for average cost',
'property_cost_method': 'average',
})
kit_1 = self.env['product.product'].create({
'name': 'Kit Product 1',
'available_in_pos': True,
'type': 'product',
'lst_price': 30.0,
'categ_id': category.id,
})
kit_2 = self.env['product.product'].create({
'name': 'Kit Product 2',
'available_in_pos': True,
'type': 'product',
'lst_price': 200.0,
'categ_id': category.id,
})
shared_component_a = self.env['product.product'].create({
'name': 'Shared Comp A',
'type': 'product',
'available_in_pos': True,
'lst_price': 10.0,
'standard_price': 5.0,
})
other_component_a = self.env['product.product'].create({
'name': 'Other Comp A',
'type': 'product',
'available_in_pos': True,
'lst_price': 20.0,
component_size = self.env['product.product'].create({
'name': 'Test Product - Small',
'standard_price': 10.0,
})
other_component_b = self.env['product.product'].create({
'name': 'Other Comp B',
'type': 'product',
'available_in_pos': True,
'lst_price': 30.0,
'standard_price': 20.0,
self.env['mrp.bom'].create({
'product_tmpl_id': product_test.id,
'product_uom_id': product_test.uom_id.id,
'product_qty': 1.0,
'type': 'phantom',
'bom_line_ids': [
Command.create({
'product_id': component_size.id,
'product_qty': 1,
'bom_product_template_attribute_value_ids': product_test.product_variant_ids[0].product_template_variant_value_ids.ids
}),
Command.create({
'product_id': component_size.id,
'product_qty': 2,
'bom_product_template_attribute_value_ids': product_test.product_variant_ids[1].product_template_variant_value_ids.ids
}),
]
})
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = kit_1
bom_product_form.product_tmpl_id = kit_1.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = shared_component_a
bom_line.product_qty = 1.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = other_component_a
bom_line.product_qty = 1.0
self.bom_a = bom_product_form.save()
bom_product_form = Form(self.env['mrp.bom'])
bom_product_form.product_id = kit_2
bom_product_form.product_tmpl_id = kit_2.product_tmpl_id
bom_product_form.product_qty = 1.0
bom_product_form.type = 'phantom'
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = shared_component_a
bom_line.product_qty = 10.0
with bom_product_form.bom_line_ids.new() as bom_line:
bom_line.product_id = other_component_b
bom_line.product_qty = 5.0
self.bom_b = bom_product_form.save()
self.pos_config.open_ui()
product_1 = product_test.product_variant_ids[0]
product_2 = product_test.product_variant_ids[1]
self.pos_config_usd.open_ui()
order = self.env['pos.order'].create({
'session_id': self.pos_config.current_session_id.id,
'session_id': self.pos_config_usd.current_session_id.id,
'lines': [(0, 0, {
'name': kit_1.name,
'product_id': kit_1.id,
'price_unit': kit_1.lst_price,
'name': product_2.name,
'product_id': product_2.id,
'price_unit': product_2.lst_price,
'qty': 1,
'tax_ids': [[6, False, []]],
'price_subtotal': kit_1.lst_price,
'price_subtotal_incl': kit_1.lst_price,
}), (0, 0, {
'name': kit_2.name,
'product_id': kit_2.id,
'price_unit': kit_2.lst_price,
'tax_ids': [],
'price_subtotal': product_2.lst_price,
'price_subtotal_incl': product_2.lst_price,
}),
(0, 0, {
'name': product_1.name,
'product_id': product_1.id,
'price_unit': product_1.lst_price,
'qty': 1,
'tax_ids': [[6, False, []]],
'price_subtotal': kit_2.lst_price,
'price_subtotal_incl': kit_2.lst_price,
'tax_ids': [],
'price_subtotal': product_1.lst_price,
'price_subtotal_incl': product_1.lst_price,
})],
'pricelist_id': self.pos_config.pricelist_id.id,
'amount_paid': kit_1.lst_price + kit_2.lst_price,
'amount_total': kit_1.lst_price + kit_2.lst_price,
'pricelist_id': self.pos_config_usd.pricelist_id.id,
'amount_paid': product_2.lst_price + product_1.lst_price,
'amount_total': product_2.lst_price + product_1.lst_price,
'amount_tax': 0.0,
'amount_return': 0.0,
'to_invoice': False,
})
payment_context = {"active_ids": order.ids, "active_id": order.id}
order_payment = self.PosMakePayment.with_context(**payment_context).create({
order_payment = self.env['pos.make.payment'].with_context(**payment_context).create({
'amount': order.amount_total,
'payment_method_id': self.cash_payment_method.id
})
order_payment.with_context(**payment_context).check()
self.pos_config.current_session_id.action_pos_session_closing_control()
pos_order = self.env['pos.order'].search([], order='id desc', limit=1)
self.assertRecordValues(pos_order.lines, [
{'product_id': kit_1.id, 'total_cost': 15.0},
{'product_id': kit_2.id, 'total_cost': 150.0},
self.pos_config_usd.current_session_id.action_pos_session_closing_control()
self.assertRecordValues(order.lines, [
{'product_id': product_2.id, 'total_cost': 20},
{'product_id': product_1.id, 'total_cost': 10},
])
# TODO : Merge this test with the other class when it is not skipped anymore
@odoo.tests.tagged('post_install', '-at_install')
class TestPosMrpTemp(CommonPosMrpTest):
def test_bom_kit_different_uom_invoice_valuation_no_invoice(self):
"""This test make sure that when a kit is made of product using UoM A but the bom line uses UoM B
the price unit is correctly computed on the invoice lines.
"""
self.env.user.group_ids += self.env.ref('uom.group_uom')
self.env.company.inventory_valuation = 'real_time'
# Edit kit product and component product
self.product_product_kit_one.categ_id = self.category_fifo_realtime
self.product_product_comp_one.standard_price = 12000
self.product_product_comp_one.uom_id = self.env.ref('uom.product_uom_dozen').id
self.product_product_comp_one.categ_id = self.category_fifo_realtime
self.product_product_comp_one.is_storable = True
# Edit kit product UoM
self.bom_one_line.bom_line_ids[0].product_uom_id = self.env.ref('uom.product_uom_unit').id
self.create_backend_pos_order({
'order_data': {
'partner_id': self.partner_moda.id,
},
'line_data': [
{'product_id': self.product_product_kit_one.id, 'qty': 1},
],
'payment_data': [
{'payment_method_id': self.cash_payment_method.id}
]
})
current_session = self.pos_config_usd.current_session_id
current_session.action_pos_session_closing_control()
accounts = self.product_product_kit_one.product_tmpl_id.get_product_accounts()
expense_line = current_session.move_id.line_ids.filtered(
lambda l: l.account_id.id == accounts['expense'].id)
interim_line = current_session.move_id.line_ids.filtered(
lambda l: l.account_id.id == accounts['stock_valuation'].id)
self.assertEqual(expense_line.debit, 1000.0)
self.assertEqual(interim_line.credit, 1000.0)