231 lines
11 KiB
Python
231 lines
11 KiB
Python
from .common import TestAccountReportsCommon
|
|
|
|
from odoo import Command, fields
|
|
from freezegun import freeze_time
|
|
from odoo.tools import format_date
|
|
from odoo.tests import tagged
|
|
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestFollowupReport(TestAccountReportsCommon):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
|
|
cls.report = cls.env.ref('account_reports.followup_report')
|
|
# Initiate Invoices
|
|
with freeze_time('2025-10-08'):
|
|
cls.today = fields.Date.today()
|
|
invoices_data = [
|
|
# Partner A invoices
|
|
{'partner': cls.partner_a, 'amount': 100.0, 'due_date': '2025-01-01'},
|
|
{'partner': cls.partner_a, 'amount': 100.0, 'due_date': cls.today},
|
|
{'partner': cls.partner_a, 'amount': 100.0, 'due_date': '2025-01-01', 'move_type': 'out_refund'},
|
|
# Partner B invoices
|
|
{'partner': cls.partner_b, 'amount': 100.0, 'due_date': '2025-01-01'},
|
|
{'partner': cls.partner_b, 'amount': 100.0, 'due_date': cls.today},
|
|
{'partner': cls.partner_b, 'amount': 400.0, 'due_date': '2025-01-01', 'move_type': 'out_refund'},
|
|
]
|
|
for invoice_data in invoices_data:
|
|
cls.init_invoice(
|
|
move_type=invoice_data.get('move_type', 'out_invoice'),
|
|
partner=invoice_data['partner'],
|
|
amounts=[invoice_data['amount']],
|
|
invoice_date_due=invoice_data['due_date'],
|
|
invoice_date=invoice_data.get('invoice_date', '2025-01-01'),
|
|
)
|
|
cls.formatted_today = format_date(cls.env, cls.today, date_format='MM/dd/YYY')
|
|
|
|
@classmethod
|
|
def init_invoice(cls, move_type, partner=None, invoice_date=None, post=False, products=None, amounts=None, taxes=None, company=False, currency=None, journal=None, invoice_date_due=None):
|
|
move = super().init_invoice(move_type, partner, invoice_date, False, products, amounts, taxes, company, currency, journal)
|
|
if invoice_date_due:
|
|
move.invoice_payment_term_id = False
|
|
move.invoice_date_due = invoice_date_due
|
|
move.action_post()
|
|
return move
|
|
|
|
@freeze_time('2025-10-08')
|
|
def test_followup_report_unfold(self):
|
|
''' Test unfolding a line when rendering the whole report, having overdue and due sections '''
|
|
options = self._generate_options(self.report, fields.Date.from_string('2025-01-01'), fields.Date.from_string('2025-01-31'))
|
|
self.assertLinesValues(
|
|
self.report._get_lines(options),
|
|
# Name Amount Balance
|
|
[ 0, 3, 5],
|
|
[
|
|
('partner_a', 100.0, 100.0),
|
|
('partner_b', -200.0, -200.0),
|
|
('Total', -100.0, -100.0),
|
|
],
|
|
options
|
|
)
|
|
|
|
options['unfolded_lines'] = [self.report._get_generic_line_id('res.partner', self.partner_a.id)]
|
|
self.assertLinesValues(
|
|
self.report._get_lines(options),
|
|
# Name Due Date Amount Balance
|
|
[ 0, 2, 3, 5],
|
|
[
|
|
('partner_a', '', 100.0, 100.0),
|
|
('Overdue', '', '', ''),
|
|
('INV/2025/00001', '01/01/2025', 100.0, 100.0),
|
|
('RINV/2025/00001', '01/01/2025', -100.0, 0.0),
|
|
('Due', '', '', ''),
|
|
('INV/2025/00002', self.formatted_today, 100.0, 100.0),
|
|
('Total partner_a', '', 100.0, 100.0),
|
|
('partner_b', '', -200.0, -200.0),
|
|
('Total', '', -100.0, -100.0),
|
|
],
|
|
options
|
|
)
|
|
|
|
@freeze_time('2025-10-08')
|
|
def test_followup_report_load_more(self):
|
|
''' Test loading more lines when reaching the limit '''
|
|
self.report.load_more_limit = 2
|
|
|
|
invoices_data = [
|
|
{'amount': 100.0, 'due_date': '2024-12-03'},
|
|
{'amount': 100.0, 'due_date': self.today}
|
|
]
|
|
|
|
for invoice_data in invoices_data:
|
|
self.init_invoice(
|
|
move_type='out_invoice',
|
|
partner=self.partner_a,
|
|
amounts=[invoice_data['amount']],
|
|
invoice_date_due=invoice_data['due_date'],
|
|
invoice_date='2025-01-01',
|
|
)
|
|
|
|
options = self._generate_options(self.report, fields.Date.from_string('2025-01-01'), fields.Date.from_string('2025-01-31'))
|
|
options['unfolded_lines'] = [self.report._get_generic_line_id('res.partner', self.partner_a.id)]
|
|
|
|
report_lines = self.report._get_lines(options)
|
|
|
|
self.assertLinesValues(
|
|
report_lines,
|
|
# Name Due Date Amount Balance
|
|
[ 0, 2, 3, 5],
|
|
[
|
|
('partner_a', '', 300.0, 300.0),
|
|
('Overdue', '', '', ''),
|
|
('INV/2025/00005', '12/03/2024', 100.0, 100.0),
|
|
('INV/2025/00001', '01/01/2025', 100.0, 200.0),
|
|
('Load more...', '', '', ''),
|
|
('Total partner_a', '', 300.0, 300.0),
|
|
('partner_b', '', -200.0, -200.0),
|
|
('Total', '', 100.0, 100.0),
|
|
],
|
|
options
|
|
)
|
|
|
|
options['unfolded_lines'] = [line['id'] for line in report_lines if line.get('unfolded')]
|
|
|
|
load_more_1 = self.report.get_expanded_lines(
|
|
options,
|
|
report_lines[0]['id'],
|
|
report_lines[4]['groupby'],
|
|
'_report_expand_unfoldable_line_partner_ledger',
|
|
report_lines[4]['progress'],
|
|
report_lines[4]['offset'],
|
|
None,
|
|
)
|
|
|
|
self.assertLinesValues(
|
|
load_more_1,
|
|
# Name Due Date Amount Balance
|
|
[ 0, 2, 3, 5],
|
|
[
|
|
('RINV/2025/00001', '01/01/2025', -100.0, 100.0),
|
|
('Due', '', '', ''),
|
|
('INV/2025/00002', self.formatted_today, 100.0, 200.0),
|
|
('Load more...', '', '', ''),
|
|
],
|
|
options
|
|
)
|
|
|
|
options['unfolded_lines'] = options['unfolded_lines'] + [line['id'] for line in load_more_1 if line.get('unfolded')]
|
|
|
|
load_more_2 = self.report.get_expanded_lines(
|
|
options,
|
|
report_lines[0]['id'],
|
|
load_more_1[3]['groupby'],
|
|
'_report_expand_unfoldable_line_partner_ledger',
|
|
load_more_1[3]['progress'],
|
|
load_more_1[3]['offset'],
|
|
None,
|
|
)
|
|
|
|
self.assertLinesValues(
|
|
load_more_2,
|
|
# Name Due Date Amount Balance
|
|
[ 0, 2, 3, 5],
|
|
[
|
|
('INV/2025/00006', self.formatted_today, 100.0, 300.0),
|
|
],
|
|
options
|
|
)
|
|
|
|
@freeze_time('2025-12-01')
|
|
def test_followup_report_single_foreign_currency(self):
|
|
"""
|
|
Test that the followup report displays the total amount in currency
|
|
when all invoices from a partner share the same foreign currency.
|
|
"""
|
|
partner_c = self.env['res.partner'].create({
|
|
'name': 'partner_c',
|
|
})
|
|
|
|
options = self._generate_options(self.report, None, '2026-12-31')
|
|
options['ignore_totals_below_sections'] = True
|
|
|
|
invoice_vals = {
|
|
'move_type': 'out_invoice',
|
|
'invoice_date': '2026-01-01',
|
|
'partner_id': partner_c.id,
|
|
'invoice_line_ids': [Command.create({
|
|
'quantity': 1,
|
|
'price_unit': 200,
|
|
'tax_ids': [],
|
|
})]
|
|
}
|
|
|
|
# Two unpaid invoices in foreign currency.
|
|
self.env['account.move'].create({**invoice_vals, 'currency_id': self.other_currency.id}).action_post()
|
|
self.env['account.move'].create({**invoice_vals, 'currency_id': self.other_currency.id}).action_post()
|
|
|
|
# The amount currency total should be displayed.
|
|
self.assertLinesValues(
|
|
self.report._get_lines(options),
|
|
# Name Amount Amount Currency
|
|
[ 0, 3, 4],
|
|
[
|
|
('partner_a', 100.0, ''),
|
|
('partner_b', -200.0, ''),
|
|
('partner_c', 200.0, 400.0),
|
|
('Total', 100.0, ''),
|
|
],
|
|
options,
|
|
currency_map={4: {'currency': self.other_currency}},
|
|
)
|
|
|
|
# Third unpaid invoice using the company currency.
|
|
self.env['account.move'].create({**invoice_vals, 'invoice_date': '2025-12-31'}).action_post()
|
|
|
|
# The amount currency total should no longer be displayed.
|
|
self.assertLinesValues(
|
|
self.report._get_lines(options),
|
|
# Name Amount Amount Currency
|
|
[ 0, 3, 4],
|
|
[
|
|
('partner_a', 100.0, ''),
|
|
('partner_b', -200.0, ''),
|
|
('partner_c', 400.0, ''),
|
|
('Total', 300.0, ''),
|
|
],
|
|
options,
|
|
)
|