Merge lp:~therp-nl/banking-addons/ba70-add_tests into lp:banking-addons

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 201
Proposed branch: lp:~therp-nl/banking-addons/ba70-add_tests
Merge into: lp:banking-addons
Diff against target: 392 lines (+375/-0)
3 files modified
account_banking_tests/__openerp__.py (+42/-0)
account_banking_tests/tests/__init__.py (+5/-0)
account_banking_tests/tests/test_payment_roundtrip.py (+328/-0)
To merge this branch: bzr merge lp:~therp-nl/banking-addons/ba70-add_tests
Reviewer Review Type Date Requested Status
Holger Brunn (Therp) code review Approve
Review via email: mp+187780@code.launchpad.net

Description of the change

This is my attempt at adding unit test for a payment/reconciliation roundtrip. I don't think I could have put it in any of the existing modules, because soon the payment export, workflow integration and reconciliation functionalities will no longer be necessary dependencies. Therefore, I put the test in its own module that depends on all needed functionality.

To post a comment you must log in.
190. By Stefan Rijnhart (Opener)

[FIX] Additional substitution of out-refactored assertion check
[FIX] Remove debug statement

Revision history for this message
Holger Brunn (Therp) (hbrunn) wrote :

Yes, adding tests is a very good idea

review: Approve (code review)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'account_banking_tests'
=== added file 'account_banking_tests/__init__.py'
=== added file 'account_banking_tests/__openerp__.py'
--- account_banking_tests/__openerp__.py 1970-01-01 00:00:00 +0000
+++ account_banking_tests/__openerp__.py 2013-09-26 17:55:39 +0000
@@ -0,0 +1,42 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Therp BV (<http://therp.nl>)
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Affero General Public License as
8# published by the Free Software Foundation, either version 3 of the
9# License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU Affero General Public License for more details.
15#
16# You should have received a copy of the GNU Affero General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21{
22 'name': 'Banking Addons - Tests',
23 'version': '0.1',
24 'license': 'AGPL-3',
25 'author': 'Therp BV',
26 'website': 'https://launchpad.net/banking-addons',
27 'category': 'Banking addons',
28 'depends': [
29 'account_accountant',
30 'account_banking',
31 'account_banking_sepa_credit_transfer',
32 ],
33 'description': '''
34This addon adds unit tests for the Banking addons. Installing this
35module will not give you any benefit other than having the tests'
36dependencies installed, so that you can run the tests. If you only
37run the tests manually, you don't even have to install this module,
38only its dependencies.
39 ''',
40 'auto_install': False,
41 'installable': True,
42}
043
=== added directory 'account_banking_tests/tests'
=== added file 'account_banking_tests/tests/__init__.py'
--- account_banking_tests/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ account_banking_tests/tests/__init__.py 2013-09-26 17:55:39 +0000
@@ -0,0 +1,5 @@
1import test_payment_roundtrip
2
3fast_suite = [
4 test_payment_roundtrip,
5 ]
06
=== added file 'account_banking_tests/tests/test_payment_roundtrip.py'
--- account_banking_tests/tests/test_payment_roundtrip.py 1970-01-01 00:00:00 +0000
+++ account_banking_tests/tests/test_payment_roundtrip.py 2013-09-26 17:55:39 +0000
@@ -0,0 +1,328 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# Copyright (C) 2013 Therp BV (<http://therp.nl>)
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU Affero General Public License as
8# published by the Free Software Foundation, either version 3 of the
9# License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU Affero General Public License for more details.
15#
16# You should have received a copy of the GNU Affero General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20from datetime import datetime
21from openerp.tests.common import SingleTransactionCase
22from openerp import netsvc
23
24
25class TestPaymentRoundtrip(SingleTransactionCase):
26
27 def assert_payment_order_state(self, expected):
28 """
29 Check that the state of our payment order is
30 equal to the 'expected' parameter
31 """
32 state = self.registry('payment.order').read(
33 self.cr, self.uid, self.payment_order_id, ['state'])['state']
34 assert state == expected, \
35 'Payment order does not go into state \'%s\'.' % expected
36
37 def assert_invoices_state(self, expected):
38 """
39 Check that the state of our invoices is
40 equal to the 'expected' parameter
41 """
42 for invoice in self.registry('account.invoice').read(
43 self.cr, self.uid, self.invoice_ids, ['state']):
44 assert invoice['state'] == expected, \
45 'Invoice does not go into state \'%s\'' % expected
46
47 def setup_company(self, reg, cr, uid):
48 """
49 Set up a company with a bank account and configure the
50 current user to work with that company
51 """
52 data_model = reg('ir.model.data')
53 self.country_id = data_model.get_object_reference(
54 cr, uid, 'base', 'nl')[1]
55 self.currency_id = data_model.get_object_reference(
56 cr, uid, 'base', 'EUR')[1]
57 self.bank_id = reg('res.bank').create(
58 cr, uid, {
59 'name': 'ING Bank',
60 'bic': 'INGBNL2A',
61 'country': self.country_id,
62 })
63 self.company_id = reg('res.company').create(
64 cr, uid, {
65 'name': '_banking_addons_test_company',
66 'currency_id': self.currency_id,
67 'country_id': self.country_id,
68 })
69 self.partner_id = reg('res.company').read(
70 cr, uid, self.company_id, ['partner_id'])['partner_id'][0]
71 self.partner_bank_id = reg('res.partner.bank').create(
72 cr, uid, {
73 'state': 'iban',
74 'acc_number': 'NL08INGB0000000555',
75 'bank': self.bank_id,
76 'bank_bic': 'INGBNL2A',
77 'partner_id': self.partner_id,
78 'company_id': self.company_id,
79 })
80 reg('res.users').write(
81 cr, uid, [uid], {
82 'company_ids': [(4, self.company_id)]})
83 reg('res.users').write(
84 cr, uid, [uid], {
85 'company_id': self.company_id})
86
87 def setup_chart(self, reg, cr, uid):
88 """
89 Set up the configurable chart of accounts and create periods
90 """
91 data_model = reg('ir.model.data')
92 chart_setup_model = reg('wizard.multi.charts.accounts')
93 chart_template_id = data_model.get_object_reference(
94 cr, uid, 'account', 'configurable_chart_template')[1]
95 chart_values = {
96 'company_id': self.company_id,
97 'currency_id': self.currency_id,
98 'chart_template_id': chart_template_id}
99 chart_values.update(
100 chart_setup_model.onchange_chart_template_id(
101 cr, uid, [], 1)['value'])
102 chart_setup_id = chart_setup_model.create(
103 cr, uid, chart_values)
104 chart_setup_model.execute(
105 cr, uid, [chart_setup_id])
106 year = datetime.now().strftime('%Y')
107 fiscalyear_id = reg('account.fiscalyear').create(
108 cr, uid, {
109 'name': year,
110 'code': year,
111 'company_id': self.company_id,
112 'date_start': '%s-01-01' % year,
113 'date_stop': '%s-12-31' % year,
114 })
115 reg('account.fiscalyear').create_period(
116 cr, uid, [fiscalyear_id])
117
118 def setup_payables(self, reg, cr, uid):
119 """
120 Set up suppliers and invoice them. Check that the invoices
121 can be validated properly.
122 """
123 partner_model = reg('res.partner')
124 supplier1 = partner_model.create(
125 cr, uid, {
126 'name': 'Supplier 1',
127 'supplier': True,
128 'country_id': self.country_id,
129 'bank_ids': [(0, False, {
130 'state': 'iban',
131 'acc_number': 'NL42INGB0000454000',
132 'bank': self.bank_id,
133 'bank_bic': 'INGBNL2A',
134 })],
135 })
136 supplier2 = partner_model.create(
137 cr, uid, {
138 'name': 'Supplier 2',
139 'supplier': True,
140 'country_id': self.country_id,
141 'bank_ids': [(0, False, {
142 'state': 'iban',
143 'acc_number': 'NL86INGB0002445588',
144 'bank': self.bank_id,
145 'bank_bic': 'INGBNL2A',
146 })],
147 })
148 self.payable_id = reg('account.account').search(
149 cr, uid, [
150 ('company_id', '=', self.company_id),
151 ('code', '=', '120000')])[0]
152 expense_id = reg('account.account').search(
153 cr, uid, [
154 ('company_id', '=', self.company_id),
155 ('code', '=', '123000')])[0]
156 invoice_model = reg('account.invoice')
157 values = {
158 'type': 'in_invoice',
159 'partner_id': supplier1,
160 'account_id': self.payable_id,
161 'invoice_line': [(0, False, {
162 'name': 'Purchase 1',
163 'price_unit': 100.0,
164 'quantity': 1,
165 'account_id': expense_id,})],
166 }
167 self.invoice_ids = [
168 invoice_model.create(
169 cr, uid, values, context={
170 'type': 'in_invoice',
171 })]
172 values.update({
173 'partner_id': supplier2,
174 'name': 'Purchase 2'})
175 self.invoice_ids.append(
176 invoice_model.create(
177 cr, uid, values, context={
178 'type': 'in_invoice'}))
179 wf_service = netsvc.LocalService('workflow')
180 for invoice_id in self.invoice_ids:
181 wf_service.trg_validate(
182 uid, 'account.invoice', invoice_id, 'invoice_open', cr)
183 self.assert_invoices_state('open')
184
185 def setup_payment_config(self, reg, cr, uid):
186 """
187 Configure an additional account and journal for payments
188 in transit and configure a payment mode with them.
189 """
190 account_parent_id = reg('account.account').search(
191 cr, uid, [
192 ('company_id', '=', self.company_id),
193 ('parent_id', '=', False)])[0]
194 user_type = reg('ir.model.data').get_object_reference(
195 cr, uid, 'account', 'data_account_type_liability')[1]
196 transfer_account_id = reg('account.account').create(
197 cr, uid, {
198 'company_id': self.company_id,
199 'parent_id': account_parent_id,
200 'code': 'TRANS',
201 'name': 'Transfer account',
202 'type': 'other',
203 'user_type': user_type,
204 'reconcile': True,
205 })
206 transfer_journal_id = reg('account.journal').search(
207 cr, uid, [
208 ('company_id', '=', self.company_id),
209 ('code', '=', 'MISC')])[0]
210 self.bank_journal_id = reg('account.journal').search(
211 cr, uid, [
212 ('company_id', '=', self.company_id),
213 ('type', '=', 'bank')])[0]
214 payment_mode_type_id = reg('ir.model.data').get_object_reference(
215 cr, uid, 'account_banking_sepa_credit_transfer',
216 'export_sepa_sct_001_001_03')[1]
217 self.payment_mode_id = reg('payment.mode').create(
218 cr, uid, {
219 'name': 'SEPA Mode',
220 'bank_id': self.partner_bank_id,
221 'journal': self.bank_journal_id,
222 'company_id': self.company_id,
223 'transfer_account_id': transfer_account_id,
224 'transfer_journal_id': transfer_journal_id,
225 'type': payment_mode_type_id,
226 })
227
228 def setup_payment(self, reg, cr, uid):
229 """
230 Create a payment order with the invoices' payable move lines.
231 Check that the payment order can be confirmed.
232 """
233 self.payment_order_id = reg('payment.order').create(
234 cr, uid, {
235 'reference': 'PAY001',
236 'mode': self.payment_mode_id,
237 })
238 context = {'active_id': self.payment_order_id}
239 entries = reg('account.move.line').search(
240 cr, uid, [
241 ('company_id', '=', self.company_id),
242 ('account_id', '=', self.payable_id),
243 ])
244 self.payment_order_create_id = reg('payment.order.create').create(
245 cr, uid, {
246 'entries': [(6, 0, entries)],
247 }, context=context)
248 reg('payment.order.create').create_payment(
249 cr, uid, [self.payment_order_create_id], context=context)
250 wf_service = netsvc.LocalService('workflow')
251 wf_service.trg_validate(
252 uid, 'payment.order', self.payment_order_id, 'open', cr)
253 self.assert_payment_order_state('open')
254
255 def export_payment(self, reg, cr, uid):
256 """
257 Call the SEPA export wizard on the payment order
258 and check that the payment order and related invoices'
259 states are moved forward afterwards
260 """
261 export_model = reg('banking.export.sepa.wizard')
262 export_id = export_model.create(
263 cr, uid, {
264 'msg_identification': 'EXP001'},
265 context={'active_ids': [self.payment_order_id]})
266 export_model.create_sepa(
267 cr, uid, [export_id])
268 export_model.save_sepa(
269 cr, uid, [export_id])
270 self.assert_payment_order_state('sent')
271 self.assert_invoices_state('paid')
272
273 def setup_bank_statement(self, reg, cr, uid):
274 """
275 Create a bank statement with a single line. Call the reconciliation
276 wizard to match the line with the open payment order. Confirm the
277 bank statement. Check if the payment order is done.
278 """
279 statement_model = reg('account.bank.statement')
280 line_model = reg('account.bank.statement.line')
281 wizard_model = reg('banking.transaction.wizard')
282 statement_id = statement_model.create(
283 cr, uid, {
284 'name': 'Statement',
285 'journal_id': self.bank_journal_id,
286 'balance_end_real': -200.0,
287 'period_id': reg('account.period').find(cr, uid)[0]
288 })
289 line_id = line_model.create(
290 cr, uid, {
291 'name': 'Statement line',
292 'statement_id': statement_id,
293 'amount': -200.0,
294 'account_id': self.payable_id,
295 })
296 wizard_id = wizard_model.create(
297 cr, uid, {'statement_line_id': line_id})
298 wizard_model.write(
299 cr, uid, [wizard_id], {
300 'manual_payment_order_id': self.payment_order_id})
301 statement_model.button_confirm_bank(cr, uid, [statement_id])
302 self.assert_payment_order_state('done')
303
304 def check_reconciliations(self, reg, cr, uid):
305 """
306 Check if the payment order has any lines and that
307 the transit move lines of those payment lines are
308 reconciled by now.
309 """
310 payment_order = reg('payment.order').browse(
311 cr, uid, self.payment_order_id)
312 assert payment_order.line_ids, 'Payment order has no payment lines'
313 for line in payment_order.line_ids:
314 assert line.transit_move_line_id, \
315 'Payment order has no transfer move line'
316 assert line.transit_move_line_id.reconcile_id, \
317 'Transfer move line on payment line is not reconciled'
318
319 def test_payment_roundtrip(self):
320 reg, cr, uid, = self.registry, self.cr, self.uid
321 self.setup_company(reg, cr, uid)
322 self.setup_chart(reg, cr, uid)
323 self.setup_payables(reg, cr, uid)
324 self.setup_payment_config(reg, cr, uid)
325 self.setup_payment(reg, cr, uid)
326 self.export_payment(reg, cr, uid)
327 self.setup_bank_statement(reg, cr, uid)
328 self.check_reconciliations(reg, cr, uid)

Subscribers

People subscribed via source and target branches

to status/vote changes: