File: test_account_payment_duplicate.py

package info (click to toggle)
odoo 18.0.0%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 878,716 kB
  • sloc: javascript: 927,937; python: 685,670; xml: 388,524; sh: 1,033; sql: 415; makefile: 26
file content (168 lines) | stat: -rw-r--r-- 8,732 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests import tagged


@tagged('post_install', '-at_install')
class TestAccountPaymentDuplicateMoves(AccountTestInvoicingCommon):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()

        cls.company = cls.company_data['company']
        cls.receivable = cls.company_data['default_account_receivable']
        cls.payable = cls.company_data['default_account_payable']
        cls.bank_journal = cls.company_data['default_journal_bank']
        cls.comp_curr = cls.company_data['currency']

        cls.payment_in = cls.env['account.payment'].create({
            'amount': 50.0,
            'payment_type': 'inbound',
            'partner_id': cls.partner_a.id,
            'destination_account_id': cls.receivable.id,
        })
        cls.payment_out = cls.env['account.payment'].create({
            'amount': 50.0,
            'payment_type': 'outbound',
            'partner_id': cls.partner_a.id,
            'destination_account_id': cls.payable.id,
        })

        cls.out_invoice_1 = cls.env['account.move'].create({
            'move_type': 'out_invoice',
            'date': '2017-01-01',
            'invoice_date': '2017-01-01',
            'partner_id': cls.partner_a.id,
            'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id, 'price_unit': 50.0, 'tax_ids': []})],
        })
        cls.in_invoice_1 = cls.env['account.move'].create({
            'move_type': 'in_invoice',
            'date': '2017-01-01',
            'invoice_date': '2017-01-01',
            'partner_id': cls.partner_a.id,
            'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id, 'price_unit': 50.0, 'tax_ids': []})],
        })
        cls.out_invoice_2 = cls.env['account.move'].create({
            'move_type': 'out_invoice',
            'date': '2017-01-01',
            'invoice_date': '2017-01-01',
            'partner_id': cls.partner_a.id,
            'invoice_line_ids': [(0, 0, {'product_id': cls.product_a.id, 'price_unit': 20.0, 'tax_ids': []})],
        })
        (cls.out_invoice_1 + cls.out_invoice_2 + cls.in_invoice_1).action_post()

    def test_duplicate_payments(self):
        """ Ensure duplicated payments are computed correctly for both inbound and outbound payments.
        For it to be a duplicate, the partner, the date and the amount must be the same.
        """
        payment_in_1 = self.payment_in
        payment_out_1 = self.payment_out

        # Different type but same partner, amount and date, no duplicate
        self.assertRecordValues(payment_in_1, [{'duplicate_payment_ids': []}])

        # Create duplicate payments
        payment_in_2 = payment_in_1.copy(default={'date': payment_in_1.date})
        payment_out_2 = payment_out_1.copy(default={'date': payment_out_1.date})
        # Inbound payment finds duplicate inbound payment, not the outbound payment with same information
        self.assertRecordValues(payment_in_2, [{
            'duplicate_payment_ids': [payment_in_1.id],
        }])
        # Outbound payment finds duplicate outbound duplicate, not the inbound payment with same information
        self.assertRecordValues(payment_out_2, [{
            'duplicate_payment_ids': [payment_out_1.id],
        }])
        # Different date but same amount and same partner, no duplicate
        payment_out_3 = payment_out_1.copy(default={'date': '2023-12-31'})
        self.assertRecordValues(payment_out_3, [{'duplicate_payment_ids': []}])

        # Different amount but same partner and same date, no duplicate
        payment_out_4 = self.env['account.payment'].create({
            'amount': 60.0,
            'payment_type': 'outbound',
            'partner_id': self.partner_a.id,
            'destination_account_id': self.payable.id,
        })
        self.assertRecordValues(payment_out_4, [{'duplicate_payment_ids': []}])

        # Different partner but same amount and same date, no duplicate
        payment_out_5 = self.env['account.payment'].create({
            'amount': 50.0,
            'payment_type': 'outbound',
            'partner_id': self.partner_b.id,
            'destination_account_id': self.payable.id,
        })
        self.assertRecordValues(payment_out_5, [{'duplicate_payment_ids': []}])

    def test_in_payment_multiple_duplicate_inbound_batch(self):
        """ Ensure duplicated payments are computed correctly when updated in batch,
        where payments are all of a single payment type
        """
        payment_1 = self.payment_in
        payment_2 = payment_1.copy(default={'date': payment_1.date})
        payment_3 = payment_1.copy(default={'date': payment_1.date})

        payments = payment_1 + payment_2 + payment_3

        self.assertRecordValues(payments, [
            {'duplicate_payment_ids': (payment_2 + payment_3).ids},
            {'duplicate_payment_ids': (payment_1 + payment_3).ids},
            {'duplicate_payment_ids': (payment_1 + payment_2).ids},
        ])

    def test_in_payment_multiple_duplicate_multiple_journals(self):
        """ Ensure duplicated payments are computed correctly when updated in batch,
        with inbound and outbound payments with different journals
        """
        payment_in_1 = self.payment_in
        payment_out_1 = self.payment_out
        # Create a different journals with a different outstanding account
        bank_journal_B = self.bank_journal.copy()
        bank_journal_B.inbound_payment_method_line_ids.payment_account_id = self.env['account.account'].create({
            'name': 'Outstanding Payment Account B',
            'code': 'OPAB',
            'account_type': 'asset_current',
            'reconcile': True,
        })
        # Create new payments in the second journal
        payment_in_2 = payment_in_1.copy(default={'date': payment_in_1.date})
        payment_in_2.journal_id = bank_journal_B
        payment_out_2 = payment_out_1.copy(default={'date': payment_out_1.date})
        payment_out_2.journal_id = bank_journal_B

        payments = payment_in_1 + payment_out_1 + payment_in_2 + payment_out_2

        self.assertRecordValues(payments, [
            {'duplicate_payment_ids': [payment_in_2.id]},
            {'duplicate_payment_ids': [payment_out_2.id]},
            {'duplicate_payment_ids': [payment_in_1.id]},
            {'duplicate_payment_ids': [payment_out_1.id]},
        ])

    def test_register_payment_different_payment_types(self):
        """ Test that payment wizard correctly calculates duplicate_payment_ids """
        payment_1 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=self.out_invoice_1.ids).create({'payment_date': self.payment_in.date})
        payment_2 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=self.in_invoice_1.ids).create({'payment_date': self.payment_out.date})
        existing_payment_in = self.payment_in
        existing_payment_out = self.payment_out

        # Payment wizards flag unreconciled existing payments of the same payment type only
        self.assertRecordValues(payment_1, [{'duplicate_payment_ids': [existing_payment_in.id]}])
        self.assertRecordValues(payment_2, [{'duplicate_payment_ids': [existing_payment_out.id]}])

    def test_register_payment_single_batch_duplicate_payments(self):
        """ Test that duplicate_payment_ids is correctly calculated for single batches """
        payment_1 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=self.out_invoice_1.ids).create({'payment_date': self.payment_in.date})
        payment_2 = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=self.out_invoice_2.ids).create({'payment_date': self.out_invoice_2.date})
        active_ids = (self.out_invoice_1 + self.out_invoice_2).ids
        combined_payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({
            'amount': 50.0,  # amount can be changed manually
            'group_payment': True,
            'payment_difference_handling': 'open',
            'payment_method_line_id': self.inbound_payment_method_line.id,
        })
        existing_payment = self.payment_in

        self.assertRecordValues(payment_1, [{'duplicate_payment_ids': [existing_payment.id]}])
        self.assertRecordValues(payment_2, [{'duplicate_payment_ids': []}])  # different amount, not a duplicate
        # Combined payments does not show payment_1 as duplicate because payment_1 is reconciled
        self.assertRecordValues(combined_payments, [{'duplicate_payment_ids': [existing_payment.id]}])