mirror of
https://github.com/bringout/oca-mrp.git
synced 2026-04-23 10:12:05 +02:00
324 lines
13 KiB
Python
324 lines
13 KiB
Python
# Copyright 2019 Camptocamp SA
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
|
|
import odoo
|
|
from odoo import fields
|
|
|
|
from odoo.addons.sale_timesheet.tests.common import TestCommonSaleTimesheet
|
|
|
|
|
|
@odoo.tests.tagged("post_install", "-at_install")
|
|
class TestRounded(TestCommonSaleTimesheet):
|
|
@classmethod
|
|
def setUpClass(cls, chart_template_ref=None):
|
|
super().setUpClass(chart_template_ref=chart_template_ref)
|
|
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
|
|
cls.sale_order = cls.env["sale.order"].create(
|
|
{
|
|
"analytic_account_id": cls.project_global.analytic_account_id.id,
|
|
"partner_id": cls.partner_a.id,
|
|
"partner_invoice_id": cls.partner_a.id,
|
|
"partner_shipping_id": cls.partner_a.id,
|
|
}
|
|
)
|
|
cls.env["sale.order.line"].create(
|
|
{
|
|
"order_id": cls.sale_order.id,
|
|
"name": cls.product_delivery_timesheet2.name,
|
|
"product_id": cls.product_delivery_timesheet2.id,
|
|
"product_uom_qty": 1,
|
|
"product_uom": cls.product_delivery_timesheet2.uom_id.id,
|
|
"price_unit": cls.product_delivery_timesheet2.list_price,
|
|
}
|
|
)
|
|
cls.sale_order.action_confirm()
|
|
cls.project_global.write(
|
|
{
|
|
"timesheet_rounding_unit": 0.25,
|
|
"timesheet_rounding_method": "UP",
|
|
"timesheet_rounding_factor": 200,
|
|
}
|
|
)
|
|
cls.product_expense = cls.env["product.product"].create(
|
|
{
|
|
"name": "Service delivered, EXPENSE",
|
|
"expense_policy": "cost",
|
|
"standard_price": 30,
|
|
"list_price": 90,
|
|
"type": "service",
|
|
"invoice_policy": "order",
|
|
"uom_id": cls.product_delivery_timesheet2.uom_id.id,
|
|
"uom_po_id": cls.product_delivery_timesheet2.uom_id.id,
|
|
}
|
|
)
|
|
cls.analytic_plan = cls.env["account.analytic.plan"].create(
|
|
{
|
|
"name": "Plan sale timesheet",
|
|
"company_id": False,
|
|
}
|
|
)
|
|
cls.avg_analytic_account = cls.env["account.analytic.account"].create(
|
|
{
|
|
"name": "AVG account",
|
|
"plan_id": cls.analytic_plan.id,
|
|
}
|
|
)
|
|
|
|
def create_analytic_line(self, **kw):
|
|
task = self.sale_order.tasks_ids[0]
|
|
values = {
|
|
"project_id": self.project_global.id,
|
|
"task_id": task.id,
|
|
"name": "Rounded test line",
|
|
"date": fields.Date.today(),
|
|
"unit_amount": 0,
|
|
"product_id": self.product_delivery_timesheet2.id,
|
|
"employee_id": self.employee_user.id,
|
|
}
|
|
values.update(kw)
|
|
return self.env["account.analytic.line"].create(values)
|
|
|
|
def test_analytic_line_init_no_rounding(self):
|
|
lines = self.env["account.analytic.line"].search([])
|
|
for line in lines:
|
|
self.assertEqual(line.unit_amount_rounded, line.unit_amount)
|
|
|
|
def test_analytic_line_create_no_rounding(self):
|
|
self.project_global.write({"timesheet_rounding_method": "NO"})
|
|
# no rounding enabled
|
|
line = self.create_analytic_line(unit_amount=1)
|
|
self.assertEqual(line.unit_amount, 1.0)
|
|
self.assertEqual(line.unit_amount_rounded, line.unit_amount)
|
|
|
|
def test_analytic_line_create(self):
|
|
line = self.create_analytic_line(unit_amount=1)
|
|
self.assertEqual(line.unit_amount_rounded, 2.0)
|
|
line = self.create_analytic_line(unit_amount=1, unit_amount_rounded=0)
|
|
self.assertEqual(line.unit_amount_rounded, 0.0)
|
|
|
|
def test_analytic_line_create_and_update_amount_rounded(self):
|
|
line = self.create_analytic_line(unit_amount=2)
|
|
self.assertEqual(line.unit_amount_rounded, 4.0)
|
|
line.write({"unit_amount_rounded": 5.0})
|
|
self.assertEqual(line.unit_amount_rounded, 5.0)
|
|
line.write({"unit_amount_rounded": 0.0})
|
|
self.assertEqual(line.unit_amount_rounded, 0.0)
|
|
|
|
def test_analytic_line_create_and_update_amount(self):
|
|
line = self.create_analytic_line(unit_amount=2)
|
|
self.assertEqual(line.unit_amount_rounded, 4.0)
|
|
line.unit_amount = 5.0
|
|
self.assertEqual(line.unit_amount_rounded, 10.0)
|
|
|
|
def test_analytic_line_read_group_override(self):
|
|
# Test of the read group with an without timesheet_rounding context
|
|
# without context the unit_amount should be the initial
|
|
# with the context the value of unit_amount should be replaced by the
|
|
# unit_amount_rounded
|
|
line = self.env["account.analytic.line"]
|
|
self.create_analytic_line(unit_amount=1)
|
|
domain = [("project_id", "=", self.project_global.id)]
|
|
fields_list = ["so_line", "unit_amount", "product_uom_id"]
|
|
groupby = ["product_uom_id", "so_line"]
|
|
|
|
data_ctx_f = line.read_group(
|
|
domain,
|
|
fields_list,
|
|
groupby,
|
|
)
|
|
self.assertEqual(data_ctx_f[0]["unit_amount"], 1.0)
|
|
|
|
data_ctx_t = line.with_context(timesheet_rounding=True).read_group(
|
|
domain,
|
|
fields_list,
|
|
groupby,
|
|
)
|
|
self.assertEqual(data_ctx_t[0]["unit_amount"], 2.0)
|
|
|
|
self.create_analytic_line(unit_amount=1.1)
|
|
data_ctx_f = line.with_context(timesheet_rounding=False).read_group(
|
|
domain,
|
|
fields_list,
|
|
groupby,
|
|
)
|
|
self.assertEqual(data_ctx_f[0]["unit_amount"], 2.1)
|
|
|
|
data_ctx_f = line.with_context(timesheet_rounding=True).read_group(
|
|
domain,
|
|
fields_list,
|
|
groupby,
|
|
)
|
|
self.assertEqual(data_ctx_f[0]["unit_amount"], 4.25)
|
|
|
|
def test_analytic_line_read_override(self):
|
|
# Cases for not rounding:
|
|
# * not linked to project -> no impact
|
|
# * is an expense -> no impact
|
|
# * ctx key for rounding is set to false -> no impact
|
|
# In all the other cases we check that unit amount is rounded.
|
|
load = "_classic_read"
|
|
fields = None
|
|
|
|
# context = False + project_id - product_expense
|
|
line = self.create_analytic_line(unit_amount=1)
|
|
unit_amount_ret = line.read(fields, load)[0]["unit_amount"]
|
|
self.assertEqual(unit_amount_ret, 1)
|
|
|
|
# context = True + project_id + product_expense
|
|
line = self.create_analytic_line(
|
|
unit_amount=1, product_id=self.product_expense.id
|
|
)
|
|
unit_amount_ret = line.with_context(timesheet_rounding=True).read(fields, load)[
|
|
0
|
|
]["unit_amount"]
|
|
self.assertEqual(unit_amount_ret, 2)
|
|
|
|
# context = True + project_id - product_expense
|
|
line = self.create_analytic_line(unit_amount=1)
|
|
unit_amount_ret = line.with_context(timesheet_rounding=True).read(fields, load)[
|
|
0
|
|
]["unit_amount"]
|
|
self.assertEqual(unit_amount_ret, 2)
|
|
|
|
def test_sale_order_qty_1(self):
|
|
# amount=1 -> should be rounded to 2 by the invoicing_factor
|
|
self.create_analytic_line(unit_amount=1)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_delivered, 2.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_to_invoice, 2.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_invoiced, 0)
|
|
|
|
def test_sale_order_qty_2(self):
|
|
# force amount_rounded=4
|
|
self.create_analytic_line(unit_amount=1, unit_amount_rounded=4)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_delivered, 4.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_to_invoice, 4.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_invoiced, 0)
|
|
|
|
def test_sale_order_qty_3(self):
|
|
# amount=0.9
|
|
# should be rounded to 2 by the invoicing_factor with the project
|
|
# timesheet_rounding_unit: 0.25
|
|
# timesheet_rounding_method: 'UP'
|
|
# timesheet_rounding_factor: 200
|
|
self.create_analytic_line(unit_amount=0.9)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_delivered, 2.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_to_invoice, 2.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_invoiced, 0)
|
|
|
|
def test_sale_order_qty_4(self):
|
|
# amount=0.9
|
|
# should be rounded to 2 by the invoicing_factor with the project
|
|
# timesheet_rounding_unit: 0.25
|
|
# timesheet_rounding_method: 'UP'
|
|
# timesheet_rounding_factor: 200
|
|
self.project_global.timesheet_rounding_factor = 400
|
|
self.create_analytic_line(unit_amount=1.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_delivered, 4.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_to_invoice, 4.0)
|
|
self.assertAlmostEqual(self.sale_order.order_line.qty_invoiced, 0)
|
|
|
|
def test_calc_rounded_amount_method(self):
|
|
aal = self.env["account.analytic.line"]
|
|
rounding_unit = 0.25
|
|
rounding_method = "UP"
|
|
factor = 200
|
|
amount = 1
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 2
|
|
)
|
|
|
|
rounding_unit = 0.0
|
|
rounding_method = "UP"
|
|
factor = 200
|
|
amount = 1
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 2
|
|
)
|
|
|
|
rounding_unit = 0.25
|
|
rounding_method = "UP"
|
|
factor = 100
|
|
amount = 1.0
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 1
|
|
)
|
|
|
|
rounding_unit = 0.25
|
|
rounding_method = "UP"
|
|
factor = 200
|
|
amount = 0.9
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 2
|
|
)
|
|
|
|
rounding_unit = 1.0
|
|
rounding_method = "UP"
|
|
factor = 200
|
|
amount = 0.6
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 2
|
|
)
|
|
|
|
rounding_unit = 0.25
|
|
rounding_method = "HALF_UP"
|
|
factor = 200
|
|
amount = 1.01
|
|
self.assertEqual(
|
|
aal._calc_rounded_amount(rounding_unit, rounding_method, factor, amount), 2
|
|
)
|
|
|
|
def test_post_invoice_with_rounded_amount_unchanged(self):
|
|
"""Posting an invoice MUST NOT recompute rounded amount unit.
|
|
- invoicing the SO should not recompute and update the
|
|
unit_amount_rounded
|
|
- the invoiced qty should be the same as the aal.unit_amount_rounded
|
|
"""
|
|
unit_amount_rounded = 111
|
|
analytic_line = self.create_analytic_line(unit_amount=10)
|
|
analytic_line.unit_amount_rounded = unit_amount_rounded
|
|
account_move = self.sale_order._create_invoices()
|
|
prd_ts_id = self.product_delivery_timesheet2
|
|
account_move._post()
|
|
# the unit_amount_rounded is not changed
|
|
self.assertEqual(analytic_line.unit_amount_rounded, unit_amount_rounded)
|
|
# the invoiced qty remains the same
|
|
inv_line = account_move.line_ids.filtered(lambda l: l.product_id == prd_ts_id)
|
|
self.assertEqual(inv_line.quantity, unit_amount_rounded)
|
|
|
|
def test_draft_invoice_with_rounded_amount_unchanged(self):
|
|
"""Drafting an invoice MUST NOT recompute rounded amount unit.
|
|
- invoicing the SO should not recompute and update the
|
|
unit_amount_rounded
|
|
- the invoiced qty should be the same as the aal.unit_amount_rounded
|
|
"""
|
|
unit_amount_rounded = 0.12
|
|
analytic_line = self.create_analytic_line(unit_amount=10)
|
|
analytic_line.unit_amount_rounded = unit_amount_rounded
|
|
account_move = self.sale_order._create_invoices()
|
|
prd_ts_id = self.product_delivery_timesheet2
|
|
account_move.button_draft()
|
|
# the unit_amount_rounded is not changed
|
|
self.assertEqual(analytic_line.unit_amount_rounded, unit_amount_rounded)
|
|
# the invoiced qty remains the same
|
|
inv_line = account_move.line_ids.filtered(lambda l: l.product_id == prd_ts_id)
|
|
self.assertEqual(inv_line.quantity, unit_amount_rounded)
|
|
|
|
def test_cancel_invoice_with_rounded_amount_unchanged(self):
|
|
"""Cancelling an invoice MUST NOT recompute rounded amount unit.
|
|
- invoicing the SO should not recompute and update the
|
|
unit_amount_rounded
|
|
- the invoiced qty should be the same as the aal.unit_amount_rounded
|
|
"""
|
|
unit_amount_rounded_total = 15
|
|
analytic_line_1 = self.create_analytic_line(unit_amount=10)
|
|
analytic_line_2 = self.create_analytic_line(unit_amount=10)
|
|
analytic_line_1.unit_amount_rounded = unit_amount_rounded_total
|
|
analytic_line_2.unit_amount_rounded = 0
|
|
account_move = self.sale_order._create_invoices()
|
|
prd_ts_id = self.product_delivery_timesheet2
|
|
account_move.button_cancel()
|
|
# the unit_amount_rounded is not changed
|
|
self.assertEqual(analytic_line_1.unit_amount_rounded, unit_amount_rounded_total)
|
|
self.assertEqual(analytic_line_2.unit_amount_rounded, 0)
|
|
# the invoiced qty remains the same
|
|
inv_line = account_move.line_ids.filtered(lambda l: l.product_id == prd_ts_id)
|
|
self.assertEqual(inv_line.quantity, unit_amount_rounded_total)
|