Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
2
account_invoice_section_sale_order/tests/__init__.py
Normal file
2
account_invoice_section_sale_order/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import test_invoice_group_by_sale_order
|
||||
from . import test_access_rights
|
||||
89
account_invoice_section_sale_order/tests/common.py
Normal file
89
account_invoice_section_sale_order/tests/common.py
Normal file
@@ -0,0 +1,89 @@
|
||||
from odoo.tests import tagged
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
@tagged("-at_install", "post_install")
|
||||
class Common(TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||
cls.setUpClassOrder()
|
||||
|
||||
@classmethod
|
||||
def setUpClassOrder(cls):
|
||||
cls.partner_1 = cls.env.ref("base.res_partner_1")
|
||||
cls.product_1 = cls.env.ref("product.product_product_1")
|
||||
cls.product_2 = cls.env.ref("product.product_product_2")
|
||||
cls.product_1.invoice_policy = "order"
|
||||
cls.product_2.invoice_policy = "order"
|
||||
cls.pricelist = cls.env["product.pricelist"].create(
|
||||
{"name": "Europe pricelist", "currency_id": cls.env.ref("base.EUR").id}
|
||||
)
|
||||
cls.order1_p1 = cls.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": cls.partner_1.id,
|
||||
"partner_shipping_id": cls.partner_1.id,
|
||||
"partner_invoice_id": cls.partner_1.id,
|
||||
"client_order_ref": "ref123",
|
||||
"pricelist_id": cls.pricelist.id,
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "order 1 line 1",
|
||||
"product_id": cls.product_1.id,
|
||||
"price_unit": 20,
|
||||
"product_uom_qty": 1,
|
||||
"product_uom": cls.product_1.uom_id.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "order 1 line 2",
|
||||
"product_id": cls.product_2.id,
|
||||
"price_unit": 20,
|
||||
"product_uom_qty": 1,
|
||||
"product_uom": cls.product_1.uom_id.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.order1_p1.action_confirm()
|
||||
cls.order2_p1 = cls.env["sale.order"].create(
|
||||
{
|
||||
"partner_id": cls.partner_1.id,
|
||||
"partner_shipping_id": cls.partner_1.id,
|
||||
"partner_invoice_id": cls.partner_1.id,
|
||||
"pricelist_id": cls.pricelist.id,
|
||||
"order_line": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "order 2 line 1",
|
||||
"product_id": cls.product_1.id,
|
||||
"price_unit": 20,
|
||||
"product_uom_qty": 1,
|
||||
"product_uom": cls.product_1.uom_id.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"name": "order 2 line 2",
|
||||
"product_id": cls.product_2.id,
|
||||
"price_unit": 20,
|
||||
"product_uom_qty": 1,
|
||||
"product_uom": cls.product_1.uom_id.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
cls.order2_p1.action_confirm()
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright 2024 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
||||
|
||||
from odoo.tests import tagged
|
||||
|
||||
from .common import Common
|
||||
|
||||
|
||||
@tagged("-at_install", "post_install")
|
||||
class TestAccessRights(Common):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
||||
cls.setUpClassUser()
|
||||
|
||||
@classmethod
|
||||
def setUpClassUser(cls):
|
||||
cls.create_only_group = cls.env["res.groups"].create(
|
||||
{"name": "Create Only Group"}
|
||||
)
|
||||
cls.sale_manager_group = cls.env.ref("sales_team.group_sale_manager")
|
||||
cls.env["ir.model.access"].create(
|
||||
[
|
||||
{
|
||||
"name": "invoice_create_only",
|
||||
"model_id": cls.env.ref("account.model_account_move").id,
|
||||
"group_id": cls.create_only_group.id,
|
||||
"perm_read": 0,
|
||||
"perm_write": 0,
|
||||
"perm_create": 1,
|
||||
"perm_unlink": 0,
|
||||
},
|
||||
{
|
||||
"name": "invoice_line_create_only",
|
||||
"model_id": cls.env.ref("account.model_account_move_line").id,
|
||||
"group_id": cls.create_only_group.id,
|
||||
"perm_read": 0,
|
||||
"perm_write": 0,
|
||||
"perm_create": 1,
|
||||
"perm_unlink": 0,
|
||||
},
|
||||
]
|
||||
)
|
||||
cls.create_only_user = cls.env["res.users"].create(
|
||||
{
|
||||
"name": "Create Only User",
|
||||
"login": "createonlyuser@example.com",
|
||||
"groups_id": [
|
||||
(6, 0, (cls.create_only_group | cls.sale_manager_group).ids),
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
def test_access_rights(self):
|
||||
orders = self.order1_p1 + self.order2_p1
|
||||
# We're testing that no exception is raised while creating invoices
|
||||
# with a user having only create access on the invoices models
|
||||
invoice_ids = orders.with_user(self.create_only_user)._create_invoices()
|
||||
self.assertTrue(bool(invoice_ids))
|
||||
@@ -0,0 +1,114 @@
|
||||
# Copyright 2020 Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
|
||||
from unittest import mock
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
from .common import Common
|
||||
|
||||
SECTION_GROUPING_FUNCTION = "odoo.addons.account_invoice_section_sale_order.models.account_move.AccountMoveLine._get_section_grouping" # noqa
|
||||
SECTION_NAME_FUNCTION = (
|
||||
"odoo.addons.base.models.res_users.Users._get_invoice_section_name"
|
||||
)
|
||||
|
||||
|
||||
class TestInvoiceGroupBySaleOrder(Common):
|
||||
def test_create_invoice(self):
|
||||
"""Check invoice is generated with sale order sections."""
|
||||
result = {
|
||||
10: (
|
||||
"".join([self.order1_p1.name, " - ", self.order1_p1.client_order_ref]),
|
||||
"line_section",
|
||||
),
|
||||
20: (f"{self.product_1.name} order 1 line 1", "product"),
|
||||
30: (f"{self.product_2.name} order 1 line 2", "product"),
|
||||
40: (self.order2_p1.name, "line_section"),
|
||||
50: (f"{self.product_1.name} order 2 line 1", "product"),
|
||||
60: (f"{self.product_2.name} order 2 line 2", "product"),
|
||||
}
|
||||
invoice_ids = (self.order1_p1 + self.order2_p1)._create_invoices()
|
||||
lines = invoice_ids[0].invoice_line_ids.sorted("sequence")
|
||||
for line in lines:
|
||||
if line.sequence not in result:
|
||||
continue
|
||||
self.assertEqual(line.name, result[line.sequence][0])
|
||||
self.assertEqual(line.display_type, result[line.sequence][1])
|
||||
|
||||
def test_create_invoice_with_currency(self):
|
||||
"""Check invoice is generated with a correct total amount"""
|
||||
orders = self.order1_p1 | self.order2_p1
|
||||
invoices = orders._create_invoices()
|
||||
self.assertEqual(invoices.amount_untaxed, 80)
|
||||
|
||||
def test_create_invoice_with_default_journal(self):
|
||||
"""Using a specific journal for the invoice should not be broken"""
|
||||
journal = self.env["account.journal"].search([("type", "=", "sale")], limit=1)
|
||||
(self.order1_p1 + self.order2_p1).with_context(
|
||||
default_journal_id=journal.id
|
||||
)._create_invoices()
|
||||
|
||||
def test_create_invoice_no_section(self):
|
||||
"""Check invoice for only one sale order
|
||||
|
||||
No need to create sections
|
||||
|
||||
"""
|
||||
invoice_id = (self.order1_p1)._create_invoices()
|
||||
line_sections = invoice_id.line_ids.filtered(
|
||||
lambda r: r.display_type == "line_section"
|
||||
)
|
||||
self.assertEqual(len(line_sections), 0)
|
||||
|
||||
def test_unknown_invoice_section_grouping_value(self):
|
||||
"""Check an error is raised when invoice_section_grouping value is
|
||||
unknown
|
||||
"""
|
||||
mock_company_section_grouping = mock.patch.object(
|
||||
type(self.env.company),
|
||||
"invoice_section_grouping",
|
||||
new_callable=mock.PropertyMock,
|
||||
)
|
||||
with mock_company_section_grouping as mocked_company_section_grouping:
|
||||
mocked_company_section_grouping.return_value = "unknown"
|
||||
with self.assertRaises(UserError):
|
||||
(self.order1_p1 + self.order2_p1)._create_invoices()
|
||||
|
||||
def test_custom_grouping_by_sale_order_user(self):
|
||||
"""Check custom grouping by sale order user.
|
||||
|
||||
By mocking account.move.line_get_section_grouping and creating
|
||||
res.users.get_invoice_section_name, this test ensures custom grouping
|
||||
is possible by redefining these functions"""
|
||||
demo_user = self.env.ref("base.user_demo")
|
||||
admin_user = self.env.ref("base.partner_admin")
|
||||
orders = self.order1_p1 + self.order2_p1
|
||||
orders.write({"user_id": admin_user.id})
|
||||
sale_order_3 = self.order1_p1.copy({"user_id": demo_user.id})
|
||||
sale_order_3.order_line[0].name = "order 3 line 1"
|
||||
sale_order_3.order_line[1].name = "order 3 line 2"
|
||||
sale_order_3.action_confirm()
|
||||
|
||||
with (
|
||||
mock.patch(SECTION_GROUPING_FUNCTION) as mocked_get_section_grouping,
|
||||
mock.patch(
|
||||
SECTION_NAME_FUNCTION, create=True
|
||||
) as mocked_get_invoice_section_name,
|
||||
):
|
||||
mocked_get_section_grouping.return_value = "sale_line_ids.order_id.user_id"
|
||||
mocked_get_invoice_section_name.return_value = "Mocked value from ResUsers"
|
||||
invoice = (orders + sale_order_3)._create_invoices()
|
||||
result = {
|
||||
10: ("Mocked value from ResUsers", "line_section"),
|
||||
20: (f"{self.product_1.name} order 1 line 1", "product"),
|
||||
30: (f"{self.product_2.name} order 1 line 2", "product"),
|
||||
40: (f"{self.product_1.name} order 2 line 1", "product"),
|
||||
50: (f"{self.product_2.name} order 2 line 2", "product"),
|
||||
60: ("Mocked value from ResUsers", "line_section"),
|
||||
70: (f"{self.product_1.name} order 3 line 1", "product"),
|
||||
80: (f"{self.product_2.name} order 3 line 2", "product"),
|
||||
}
|
||||
for line in invoice.invoice_line_ids.sorted("sequence"):
|
||||
if line.sequence not in result:
|
||||
continue
|
||||
self.assertEqual(line.name, result[line.sequence][0])
|
||||
self.assertEqual(line.display_type, result[line.sequence][1])
|
||||
Reference in New Issue
Block a user