19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:07 +01:00
parent ba20ce7443
commit 768b70e05e
2357 changed files with 1057103 additions and 712486 deletions

View file

@ -2,57 +2,24 @@
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.exceptions import ValidationError
from odoo.tests import tagged
from odoo.tests import Form, tagged
from odoo import fields, Command
from odoo.tests.common import Form
from odoo.tools.safe_eval import datetime
@tagged('post_install', '-at_install')
class TestAccountPaymentTerms(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
def setUpClass(cls):
super().setUpClass()
cls.other_currency = cls.setup_other_currency('EUR', rounding=0.001)
cls.pay_term_today = cls.env['account.payment.term'].create({
'name': 'Today',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 0,
}),
],
})
cls.pay_term_next_month_on_the_15 = cls.env['account.payment.term'].create({
'name': 'Next month on the 15th',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 0,
'end_month': True,
'days_after': 15,
}),
],
})
cls.pay_term_last_day_of_month = cls.env['account.payment.term'].create({
'name': 'Last Day of month',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 0,
'end_month': True
}),
],
})
cls.pay_term_first_day_next_month = cls.env['account.payment.term'].create({
'name': 'First day next month',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 0,
'end_month': True,
'days_after': 1,
'value_amount': 100,
'value': 'percent',
'nb_days': 0,
}),
],
})
@ -61,110 +28,133 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon):
'name': 'Net 30 days',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 30,
'value_amount': 100,
'value': 'percent',
'nb_days': 30,
}),
],
})
cls.pay_term_30_days_end_of_month = cls.env['account.payment.term'].create({
'name': '30 days end of month',
cls.pay_term_60_days = cls.env['account.payment.term'].create({
'name': '60 days two lines',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 30,
'end_month': True
'value_amount': 30,
'value': 'percent',
'nb_days': 15,
}),
(0, 0, {
'value_amount': 70,
'value': 'percent',
'nb_days': 45,
}),
],
})
cls.pay_term_1_month_end_of_month = cls.env['account.payment.term'].create({
'name': '1 month, end of month',
cls.pay_term_30_days = cls.env['account.payment.term'].create({
'name': '60 days two lines',
'line_ids': [
(0, 0, {
'value': 'balance',
'months': 1,
'days': 0,
'end_month': True
}),
],
})
cls.pay_term_30_days_end_of_month_the_10 = cls.env['account.payment.term'].create({
'name': '30 days end of month the 10th',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 30,
'end_month': True,
'days_after': 10,
}),
],
})
cls.pay_term_90_days_end_of_month_the_10 = cls.env['account.payment.term'].create({
'name': '90 days end of month the 10',
'line_ids': [
(0, 0, {
'value': 'balance',
'days': 90,
'end_month': True,
'days_after': 10,
}),
],
})
cls.pay_term_3_months_end_of_month_the_10 = cls.env['account.payment.term'].create({
'name': '3 months end of month the 10',
'line_ids': [
(0, 0, {
'value': 'balance',
'months': 3,
'end_month': True,
'days_after': 10,
}),
],
})
cls.pay_term_end_month_on_the_30th = cls.env['account.payment.term'].create({
'name': 'End of month, the 30th',
'line_ids': [
(0, 0, {
'value': 'balance',
'end_month': True,
'days_after': 30,
}),
],
})
cls.pay_term_1_month_15_days_end_month_45_days = cls.env['account.payment.term'].create({
'name': '1 month, 15 days, end month, 45 days',
'line_ids': [
(0, 0, {
'value': 'balance',
'months': 1,
'days': 15,
'end_month': True,
'days_after': 45,
}),
],
})
cls.pay_term_next_10_of_the_month = cls.env['account.payment.term'].create({
'name': 'Next 10th of the month',
'line_ids': [
(0, 0, {
'value': 'balance',
'months': 0,
'days': -10,
'end_month': True,
'days_after': 10,
'value_amount': 100,
'value': 'percent',
'nb_days': 15,
}),
],
})
cls.invoice = cls.init_invoice('out_refund', products=cls.product_a+cls.product_b)
cls.pay_term_a = cls.env['account.payment.term'].create({
'name': "turlututu",
'early_discount': True,
'discount_percentage': 10,
'discount_days': 1,
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'nb_days': 2,
}),
],
})
cls.pay_term_b = cls.env['account.payment.term'].create({
'name': "tralala",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 50,
'nb_days': 2,
}),
Command.create({
'value': 'percent',
'value_amount': 50,
'nb_days': 4,
}),
],
})
cls.pay_term_days_end_of_month_10 = cls.env['account.payment.term'].create({
'name': "basic case",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'nb_days': 30,
'delay_type': 'days_end_of_month_on_the',
'days_next_month': 10,
}),
],
})
cls.pay_term_days_end_of_month_31 = cls.env['account.payment.term'].create({
'name': "special case 31",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'nb_days': 30,
'delay_type': 'days_end_of_month_on_the',
'days_next_month': 31,
}),
],
})
cls.pay_term_days_end_of_month_30 = cls.env['account.payment.term'].create({
'name': "special case 30",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'delay_type': 'days_end_of_month_on_the',
'days_next_month': 30,
'nb_days': 0,
}),
],
})
cls.pay_term_days_end_of_month_29 = cls.env['account.payment.term'].create({
'name': "special case 29",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'delay_type': 'days_end_of_month_on_the',
'days_next_month': 29,
'nb_days': 0,
}),
],
})
cls.pay_term_days_end_of_month_days_next_month_0 = cls.env['account.payment.term'].create({
'name': "special case days next month 0",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 100,
'delay_type': 'days_end_of_month_on_the',
'days_next_month': 0,
'nb_days': 30,
}),
],
})
def assertPaymentTerm(self, pay_term, invoice_date, dates):
with Form(self.invoice) as move_form:
move_form.invoice_payment_term_id = pay_term
@ -172,7 +162,7 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon):
self.assertEqual(
self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']
).mapped('date_maturity'),
).sorted(key=lambda r: r.date_maturity).mapped('date_maturity'),
[fields.Date.from_string(date) for date in dates],
)
@ -180,223 +170,496 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon):
self.assertPaymentTerm(self.pay_term_today, '2019-01-01', ['2019-01-01'])
self.assertPaymentTerm(self.pay_term_today, '2019-01-15', ['2019-01-15'])
self.assertPaymentTerm(self.pay_term_today, '2019-01-31', ['2019-01-31'])
self.assertPaymentTerm(self.pay_term_next_month_on_the_15, '2019-01-01', ['2019-02-15'])
self.assertPaymentTerm(self.pay_term_next_month_on_the_15, '2019-01-15', ['2019-02-15'])
self.assertPaymentTerm(self.pay_term_next_month_on_the_15, '2019-01-31', ['2019-02-15'])
self.assertPaymentTerm(self.pay_term_last_day_of_month, '2019-01-01', ['2019-01-31'])
self.assertPaymentTerm(self.pay_term_last_day_of_month, '2019-01-15', ['2019-01-31'])
self.assertPaymentTerm(self.pay_term_last_day_of_month, '2019-01-31', ['2019-01-31'])
self.assertPaymentTerm(self.pay_term_first_day_next_month, '2019-01-01', ['2019-02-01'])
self.assertPaymentTerm(self.pay_term_first_day_next_month, '2019-01-15', ['2019-02-01'])
self.assertPaymentTerm(self.pay_term_first_day_next_month, '2019-01-31', ['2019-02-01'])
self.assertPaymentTerm(self.pay_term_net_30_days, '2022-01-01', ['2022-01-31'])
self.assertPaymentTerm(self.pay_term_net_30_days, '2022-01-15', ['2022-02-14'])
self.assertPaymentTerm(self.pay_term_net_30_days, '2022-01-31', ['2022-03-02'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month, '2022-01-01', ['2022-01-31'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month, '2022-01-15', ['2022-02-28'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month, '2022-01-31', ['2022-03-31'])
self.assertPaymentTerm(self.pay_term_1_month_end_of_month, '2022-01-01', ['2022-02-28'])
self.assertPaymentTerm(self.pay_term_1_month_end_of_month, '2022-01-15', ['2022-02-28'])
self.assertPaymentTerm(self.pay_term_1_month_end_of_month, '2022-01-31', ['2022-02-28'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month_the_10, '2022-01-01', ['2022-02-10'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month_the_10, '2022-01-15', ['2022-03-10'])
self.assertPaymentTerm(self.pay_term_30_days_end_of_month_the_10, '2022-01-31', ['2022-04-10'])
self.assertPaymentTerm(self.pay_term_90_days_end_of_month_the_10, '2022-01-01', ['2022-05-10'])
self.assertPaymentTerm(self.pay_term_90_days_end_of_month_the_10, '2022-01-15', ['2022-05-10'])
self.assertPaymentTerm(self.pay_term_90_days_end_of_month_the_10, '2022-01-31', ['2022-06-10'])
self.assertPaymentTerm(self.pay_term_3_months_end_of_month_the_10, '2022-01-01', ['2022-05-10'])
self.assertPaymentTerm(self.pay_term_3_months_end_of_month_the_10, '2022-01-15', ['2022-05-10'])
self.assertPaymentTerm(self.pay_term_3_months_end_of_month_the_10, '2022-01-31', ['2022-05-10'])
self.assertPaymentTerm(self.pay_term_1_month_15_days_end_month_45_days, '2022-01-01', ['2022-04-14'])
self.assertPaymentTerm(self.pay_term_1_month_15_days_end_month_45_days, '2022-01-15', ['2022-05-15'])
self.assertPaymentTerm(self.pay_term_1_month_15_days_end_month_45_days, '2022-01-31', ['2022-05-15'])
self.assertPaymentTerm(self.pay_term_next_10_of_the_month, '2022-01-01', ['2022-01-10'])
self.assertPaymentTerm(self.pay_term_next_10_of_the_month, '2022-01-09', ['2022-01-10'])
self.assertPaymentTerm(self.pay_term_next_10_of_the_month, '2022-01-10', ['2022-01-10'])
self.assertPaymentTerm(self.pay_term_next_10_of_the_month, '2022-01-15', ['2022-02-10'])
self.assertPaymentTerm(self.pay_term_next_10_of_the_month, '2022-01-31', ['2022-02-10'])
def test_payment_term_compute_method(self):
def assert_payment_term_values(expected_values_list):
res = pay_term._compute_terms(
self.assertPaymentTerm(self.pay_term_60_days, '2022-01-01', ['2022-01-16', '2022-02-15'])
self.assertPaymentTerm(self.pay_term_60_days, '2022-01-15', ['2022-01-30', '2022-03-01'])
self.assertPaymentTerm(self.pay_term_60_days, '2022-01-31', ['2022-02-15', '2022-03-17'])
def test_wrong_payment_term(self):
with self.assertRaises(ValidationError):
self.env['account.payment.term'].create({
'name': 'Wrong Payment Term',
'line_ids': [
(0, 0, {
'value': 'percent',
'value_amount': 50,
}),
],
})
def test_payment_term_compute_method_with_cash_discount(self):
self.pay_term_a.early_pay_discount_computation = 'included'
computed_term_a = self.pay_term_a._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
150, 150, 1, 1000, 1000,
150.0, 150.0, 1.0, 1000.0, 1000.0,
)
self.assertEqual(len(res), len(expected_values_list))
for values, (company_amount, discount_balance) in zip(res, expected_values_list):
self.assertDictEqual(
{
'company_amount': values['company_amount'],
'discount_balance': values['discount_balance'],
},
{
self.assertDictEqual(
{
'total_amount': computed_term_a.get("total_amount"),
'discount_balance': computed_term_a.get("discount_balance"),
'line_ids': computed_term_a.get("line_ids"),
},
#What should be obtained
{
'total_amount': 1150.0,
'discount_balance': 1035.0,
'line_ids': [{
'date': datetime.date(2016, 1, 3),
'company_amount': 1150.0,
'foreign_amount': 1150.0,
}],
},
)
'company_amount': company_amount,
'discount_balance': discount_balance,
},
def test_payment_term_compute_method_with_cash_discount_and_cash_rounding(self):
foreign_currency = self.other_currency
rate = self.env['res.currency']._get_conversion_rate(foreign_currency, self.env.company.currency_id, self.env.company, '2017-01-01')
self.assertEqual(rate, 0.5)
self.pay_term_a.early_pay_discount_computation = 'included'
computed_term_a = self.pay_term_a._compute_terms(
fields.Date.from_string('2016-01-01'), foreign_currency, self.env.company,
75, 150, 1, 359.18, 718.35, cash_rounding=self.cash_rounding_a,
)
self.assertDictEqual(
{
'total_amount': computed_term_a.get("total_amount"),
'discount_balance': computed_term_a.get("discount_balance"),
'discount_amount_currency': computed_term_a.get("discount_amount_currency"),
'line_ids': computed_term_a.get("line_ids"),
},
# What should be obtained
{
'total_amount': 434.18,
'discount_balance': 390.78,
'discount_amount_currency': 781.55, # w/o cash rounding: 868.35 * 0.9 = 781.515
'line_ids': [{
'date': datetime.date(2016, 1, 3),
'company_amount': 434.18,
'foreign_amount': 868.35,
}],
},
)
def test_payment_term_compute_method_without_cash_discount(self):
computed_term_b = self.pay_term_b._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
150.0, 150.0, 1.0, 1000.0, 1000.0,
)
self.assertDictEqual(
{
'total_amount': computed_term_b.get("total_amount"),
'discount_balance': computed_term_b.get("discount_balance"),
'line_ids': computed_term_b.get("line_ids"),
},
# What should be obtained
{
'total_amount': 1150.0,
'discount_balance': 0,
'line_ids': [{
'date': datetime.date(2016, 1, 3),
'company_amount': 575.0,
'foreign_amount': 575.0,
}, {
'date': datetime.date(2016, 1, 5),
'company_amount': 575.0,
'foreign_amount': 575.0,
}],
},
)
def test_payment_term_compute_method_without_cash_discount_with_cash_rounding(self):
foreign_currency = self.other_currency
rate = self.env['res.currency']._get_conversion_rate(foreign_currency, self.env.company.currency_id, self.env.company, '2017-01-01')
self.assertEqual(rate, 0.5)
self.pay_term_a.early_pay_discount_computation = 'included'
computed_term_b = self.pay_term_b._compute_terms(
fields.Date.from_string('2016-01-01'), foreign_currency, self.env.company,
75, 150, 1, 359.18, 718.35, cash_rounding=self.cash_rounding_a,
)
self.assertDictEqual(
{
'total_amount': computed_term_b.get("total_amount"),
'discount_balance': computed_term_b.get("discount_balance"),
'discount_amount_currency': computed_term_b.get("discount_amount_currency"),
'line_ids': computed_term_b.get("line_ids"),
},
# What should be obtained
{
'total_amount': 434.18,
'discount_balance': 0,
'discount_amount_currency': None,
'line_ids': [{
'date': datetime.date(2016, 1, 3),
'company_amount': 217.1,
'foreign_amount': 434.2,
}, {
'date': datetime.date(2016, 1, 5),
'company_amount': 217.08,
'foreign_amount': 434.15000000000003,
}],
},
)
# Cash rounding should not affect the totals
self.assertAlmostEqual(434.18, sum(line['company_amount'] for line in computed_term_b['line_ids']))
self.assertAlmostEqual(868.35, sum(line['foreign_amount'] for line in computed_term_b['line_ids']))
def test_payment_term_compute_method_early_excluded(self):
self.pay_term_a.early_pay_discount_computation = 'excluded'
computed_term_a = self.pay_term_a._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
150.0, 150.0, 1.0, 1000.0, 1000.0,
)
self.assertDictEqual(
{
'total_amount': computed_term_a.get("total_amount"),
'discount_balance': computed_term_a.get("discount_balance"),
'line_ids': computed_term_a.get("line_ids"),
},
# What should be obtained
{
'total_amount': 1150.0,
'discount_balance': 1050.0,
'line_ids': [{
'date': datetime.date(2016, 1, 3),
'company_amount': 1150.0,
'foreign_amount': 1150.0,
}],
},
)
def test_payment_term_residual_amount_on_last_line_with_fixed_amount_multi_currency(self):
pay_term = self.env['account.payment.term'].create({
'name': "test_payment_term_residual_amount_on_last_line",
'line_ids': [
Command.create({
'value_amount': 50,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 50,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 0.02,
'value': 'fixed',
'nb_days': 0,
}),
],
})
computed_term = pay_term._compute_terms(
fields.Date.from_string('2016-01-01'), self.other_currency, self.env.company,
0.0, 0.0, 1.0, 0.04, 0.09,
)
self.assertEqual(
[
(
self.other_currency.round(l['foreign_amount']),
self.company_data['currency'].round(l['company_amount']),
)
for l in computed_term['line_ids']
],
[(0.045, 0.02), (0.045, 0.02), (0.0, 0.0)],
)
def test_payment_term_residual_amount_on_last_line(self):
pay_term = self.env['account.payment.term'].create({
'name': "turlututu",
'name': "test_payment_term_residual_amount_on_last_line",
'line_ids': [
Command.create({
'value_amount': 50,
'value': 'percent',
'value_amount': 10,
'days': 2,
'discount_percentage': 10,
'discount_days': 1,
'nb_days': 0,
}),
Command.create({
'value_amount': 50,
'value': 'percent',
'value_amount': 20,
'days': 4,
'discount_percentage': 20,
'discount_days': 3,
}),
Command.create({
'value': 'percent',
'value_amount': 20,
'days': 6,
}),
Command.create({
'value': 'balance',
'days': 8,
'discount_percentage': 20,
'discount_days': 7,
'nb_days': 0,
}),
],
})
self.env.company.early_pay_discount_computation = 'included'
assert_payment_term_values([
(115.0, 103.5),
(230.0, 184.0),
(230.0, 0.0),
(575.0, 460.0),
])
computed_term = pay_term._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
0.0, 0.0, 1.0, 0.03, 0.03,
)
self.assertEqual(
[self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']],
[0.02, 0.01],
)
self.env.company.early_pay_discount_computation = 'excluded'
assert_payment_term_values([
(115.0, 105.0),
(230.0, 190.0),
(230.0, 0.0),
(575.0, 475.0),
])
def test_payment_term_last_balance_line_with_fixed(self):
pay_term = self.env['account.payment.term'].create({
'name': 'test_payment_term_last_balance_line_with_fixed',
'line_ids': [
Command.create({
'value_amount': 70,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 200,
'value': 'fixed',
'nb_days': 0,
}),
Command.create({
'value_amount': 30,
'value': 'percent',
'nb_days': 0,
}),
]
})
def test_payment_term_compute_method_cash_rounding(self):
"""Test that the payment terms are computed correctly in case we apply cash rounding.
We check the amounts in document and company currency.
We check that the cash rounding does not change the totals in document or company curreny.
computed_term = pay_term._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
0.0, 0.0, 1.0, 1000.0, 1000.0,
)
self.assertEqual(
[self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']],
[700.0, 200.0, 100.0],
)
def test_payment_term_last_balance_line_with_fixed_negative(self):
pay_term = self.env['account.payment.term'].create({
'name': 'test_payment_term_last_balance_line_with_fixed_negative',
'line_ids': [
Command.create({
'value_amount': 70,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 500,
'value': 'fixed',
'nb_days': 0,
}),
Command.create({
'value_amount': 30,
'value': 'percent',
'nb_days': 0,
}),
]
})
computed_term = pay_term._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
0.0, 0.0, 1.0, 1000.0, 1000.0,
)
self.assertEqual(
[self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']],
[700.0, 500.0, -200.0],
)
def test_payment_term_last_balance_line_with_fixed_negative_fixed(self):
pay_term = self.env['account.payment.term'].create({
'name': 'test_payment_term_last_balance_line_with_fixed_negative_fixed',
'line_ids': [
Command.create({
'value_amount': 70,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 500,
'value': 'fixed',
'nb_days': 0,
}),
Command.create({
'value_amount': 30,
'value': 'percent',
'nb_days': 0,
}),
Command.create({
'value_amount': 200,
'value': 'fixed',
'nb_days': 0,
}),
]
})
computed_term = pay_term._compute_terms(
fields.Date.from_string('2016-01-01'), self.env.company.currency_id, self.env.company,
0.0, 0.0, 1.0, 1000.0, 1000.0,
)
self.assertEqual(
[self.env.company.currency_id.round(l['foreign_amount']) for l in computed_term['line_ids']],
[700.0, 500.0, 300.0, -500.0],
)
def test_payment_term_percent_round_calculation(self):
"""
def assert_payment_term_values(expected_values_list):
foreign_currency = self.currency_data['currency']
rate = self.env['res.currency']._get_conversion_rate(foreign_currency, self.env.company.currency_id, self.env.company, '2017-01-01')
self.assertEqual(rate, 0.5)
res = pay_term._compute_terms(
fields.Date.from_string('2017-01-01'), foreign_currency, self.env.company,
75, 150, 1, 359.18, 718.35, cash_rounding=self.cash_rounding_a
)
self.assertEqual(len(res), len(expected_values_list))
keys = ['company_amount', 'discount_balance', 'foreign_amount', 'discount_amount_currency']
for index, (values, expected_values) in enumerate(zip(res, expected_values_list)):
for key in keys:
with self.subTest(index=index, key=key):
self.assertAlmostEqual(values[key], expected_values[key])
total_company_amount = sum(value['company_amount'] for value in res)
total_foreign_amount = sum(value['foreign_amount'] for value in res)
self.assertAlmostEqual(total_company_amount, 434.18)
self.assertAlmostEqual(total_foreign_amount, 868.35)
pay_term = self.env['account.payment.term'].create({
'name': "turlututu",
the sum function might not sum the floating numbers properly
if there are a lot of lines with floating numbers
so this test verifies the round function changes
"""
self.env['account.payment.term'].create({
'name': "test_payment_term_percent_round_calculation",
'line_ids': [
Command.create({
'value': 'percent',
'value_amount': 10,
'days': 2,
'discount_percentage': 10,
'discount_days': 1,
}),
Command.create({
'value': 'percent',
'value_amount': 20,
'days': 4,
'discount_percentage': 20,
'discount_days': 3,
}),
Command.create({
'value': 'percent',
'value_amount': 20,
'days': 6,
}),
Command.create({
'value': 'balance',
'days': 8,
'discount_percentage': 20,
'discount_days': 7,
}),
Command.create({'value_amount': 50, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 1.66, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 16.8, 'value': 'percent', 'nb_days': 0, }),
],
})
with self.subTest(test='included'):
self.env.company.early_pay_discount_computation = 'included'
assert_payment_term_values([
{
'company_amount': 43.43,
'discount_balance': 39.11,
'foreign_amount': 86.85,
'discount_amount_currency': 78.20,
},
{
'company_amount': 86.86,
'discount_balance': 69.51,
'foreign_amount': 173.70,
'discount_amount_currency': 139.00,
},
{
'company_amount': 86.86,
'discount_balance': 0,
'foreign_amount': 173.70,
'discount_amount_currency': 0.00,
},
{
'company_amount': 217.03,
'discount_balance': 173.63,
'foreign_amount': 434.10,
'discount_amount_currency': 347.30,
},
])
def test_payment_term_days_end_of_month_on_the(self):
"""
This test will check that payment terms with a delay_type 'days_end_of_month_on_the' works as expected.
It will check if the date of the date maturity is correctly calculated depending on the invoice date and payment
term selected.
"""
with Form(self.invoice) as basic_case:
basic_case.invoice_payment_term_id = self.pay_term_days_end_of_month_10
basic_case.invoice_date = '2023-12-12'
with self.subTest(test='excluded'):
self.env.company.early_pay_discount_computation = 'excluded'
assert_payment_term_values([
{
'company_amount': 43.43,
'discount_balance': 39.86,
'foreign_amount': 86.85,
'discount_amount_currency': 79.70,
},
{
'company_amount': 86.86,
'discount_balance': 72.51,
'foreign_amount': 173.70,
'discount_amount_currency': 145.00,
},
{
'company_amount': 86.86,
'discount_balance': 0,
'foreign_amount': 173.70,
'discount_amount_currency': 0.00,
},
{
'company_amount': 217.03,
'discount_balance': 181.13,
'foreign_amount': 434.10,
'discount_amount_currency': 362.30,
},
])
expected_date_basic_case = self.invoice.line_ids.filtered(lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity'),
self.assertEqual(expected_date_basic_case[0], [fields.Date.from_string('2024-02-10')])
with Form(self.invoice) as special_case:
special_case.invoice_payment_term_id = self.pay_term_days_end_of_month_31
special_case.invoice_date = '2023-12-12'
expected_date_special_case = self.invoice.line_ids.filtered(lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity'),
self.assertEqual(expected_date_special_case[0], [fields.Date.from_string('2024-02-29')])
def test_payment_term_labels(self):
# create a payment term with 40% now, 30% in 30 days and 30% in 60 days
multiple_installment_term = self.env['account.payment.term'].create({
'name': "test_payment_term_labels",
'line_ids': [
Command.create({'value_amount': 40, 'value': 'percent', 'nb_days': 0, }),
Command.create({'value_amount': 30, 'value': 'percent', 'nb_days': 30, }),
Command.create({'value_amount': 30, 'value': 'percent', 'nb_days': 60, }),
],
})
# create immediate payment term
immediate_term = self.env['account.payment.term'].create({
'name': 'Immediate',
'line_ids': [
Command.create({'value_amount': 100, 'value': 'percent', 'nb_days': 0, }),
],
})
# create an invoice with immediate payment term
invoice = self.init_invoice('out_invoice', products=self.product_a)
invoice.invoice_payment_term_id = immediate_term
# check the payment term labels
invoice_terms = invoice.line_ids.filtered(lambda l: l.display_type == 'payment_term')
self.assertEqual(invoice_terms[0].name, False)
# change the payment term to the multiple installment term
invoice.invoice_payment_term_id = multiple_installment_term
invoice_terms = invoice.line_ids.filtered(lambda l: l.display_type == 'payment_term').sorted('date_maturity')
self.assertEqual(invoice_terms[0].name, 'installment #1')
self.assertEqual(invoice_terms[0].debit, invoice.amount_total * 0.4)
self.assertEqual(invoice_terms[1].name, 'installment #2')
self.assertEqual(invoice_terms[1].debit, invoice.amount_total * 0.3)
self.assertEqual(invoice_terms[2].name, 'installment #3')
self.assertEqual(invoice_terms[2].debit, invoice.amount_total * 0.3)
def test_payment_term_days_end_of_month_nb_days_0(self):
"""
This test will check that payment terms with a delay_type 'days_end_of_month_on_the'
in combination with nb_days works as expected
Invoice date = 2024-05-23
# case 1
'nb_days' = 0
`days_next_month` = 29
-> 2024-05-23 + 0 days = 2024-05-23
=> `date_maturity` -> 2024-06-29
# case 2
'nb_days' = 0
`days_next_month` = 31
-> 2024-05-23 + 0 days = 2024-05-23
=> `date_maturity` -> 2024-06-30
"""
self.pay_term_days_end_of_month_29.line_ids.nb_days = 0
self.pay_term_days_end_of_month_31.line_ids.nb_days = 0
with Form(self.invoice) as case_1:
case_1.invoice_payment_term_id = self.pay_term_days_end_of_month_29
case_1.invoice_date = '2024-05-23'
expected_date_case_1 = self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity')
self.assertEqual(expected_date_case_1, [fields.Date.from_string('2024-06-29')])
with Form(self.invoice) as case_2:
case_2.invoice_payment_term_id = self.pay_term_days_end_of_month_31
case_2.invoice_date = '2024-05-23'
expected_date_case_2 = self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity')
self.assertEqual(expected_date_case_2, [fields.Date.from_string('2024-06-30')])
def test_payment_term_days_end_of_month_nb_days_15(self):
"""
This test will check that payment terms with a delay_type 'days_end_of_month_on_the'
in combination with nb_days works as expected
Invoice date = 2024-05-23
# case 1
'nb_days' = 15
`days_next_month` = 30
-> 2024-05-23 + 15 days = 2024-06-07
=> `date_maturity` -> 2024-07-30
# case 2
'nb_days' = 15
`days_next_month` = 31
-> 2024-05-23 + 15 days = 2024-06-07
=> `date_maturity` -> 2024-07-31
"""
self.pay_term_days_end_of_month_30.line_ids.nb_days = 15
self.pay_term_days_end_of_month_31.line_ids.nb_days = 15
with Form(self.invoice) as case_1:
case_1.invoice_payment_term_id = self.pay_term_days_end_of_month_30
case_1.invoice_date = '2024-05-24'
expected_date_case_1 = self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity')
self.assertEqual(expected_date_case_1, [fields.Date.from_string('2024-07-30')])
with Form(self.invoice) as case_2:
case_2.invoice_payment_term_id = self.pay_term_days_end_of_month_31
case_2.invoice_date = '2024-05-23'
expected_date_case_2 = self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity')
self.assertEqual(expected_date_case_2, [fields.Date.from_string('2024-07-31')])
def test_payment_term_days_end_of_month_days_next_month_0(self):
with Form(self.invoice) as case_1:
case_1.invoice_payment_term_id = self.pay_term_days_end_of_month_days_next_month_0
case_1.invoice_date = '2024-04-22'
expected_date_case_1 = self.invoice.line_ids.filtered(
lambda l: l.account_id == self.company_data['default_account_receivable']).mapped('date_maturity')
self.assertEqual(expected_date_case_1, [fields.Date.from_string('2024-05-31')])
def test_payment_term_multi_company(self):
"""
@ -404,7 +667,8 @@ class TestAccountPaymentTerms(AccountTestInvoicingCommon):
OdooBot has `res.company(1)` set as the default company. The test checks that the payment term correctly reflects
the company associated with the move, independent of the user's default company.
"""
user_company, other_company = self.company_data_2.get('company'), self.company_data.get('company')
user_company = self.env['res.company'].create({'name': 'user_company'})
other_company = self.company_data.get('company')
self.env.user.write({
'company_ids': [user_company.id, other_company.id],
'company_id': user_company.id,