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