1113 lines
48 KiB
Python
1113 lines
48 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
|
||
|
from odoo.exceptions import ValidationError
|
||
|
from odoo.tests import tagged, Form
|
||
|
from odoo import fields, Command
|
||
|
|
||
|
|
||
|
@tagged('post_install', '-at_install')
|
||
|
class TestAccountEarlyPaymentDiscount(AccountTestInvoicingCommon):
|
||
|
|
||
|
@classmethod
|
||
|
def setUpClass(cls):
|
||
|
super().setUpClass()
|
||
|
cls.other_currency = cls.setup_other_currency('EUR')
|
||
|
# Payment Terms
|
||
|
cls.early_pay_10_percents_10_days = cls.env['account.payment.term'].create({
|
||
|
'name': '10% discount if paid within 10 days',
|
||
|
'company_id': cls.company_data['company'].id,
|
||
|
'early_discount': True,
|
||
|
'discount_percentage': 10,
|
||
|
'discount_days': 10,
|
||
|
'line_ids': [Command.create({
|
||
|
'value': 'percent',
|
||
|
'nb_days': 0,
|
||
|
'value_amount': 100,
|
||
|
})]
|
||
|
})
|
||
|
|
||
|
cls.pay_term_net_30_days = cls.env['account.payment.term'].create({
|
||
|
'name': 'Net 30 days',
|
||
|
'line_ids': [
|
||
|
(0, 0, {
|
||
|
'value_amount': 100,
|
||
|
'value': 'percent',
|
||
|
'nb_days': 30,
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
cls.pay_30_percents_now_balance_60_days = cls.env['account.payment.term'].create({
|
||
|
'name': '30% Now, Balance 60 Days',
|
||
|
'line_ids': [
|
||
|
Command.create({
|
||
|
'value_amount': 30,
|
||
|
'value': 'percent',
|
||
|
'nb_days': 0,
|
||
|
}),
|
||
|
Command.create({
|
||
|
'value_amount': 70,
|
||
|
'value': 'percent',
|
||
|
'nb_days': 60,
|
||
|
})
|
||
|
]
|
||
|
})
|
||
|
|
||
|
# ========================== Tests Payment Terms ==========================
|
||
|
def test_early_payment_end_date(self):
|
||
|
inv_1200_10_percents_discount_no_tax = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line', 'price_unit': 1200.0, 'tax_ids': []
|
||
|
})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
for line in inv_1200_10_percents_discount_no_tax.line_ids:
|
||
|
if line.display_type == 'payment_term':
|
||
|
self.assertEqual(
|
||
|
line.discount_date,
|
||
|
fields.Date.from_string('2019-01-11') or False
|
||
|
)
|
||
|
|
||
|
def test_invoice_report_without_invoice_date(self):
|
||
|
"""
|
||
|
Ensure that an invoice with an early discount payment term
|
||
|
and no invoice date can be previewed or printed.
|
||
|
"""
|
||
|
self.registry.enter_test_mode(self.cr)
|
||
|
self.addCleanup(self.registry.leave_test_mode)
|
||
|
out_invoice = self.env['account.move'].create([{
|
||
|
'move_type': 'out_invoice',
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line1',
|
||
|
})]
|
||
|
}])
|
||
|
|
||
|
# Assert that the invoice date is not set
|
||
|
self.assertEqual(out_invoice.invoice_date, False)
|
||
|
|
||
|
report = self.env['ir.actions.report'].with_context(force_report_rendering=True)._render_qweb_pdf('account.account_invoices', res_ids=out_invoice.id)
|
||
|
self.assertTrue(report)
|
||
|
|
||
|
#Test for invoices with multiple due dates and no early discount
|
||
|
out_invoice.invoice_payment_term_id = self.pay_30_percents_now_balance_60_days
|
||
|
new_report = self.env['ir.actions.report']._render_qweb_pdf('account.account_invoices', res_ids=out_invoice.id)
|
||
|
self.assertTrue(new_report)
|
||
|
|
||
|
# ========================== Tests Taxes Amounts =============================
|
||
|
def test_fixed_tax_amount_discounted_payment_mixed(self):
|
||
|
fixed_tax = self.env['account.tax'].create({
|
||
|
'name': 'Test 0.05',
|
||
|
'amount_type': 'fixed',
|
||
|
'amount': 0.05,
|
||
|
})
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'mixed'
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [Command.set(self.product_a.taxes_id.ids + fixed_tax.ids)], #15% tax + fixed 0.05
|
||
|
})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
self.assertInvoiceValues(invoice, [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'display_type': 'epd', 'balance': -100.0},
|
||
|
{'display_type': 'epd', 'balance': 100.0},
|
||
|
{'display_type': 'product', 'balance': -1000.0},
|
||
|
{'display_type': 'tax', 'balance': -135},
|
||
|
{'display_type': 'tax', 'balance': -0.05},
|
||
|
{'display_type': 'payment_term', 'balance': 1135.05},
|
||
|
], {
|
||
|
'amount_untaxed': 1000.0,
|
||
|
'amount_tax': 135.05,
|
||
|
'amount_total': 1135.05,
|
||
|
})
|
||
|
|
||
|
# ========================== Tests Payment Register ==========================
|
||
|
def test_register_discounted_payment_on_single_invoice(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
out_invoice_1.action_post()
|
||
|
active_ids = out_invoice_1.ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-02',
|
||
|
})._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertEqual(
|
||
|
payments.move_id.line_ids.sorted('balance').mapped('amount_currency'),
|
||
|
[-1000.0, 100.0, 900.0],
|
||
|
)
|
||
|
|
||
|
def test_register_discounted_payment_on_single_invoice_with_fixed_tax_1(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
fixed_tax = self.env['account.tax'].create({
|
||
|
'name': 'Test 0.05',
|
||
|
'amount_type': 'fixed',
|
||
|
'amount': 0.05,
|
||
|
'type_tax_use': 'purchase',
|
||
|
})
|
||
|
|
||
|
inv = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 1500.0,
|
||
|
'tax_ids': [Command.set(self.product_a.supplier_taxes_id.ids + fixed_tax.ids)]
|
||
|
})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
inv.action_post()
|
||
|
active_ids = inv.ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
})._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -1552.55, 'tax_tag_invert': False},
|
||
|
{'amount_currency': -150.0, 'tax_tag_invert': True},
|
||
|
{'amount_currency': -22.5, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 1725.05, 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_register_discounted_payment_on_single_invoice_with_fixed_tax_2(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
fixed_tax = self.env['account.tax'].create({
|
||
|
'name': 'Test 0.05',
|
||
|
'amount_type': 'fixed',
|
||
|
'amount': 0.05,
|
||
|
'type_tax_use': 'purchase',
|
||
|
})
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 50.0,
|
||
|
'tax_ids': [Command.set(self.product_a.supplier_taxes_id.ids + fixed_tax.ids)]
|
||
|
})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
invoice.action_post()
|
||
|
payments = self.env['account.payment.register']\
|
||
|
.with_context(active_model='account.move', active_ids=invoice.ids)\
|
||
|
.create({'payment_date': '2017-01-01'})\
|
||
|
._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -51.80, 'tax_tag_invert': False},
|
||
|
{'amount_currency': -5.00, 'tax_tag_invert': True},
|
||
|
{'amount_currency': -0.75, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 57.55, 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_register_discounted_payment_on_single_invoice_with_tax(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
inv_1500_10_percents_discount_tax_incl_15_percents_tax = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({'name': 'line', 'price_unit': 1500.0, 'tax_ids': [Command.set(self.product_a.supplier_taxes_id.ids)]})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
inv_1500_10_percents_discount_tax_incl_15_percents_tax.action_post()
|
||
|
active_ids = inv_1500_10_percents_discount_tax_incl_15_percents_tax.ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
})._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -1552.5, 'tax_tag_invert': False},
|
||
|
{'amount_currency': -150.0, 'tax_tag_invert': True},
|
||
|
{'amount_currency': -22.5, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 1725.0, 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_register_discounted_payment_on_single_out_invoice_with_tax(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
inv_1500_10_percents_discount_tax_incl_15_percents_tax = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [Command.create({'name': 'line', 'price_unit': 1500.0, 'tax_ids': [Command.set(self.product_a.taxes_id.ids)]})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
inv_1500_10_percents_discount_tax_incl_15_percents_tax.action_post()
|
||
|
active_ids = inv_1500_10_percents_discount_tax_incl_15_percents_tax.ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
})._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -1725.0, 'tax_tag_invert': False},
|
||
|
{'amount_currency': 22.5, 'tax_tag_invert': False},
|
||
|
{'amount_currency': 150.0, 'tax_tag_invert': False},
|
||
|
{'amount_currency': 1552.5, 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_register_discounted_payment_multi_line_discount(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
inv_mixed_lines_discount_and_no_discount = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({'name': 'line', 'price_unit': 1000.0, 'tax_ids': [Command.set(self.product_a.supplier_taxes_id.ids)]}),
|
||
|
Command.create({'name': 'line', 'price_unit': 2000.0, 'tax_ids': None})
|
||
|
],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
inv_mixed_lines_discount_and_no_discount.action_post()
|
||
|
active_ids = inv_mixed_lines_discount_and_no_discount.ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2017-01-01',
|
||
|
'group_payment': True
|
||
|
})._create_payments()
|
||
|
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -2835.0, 'tax_tag_invert': False},
|
||
|
{'amount_currency': -200.0, 'tax_tag_invert': False},
|
||
|
{'amount_currency': -100.0, 'tax_tag_invert': True},
|
||
|
{'amount_currency': -15.0, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 3150.0, 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_register_payment_batch_included(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'included'
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': True
|
||
|
})._create_payments()
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -3000.0},
|
||
|
{'amount_currency': 300.0},
|
||
|
{'amount_currency': 2700},
|
||
|
])
|
||
|
|
||
|
def test_register_payment_batch_excluded(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'excluded'
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': [Command.set(self.product_a.taxes_id.ids)]})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': True
|
||
|
})._create_payments()
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -3150.0},
|
||
|
{'amount_currency': 300.0},
|
||
|
{'amount_currency': 2850},
|
||
|
])
|
||
|
|
||
|
def test_register_payment_batch_mixed(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'mixed'
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': [Command.set(self.product_a.taxes_id.ids)]})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': True
|
||
|
})._create_payments()
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -3135.0},
|
||
|
{'amount_currency': 300.0},
|
||
|
{'amount_currency': 2835.0},
|
||
|
])
|
||
|
|
||
|
def test_register_payment_batch_mixed_one_too_late(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'mixed'
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2017-01-01',
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': [Command.set(self.product_a.taxes_id.ids)]})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': True
|
||
|
})._create_payments()
|
||
|
self.assertTrue(payments.is_reconciled)
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -3135.0},
|
||
|
{'amount_currency': 200.0},
|
||
|
{'amount_currency': 2935.0},
|
||
|
])
|
||
|
|
||
|
def test_mixed_epd_with_draft_invoice(self):
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'mixed'
|
||
|
tax = self.env['account.tax'].create({
|
||
|
'name': 'WonderTax',
|
||
|
'amount': 10,
|
||
|
})
|
||
|
with Form(self.env['account.move'].with_context(default_move_type='out_invoice')) as invoice:
|
||
|
invoice.partner_id = self.partner_a
|
||
|
invoice.invoice_date = fields.Date.from_string('2022-02-21')
|
||
|
invoice.invoice_payment_term_id = self.early_pay_10_percents_10_days
|
||
|
with invoice.invoice_line_ids.new() as line_form:
|
||
|
line_form.product_id = self.product_a
|
||
|
line_form.price_unit = 1000
|
||
|
line_form.quantity = 1
|
||
|
line_form.tax_ids.clear()
|
||
|
line_form.tax_ids.add(tax)
|
||
|
self._assert_tax_totals_summary(invoice.tax_totals, {
|
||
|
'same_tax_base': True,
|
||
|
'currency_id': self.env.company.currency_id.id,
|
||
|
'base_amount_currency': 1000.0,
|
||
|
'tax_amount_currency': 90.0,
|
||
|
'total_amount_currency': 1090.0,
|
||
|
'subtotals': [
|
||
|
{
|
||
|
'name': "Untaxed Amount",
|
||
|
'base_amount_currency': 1000.0,
|
||
|
'tax_amount_currency': 90.0,
|
||
|
'tax_groups': [
|
||
|
{
|
||
|
'id': tax.tax_group_id.id,
|
||
|
'base_amount_currency': 900.0,
|
||
|
'tax_amount_currency': 90.0,
|
||
|
'display_base_amount_currency': 900.0,
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
],
|
||
|
})
|
||
|
|
||
|
def test_intracomm_bill_with_early_payment_included(self):
|
||
|
tax_tags = self.env['account.account.tag'].create({
|
||
|
'name': f'tax_tag_{i}',
|
||
|
'applicability': 'taxes',
|
||
|
'country_id': self.env.company.account_fiscal_country_id.id,
|
||
|
} for i in range(6))
|
||
|
|
||
|
intracomm_tax = self.env['account.tax'].create({
|
||
|
'name': 'tax20',
|
||
|
'amount_type': 'percent',
|
||
|
'amount': 20,
|
||
|
'type_tax_use': 'purchase',
|
||
|
'invoice_repartition_line_ids': [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[0].ids)]}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[1].ids)]}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[2].ids)]}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
Command.create({'repartition_type': 'base', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[3].ids)]}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0, 'tag_ids': [Command.set(tax_tags[4].ids)]}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0, 'tag_ids': [Command.set(tax_tags[5].ids)]}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
early_payment_term = self.env['account.payment.term'].create({
|
||
|
'name': "early_payment_term",
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'early_pay_discount_computation': 'included',
|
||
|
'early_discount': True,
|
||
|
'discount_percentage': 2,
|
||
|
'discount_days': 7,
|
||
|
'line_ids': [
|
||
|
Command.create({
|
||
|
'value': 'percent',
|
||
|
'value_amount': 100.0,
|
||
|
'nb_days': 30,
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
bill = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_payment_term_id': early_payment_term.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [Command.set(intracomm_tax.ids)],
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
bill.action_post()
|
||
|
|
||
|
payment = self.env['account.payment.register']\
|
||
|
.with_context(active_model='account.move', active_ids=bill.ids)\
|
||
|
.create({'payment_date': '2019-01-01'})\
|
||
|
._create_payments()
|
||
|
|
||
|
self.assertRecordValues(payment.move_id.line_ids.sorted('balance'), [
|
||
|
# pylint: disable=bad-whitespace
|
||
|
{'amount_currency': -980.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False},
|
||
|
{'amount_currency': -20.0, 'tax_ids': intracomm_tax.ids, 'tax_tag_ids': tax_tags[3].ids, 'tax_tag_invert': True},
|
||
|
{'amount_currency': -4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[4].ids, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 4.0, 'tax_ids': [], 'tax_tag_ids': tax_tags[5].ids, 'tax_tag_invert': True},
|
||
|
{'amount_currency': 1000.0, 'tax_ids': [], 'tax_tag_ids': [], 'tax_tag_invert': False},
|
||
|
])
|
||
|
|
||
|
def test_mixed_early_discount_with_tag_on_tax_base_line(self):
|
||
|
"""
|
||
|
Ensure that early payment discount line grouping works properly when
|
||
|
using a tax that adds tax tags to its base line.
|
||
|
"""
|
||
|
tax_tag = self.env['account.account.tag'].create({
|
||
|
'name': 'tax_tag',
|
||
|
'applicability': 'taxes',
|
||
|
'country_id': self.env.company.account_fiscal_country_id.id,
|
||
|
})
|
||
|
|
||
|
tax_21 = self.env['account.tax'].create({
|
||
|
'name': "tax_21",
|
||
|
'amount': 21,
|
||
|
'invoice_repartition_line_ids': [
|
||
|
Command.create({
|
||
|
'factor_percent': 100,
|
||
|
'repartition_type': 'base',
|
||
|
'tag_ids': [Command.set(tax_tag.ids)],
|
||
|
}),
|
||
|
Command.create({
|
||
|
'factor_percent': 100, 'repartition_type': 'tax',
|
||
|
}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
Command.create({
|
||
|
'factor_percent': 100, 'repartition_type': 'base',
|
||
|
}),
|
||
|
Command.create({
|
||
|
'factor_percent': 100, 'repartition_type': 'tax',
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
|
||
|
self.early_pay_10_percents_10_days.early_pay_discount_computation = 'mixed'
|
||
|
bill = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
bill.write({
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': 'line1',
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [Command.set(tax_21.ids)],
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
bill.write({
|
||
|
'invoice_line_ids': [Command.create({
|
||
|
'name': 'line2',
|
||
|
'price_unit': 1000.0,
|
||
|
'tax_ids': [Command.set(tax_21.ids)],
|
||
|
})],
|
||
|
})
|
||
|
epd_lines = bill.line_ids.filtered(lambda line: line.display_type == 'epd')
|
||
|
self.assertRecordValues(epd_lines.sorted('balance'), [
|
||
|
{'balance': -200.0},
|
||
|
{'balance': 200.0},
|
||
|
])
|
||
|
|
||
|
def test_mixed_epd_with_tax_included(self):
|
||
|
early_pay_2_percents_10_days = self.env['account.payment.term'].create({
|
||
|
'name': '2% discount if paid within 10 days',
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'early_discount': True,
|
||
|
'discount_percentage': 2,
|
||
|
'discount_days': 10,
|
||
|
'early_pay_discount_computation': 'mixed',
|
||
|
'line_ids': [Command.create({
|
||
|
'value': 'percent',
|
||
|
'nb_days': 0,
|
||
|
'value_amount': 100,
|
||
|
})]
|
||
|
})
|
||
|
tax = self.env['account.tax'].create({
|
||
|
'name': 'Tax 21% included',
|
||
|
'amount': 21,
|
||
|
'price_include_override': 'tax_included',
|
||
|
})
|
||
|
|
||
|
with Form(self.env['account.move'].with_context(default_move_type='out_invoice')) as invoice:
|
||
|
invoice.partner_id = self.partner_a
|
||
|
invoice.invoice_date = fields.Date.from_string('2022-02-21')
|
||
|
invoice.invoice_payment_term_id = early_pay_2_percents_10_days
|
||
|
with invoice.invoice_line_ids.new() as line_form:
|
||
|
line_form.product_id = self.product_a
|
||
|
line_form.price_unit = 121
|
||
|
line_form.quantity = 1
|
||
|
line_form.tax_ids.clear()
|
||
|
line_form.tax_ids.add(tax)
|
||
|
self._assert_tax_totals_summary(invoice.tax_totals, {
|
||
|
'same_tax_base': True,
|
||
|
'currency_id': self.env.company.currency_id.id,
|
||
|
'base_amount_currency': 100.0,
|
||
|
'tax_amount_currency': 20.58,
|
||
|
'total_amount_currency': 120.58,
|
||
|
'subtotals': [
|
||
|
{
|
||
|
'name': "Untaxed Amount",
|
||
|
'base_amount_currency': 100.0,
|
||
|
'tax_amount_currency': 20.58,
|
||
|
'tax_groups': [
|
||
|
{
|
||
|
'id': tax.tax_group_id.id,
|
||
|
'base_amount_currency': 98.0,
|
||
|
'tax_amount_currency': 20.58,
|
||
|
'display_base_amount_currency': 98.0,
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
],
|
||
|
})
|
||
|
|
||
|
def test_mixed_epd_with_tax_no_duplication(self):
|
||
|
(self.pay_terms_a | self.early_pay_10_percents_10_days).write({'early_pay_discount_computation': 'mixed'})
|
||
|
inv = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({'name': 'line', 'price_unit': 100.0, 'tax_ids': [Command.set(self.product_a.taxes_id.ids)]}),
|
||
|
],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
self.assertEqual(len(inv.line_ids), 5) # 1 prod, 1 tax, 1 epd, 1 epd tax discount, 1 payment terms
|
||
|
inv.write({'invoice_payment_term_id': self.pay_terms_a.id})
|
||
|
self.assertEqual(len(inv.line_ids), 3) # 1 prod, 1 tax, 1 payment terms
|
||
|
inv.write({'invoice_payment_term_id': self.early_pay_10_percents_10_days.id})
|
||
|
self.assertEqual(len(inv.line_ids), 5)
|
||
|
|
||
|
def test_mixed_epd_with_tax_deleted_line(self):
|
||
|
self.early_pay_10_percents_10_days.write({'early_pay_discount_computation': 'mixed'})
|
||
|
tax_a = self.env['account.tax'].create({
|
||
|
'name': 'Test A',
|
||
|
'amount': 10,
|
||
|
})
|
||
|
tax_b = self.env['account.tax'].create({
|
||
|
'name': 'Test B',
|
||
|
'amount': 15,
|
||
|
})
|
||
|
|
||
|
inv = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({'name': 'line', 'price_unit': 100.0, 'tax_ids': [Command.set(tax_a.ids)]}),
|
||
|
Command.create({'name': 'line2', 'price_unit': 100.0, 'tax_ids': [Command.set(tax_b.ids)]}),
|
||
|
],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
self.assertEqual(len(inv.line_ids), 8) # 2 prod, 2 tax, 1 epd, 2 epd tax discount, 1 payment terms
|
||
|
inv.invoice_line_ids[1].unlink()
|
||
|
self.assertEqual(len(inv.line_ids), 5) # 1 prod, 1 tax, 1 epd, 1 epd tax discount, 1 payment terms
|
||
|
self.assertEqual(inv.amount_tax, 9.00) # $100.0 @ 10% tax (-10% epd)
|
||
|
|
||
|
def test_mixed_epd_with_rounding_issue(self):
|
||
|
"""
|
||
|
Ensure epd line will not unbalance the invoice
|
||
|
"""
|
||
|
tax_6 = self.env['account.tax'].create({
|
||
|
'name': '6%',
|
||
|
'amount': 6,
|
||
|
})
|
||
|
tax_12 = self.env['account.tax'].create({
|
||
|
'name': '12%',
|
||
|
'amount': 12,
|
||
|
})
|
||
|
tax_136 = self.env['account.tax'].create({
|
||
|
'name': '136',
|
||
|
'amount': 0.136,
|
||
|
'amount_type': 'fixed',
|
||
|
'include_base_amount': True,
|
||
|
})
|
||
|
tax_176 = self.env['account.tax'].create({
|
||
|
'name': '176',
|
||
|
'amount': 0.176,
|
||
|
'amount_type': 'fixed',
|
||
|
'include_base_amount': True,
|
||
|
})
|
||
|
|
||
|
early_pay_1_percents_7_days = self.env['account.payment.term'].create({
|
||
|
'name': '1% discount if paid within 7 days',
|
||
|
'company_id': self.company_data['company'].id,
|
||
|
'early_pay_discount_computation': 'mixed',
|
||
|
'discount_percentage': 1,
|
||
|
'discount_days': 7,
|
||
|
'early_discount': True,
|
||
|
'line_ids': [Command.create({
|
||
|
'value': 'percent',
|
||
|
'nb_days': 0,
|
||
|
'value_amount': 100,
|
||
|
})]
|
||
|
})
|
||
|
|
||
|
# The following vals will create a rounding issue
|
||
|
line_create_vals = [
|
||
|
(116, 6, tax_6),
|
||
|
(0.91, 350, tax_6),
|
||
|
(194.21, 1, tax_136 | tax_12),
|
||
|
(31.46, 5, tax_176 | tax_12)
|
||
|
]
|
||
|
|
||
|
# If invoice is not balanced the following create will fail
|
||
|
self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2022-02-21',
|
||
|
'invoice_payment_term_id': early_pay_1_percents_7_days.id,
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'price_unit': price_unit,
|
||
|
'quantity': quantity,
|
||
|
'tax_ids': [Command.set(taxes.ids)]
|
||
|
}) for price_unit, quantity, taxes in line_create_vals
|
||
|
]
|
||
|
})
|
||
|
|
||
|
def test_register_payment_batch_with_discount_and_without_discount(self):
|
||
|
"""
|
||
|
Test that a batch payment, that is
|
||
|
- not grouped
|
||
|
- with invoices having different payment terms (1 with discount, 1 without)
|
||
|
-> will not crash
|
||
|
"""
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.pay_term_net_30_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': False
|
||
|
})._create_payments()
|
||
|
self.assertTrue(all(payments.mapped('is_reconciled')))
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -2000.0},
|
||
|
{'amount_currency': -1000.0},
|
||
|
{'amount_currency': 200.0},
|
||
|
{'amount_currency': 1000},
|
||
|
{'amount_currency': 1800},
|
||
|
])
|
||
|
|
||
|
def test_register_payment_batch_without_discount(self):
|
||
|
"""
|
||
|
Test that a batch payment, that is
|
||
|
- not grouped
|
||
|
- with invoices having the same payment terms (without discount)
|
||
|
-> will not crash
|
||
|
"""
|
||
|
out_invoice_1 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.pay_term_net_30_days.id,
|
||
|
})
|
||
|
out_invoice_2 = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'date': '2019-01-01',
|
||
|
'invoice_date': '2019-01-01',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'currency_id': self.other_currency.id,
|
||
|
'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})],
|
||
|
'invoice_payment_term_id': self.pay_term_net_30_days.id,
|
||
|
})
|
||
|
(out_invoice_1 + out_invoice_2).action_post()
|
||
|
active_ids = (out_invoice_1 + out_invoice_2).ids
|
||
|
|
||
|
payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
|
||
|
'payment_date': '2019-01-01', 'group_payment': False
|
||
|
})._create_payments()
|
||
|
self.assertTrue(all(payments.mapped('is_reconciled')))
|
||
|
self.assertRecordValues(payments.move_id.line_ids.sorted('balance'), [
|
||
|
{'amount_currency': -2000.0},
|
||
|
{'amount_currency': -1000.0},
|
||
|
{'amount_currency': 1000.0},
|
||
|
{'amount_currency': 2000},
|
||
|
])
|
||
|
|
||
|
def test_mixed_epd_with_tax_refund(self):
|
||
|
"""
|
||
|
Ensure epd line are addeed to refunds
|
||
|
"""
|
||
|
self.early_pay_10_percents_10_days.write({'early_pay_discount_computation': 'mixed'})
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2022-02-21',
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'price_unit': 100.0,
|
||
|
'quantity': 1,
|
||
|
'tax_ids': [Command.set(self.product_a.taxes_id.ids)],
|
||
|
})
|
||
|
]
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice.ids).create({
|
||
|
'date': fields.Date.from_string('2017-01-01'),
|
||
|
'reason': 'no reason again',
|
||
|
'journal_id': invoice.journal_id.id,
|
||
|
})
|
||
|
|
||
|
receivable_line = invoice.line_ids.filtered(lambda x: x.account_id.account_type == 'asset_receivable')
|
||
|
reversal = move_reversal.modify_moves()
|
||
|
reverse_move = self.env['account.move'].browse(reversal['res_id'])
|
||
|
|
||
|
self.assertEqual(invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.")
|
||
|
|
||
|
self.assertRecordValues(reverse_move.line_ids.sorted('id'), [
|
||
|
{
|
||
|
'balance': -100.0,
|
||
|
'tax_base_amount': 0.0,
|
||
|
'display_type': 'product',
|
||
|
},
|
||
|
{
|
||
|
'balance': 10.0,
|
||
|
'tax_base_amount': 0.0,
|
||
|
'display_type': 'epd',
|
||
|
},
|
||
|
{
|
||
|
'balance': -10.0,
|
||
|
'tax_base_amount': 0.0,
|
||
|
'display_type': 'epd',
|
||
|
},
|
||
|
{
|
||
|
'balance': -13.5,
|
||
|
'tax_base_amount': 90.0,
|
||
|
'display_type': 'tax',
|
||
|
},
|
||
|
{
|
||
|
'balance': receivable_line.balance,
|
||
|
'tax_base_amount': 0.0,
|
||
|
'display_type': 'payment_term',
|
||
|
},
|
||
|
])
|
||
|
|
||
|
def test_epd_validation_on_payment_terms(self):
|
||
|
"""
|
||
|
Test that enabling Early Payment Discount (EPD) on payment terms with multiple lines raises a ValidationError,
|
||
|
and that enabling EPD on payment terms with a single line does not raise any error.
|
||
|
"""
|
||
|
payment_term = self.env['account.payment.term'].create({
|
||
|
'name': 'Test Term',
|
||
|
'line_ids': [
|
||
|
Command.create({'value': 'percent', 'value_amount': 50, 'nb_days': 30}),
|
||
|
Command.create({'value': 'percent', 'value_amount': 50, 'nb_days': 60}),
|
||
|
]
|
||
|
})
|
||
|
|
||
|
with self.assertRaisesRegex(
|
||
|
ValidationError,
|
||
|
"The Early Payment Discount functionality can only be used with payment terms using a single 100% line.",
|
||
|
msg="EPD should not be allowed with multiple term lines",
|
||
|
):
|
||
|
payment_term.early_discount = True
|
||
|
|
||
|
# Modify the payment term to have a single line
|
||
|
payment_term.line_ids = [
|
||
|
Command.clear(),
|
||
|
Command.create({"value": "percent", "value_amount": 100, "nb_days": 30}),
|
||
|
]
|
||
|
|
||
|
try:
|
||
|
payment_term.early_discount = True
|
||
|
except ValidationError:
|
||
|
self.fail(
|
||
|
"ValidationError raised unexpectedly for single-line payment term with EPD"
|
||
|
)
|
||
|
|
||
|
def test_epd_entry_tag_invert_with_distinct_negative_invoice_line(self):
|
||
|
"""
|
||
|
`tax_tag_invert` should be the same for all Early Payment Discount lines of a single entry
|
||
|
"""
|
||
|
|
||
|
analytic_plan = self.env['account.analytic.plan'].create({
|
||
|
'name': 'existential plan',
|
||
|
})
|
||
|
analytic_account_a = self.env['account.analytic.account'].create({
|
||
|
'name': 'positive_account',
|
||
|
'plan_id': analytic_plan.id,
|
||
|
})
|
||
|
analytic_account_b = self.env['account.analytic.account'].create({
|
||
|
'name': 'negative_account',
|
||
|
'plan_id': analytic_plan.id,
|
||
|
})
|
||
|
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_date': '2019-01-10',
|
||
|
'date': '2019-01-10',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 2000,
|
||
|
'tax_ids': self.tax_sale_a,
|
||
|
'analytic_distribution': {str(analytic_account_a.id): 100},
|
||
|
}),
|
||
|
Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': -1500,
|
||
|
'tax_ids': self.tax_sale_a,
|
||
|
'analytic_distribution': {str(analytic_account_b.id): 100},
|
||
|
}),
|
||
|
],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
bill = self.env['account.move'].create({
|
||
|
'move_type': 'in_invoice',
|
||
|
'partner_id': self.partner_b.id,
|
||
|
'invoice_date': '2019-01-10',
|
||
|
'date': '2019-01-10',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': 3000,
|
||
|
'tax_ids': self.tax_purchase_a,
|
||
|
'analytic_distribution': {str(analytic_account_a.id): 100},
|
||
|
}),
|
||
|
Command.create({
|
||
|
'name': 'line',
|
||
|
'price_unit': -2250,
|
||
|
'tax_ids': self.tax_purchase_a,
|
||
|
'analytic_distribution': {str(analytic_account_b.id): 100},
|
||
|
}),
|
||
|
],
|
||
|
'invoice_payment_term_id': self.early_pay_10_percents_10_days.id,
|
||
|
})
|
||
|
bill.action_post()
|
||
|
|
||
|
payments = self.env['account.payment.register'].with_context(
|
||
|
active_model='account.move',
|
||
|
active_ids=invoice.ids,
|
||
|
).create({
|
||
|
'payment_date': '2019-01-01',
|
||
|
})._create_payments()
|
||
|
payment_moves = payments.move_id
|
||
|
|
||
|
for line in payment_moves.line_ids.filtered(lambda line: line.tax_repartition_line_id or line.tax_ids):
|
||
|
self.assertFalse(line.tax_tag_invert)
|
||
|
|
||
|
payments = self.env['account.payment.register'].with_context(
|
||
|
active_model='account.move',
|
||
|
active_ids=bill.ids,
|
||
|
).create({
|
||
|
'payment_date': '2019-01-01',
|
||
|
})._create_payments()
|
||
|
payment_moves = payments.move_id
|
||
|
|
||
|
for line in payment_moves.line_ids.filtered(lambda line: line.tax_repartition_line_id or line.tax_ids):
|
||
|
self.assertTrue(line.tax_tag_invert)
|
||
|
|
||
|
def test_epd_multiple_repartition_lines(self):
|
||
|
"""
|
||
|
In the case of multi repartition lines tax definition with an early payment discount
|
||
|
We want to make sure that the EPD lines are correct.
|
||
|
We want the rounding difference to be added to the "biggest" base line.
|
||
|
"""
|
||
|
# Taxes.
|
||
|
common_values = {
|
||
|
'amount': 17.0,
|
||
|
'invoice_repartition_line_ids': [
|
||
|
Command.create({'repartition_type': 'base'}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0}),
|
||
|
],
|
||
|
'refund_repartition_line_ids': [
|
||
|
Command.create({'repartition_type': 'base'}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': 100.0}),
|
||
|
Command.create({'repartition_type': 'tax', 'factor_percent': -100.0}),
|
||
|
],
|
||
|
}
|
||
|
|
||
|
tax1, tax2 = self.env['account.tax'].create([
|
||
|
{'name': "tax1", **common_values},
|
||
|
{'name': "tax2", **common_values},
|
||
|
])
|
||
|
|
||
|
# Early payment.
|
||
|
payment_term = self.env['account.payment.term'].create({
|
||
|
'name': "10% discount if paid within 10 days",
|
||
|
'early_discount': True,
|
||
|
'early_pay_discount_computation': 'included',
|
||
|
'discount_percentage': 2,
|
||
|
'discount_days': 10,
|
||
|
'line_ids': [Command.create({
|
||
|
'value': 'percent',
|
||
|
'nb_days': 0,
|
||
|
'value_amount': 100,
|
||
|
})]
|
||
|
})
|
||
|
|
||
|
# Invoice.
|
||
|
invoice = self.env['account.move'].create({
|
||
|
'move_type': 'out_invoice',
|
||
|
'partner_id': self.partner_a.id,
|
||
|
'invoice_payment_term_id': payment_term.id,
|
||
|
'invoice_date': '2017-01-01',
|
||
|
'invoice_line_ids': [
|
||
|
Command.create({
|
||
|
'name': "Line One",
|
||
|
'price_unit': 739.95,
|
||
|
'tax_ids': [Command.set(tax1.ids)],
|
||
|
}),
|
||
|
Command.create({
|
||
|
'name': "Line Two",
|
||
|
'price_unit': 37.80,
|
||
|
'tax_ids': [Command.set(tax2.ids)],
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
invoice.action_post()
|
||
|
|
||
|
# Payment.
|
||
|
payment = self.env['account.payment.register']\
|
||
|
.with_context(active_model='account.move', active_ids=invoice.ids)\
|
||
|
.create({'payment_date': '2017-01-01'})\
|
||
|
._create_payments()
|
||
|
|
||
|
self.assertRecordValues(payment.move_id.line_ids.sorted('amount_currency'), [
|
||
|
# Invoice's total:
|
||
|
{'amount_currency': -777.75},
|
||
|
# Base / tax lines:
|
||
|
{'amount_currency': -2.51},
|
||
|
{'amount_currency': -0.13},
|
||
|
{'amount_currency': 0.13},
|
||
|
{'amount_currency': 0.76},
|
||
|
{'amount_currency': 2.51},
|
||
|
{'amount_currency': 14.79},
|
||
|
# Discounted amount:
|
||
|
{'amount_currency': 762.2},
|
||
|
])
|