Merge lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 into lp:banking-addons/6.1
- 6.1-dev-fixes_from_testing_iteration_2
- Merge into 6.1
Proposed by
Stefan Rijnhart (Opener)
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 129 | ||||
Proposed branch: | lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 | ||||
Merge into: | lp:banking-addons/6.1 | ||||
Diff against target: |
1203 lines (+423/-330) (has conflicts) 7 files modified
account_banking/account_banking.py (+73/-24) account_banking/account_banking_view.xml (+1/-1) account_banking/banking_import_transaction.py (+319/-297) account_banking/wizard/banking_transaction_wizard.py (+2/-3) account_direct_debit/model/account_payment.py (+0/-1) account_direct_debit/view/account_invoice.xml (+2/-2) account_direct_debit/workflow/account_invoice.xml (+26/-2) Text conflict in account_banking/banking_import_transaction.py |
||||
To merge this branch: | bzr merge lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Jesudason | Pending | ||
Stefan Rijnhart (Opener) | Pending | ||
Review via email: mp+104535@code.launchpad.net |
This proposal supersedes a proposal from 2012-05-02.
Commit message
Description of the change
This branch should contain the necessary adaptations of the code associated with payment and direct debit orders to work nicely with the new voucher oriented reconciliation mechanism as well as some streamlining of the latter.
It also restores the ability to encode statements manually.
To post a comment you must log in.
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote : Posted in a previous version of this proposal | # |
review:
Needs Resubmitting
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'account_banking/account_banking.py' | |||
2 | --- account_banking/account_banking.py 2012-04-14 09:16:54 +0000 | |||
3 | +++ account_banking/account_banking.py 2012-05-03 11:53:24 +0000 | |||
4 | @@ -58,13 +58,11 @@ | |||
5 | 58 | Rejected payments from the bank receive on import the status 'rejected'. | 58 | Rejected payments from the bank receive on import the status 'rejected'. |
6 | 59 | ''' | 59 | ''' |
7 | 60 | import time | 60 | import time |
8 | 61 | import sys | ||
9 | 62 | import sepa | 61 | import sepa |
10 | 63 | from osv import osv, fields | 62 | from osv import osv, fields |
11 | 64 | from tools.translate import _ | 63 | from tools.translate import _ |
12 | 65 | from wizard.banktools import get_or_create_bank | 64 | from wizard.banktools import get_or_create_bank |
13 | 66 | import decimal_precision as dp | 65 | import decimal_precision as dp |
14 | 67 | import pooler | ||
15 | 68 | import netsvc | 66 | import netsvc |
16 | 69 | from openerp import SUPERUSER_ID | 67 | from openerp import SUPERUSER_ID |
17 | 70 | 68 | ||
18 | @@ -322,6 +320,26 @@ | |||
19 | 322 | # 'currency': _currency, | 320 | # 'currency': _currency, |
20 | 323 | } | 321 | } |
21 | 324 | 322 | ||
22 | 323 | def _check_company_id(self, cr, uid, ids, context=None): | ||
23 | 324 | """ | ||
24 | 325 | Adapt this constraint method from the account module to reflect the | ||
25 | 326 | move of period_id to the statement line | ||
26 | 327 | """ | ||
27 | 328 | for statement in self.browse(cr, uid, ids, context=context): | ||
28 | 329 | if (statement.period_id and | ||
29 | 330 | statement.company_id.id != statement.period_id.company_id.id): | ||
30 | 331 | return False | ||
31 | 332 | for line in statement.line_ids: | ||
32 | 333 | if (line.period_id and | ||
33 | 334 | statement.company_id.id != line.period_id.company_id.id): | ||
34 | 335 | return False | ||
35 | 336 | return True | ||
36 | 337 | |||
37 | 338 | # Redefine the constraint, or it still refer to the original method | ||
38 | 339 | _constraints = [ | ||
39 | 340 | (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']), | ||
40 | 341 | ] | ||
41 | 342 | |||
42 | 325 | def _get_period(self, cursor, uid, date, context=None): | 343 | def _get_period(self, cursor, uid, date, context=None): |
43 | 326 | ''' | 344 | ''' |
44 | 327 | Find matching period for date, not meant for _defaults. | 345 | Find matching period for date, not meant for _defaults. |
45 | @@ -341,10 +359,12 @@ | |||
46 | 341 | context=None): | 359 | context=None): |
47 | 342 | # This is largely a copy of the original code in account | 360 | # This is largely a copy of the original code in account |
48 | 343 | # Modifications are marked with AB | 361 | # Modifications are marked with AB |
49 | 362 | # Modifications by account_voucher are merged below. | ||
50 | 344 | # As there is no valid inheritance mechanism for large actions, this | 363 | # As there is no valid inheritance mechanism for large actions, this |
51 | 345 | # is the only option to add functionality to existing actions. | 364 | # is the only option to add functionality to existing actions. |
52 | 346 | # WARNING: when the original code changes, this trigger has to be | 365 | # WARNING: when the original code changes, this trigger has to be |
53 | 347 | # updated in sync. | 366 | # updated in sync. |
54 | 367 | |||
55 | 348 | if context is None: | 368 | if context is None: |
56 | 349 | context = {} | 369 | context = {} |
57 | 350 | res_currency_obj = self.pool.get('res.currency') | 370 | res_currency_obj = self.pool.get('res.currency') |
58 | @@ -352,8 +372,36 @@ | |||
59 | 352 | account_move_line_obj = self.pool.get('account.move.line') | 372 | account_move_line_obj = self.pool.get('account.move.line') |
60 | 353 | account_bank_statement_line_obj = self.pool.get( | 373 | account_bank_statement_line_obj = self.pool.get( |
61 | 354 | 'account.bank.statement.line') | 374 | 'account.bank.statement.line') |
64 | 355 | st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id, | 375 | st_line = account_bank_statement_line_obj.browse( |
65 | 356 | context=context) | 376 | cr, uid, st_line_id, context=context) |
66 | 377 | # Start account voucher | ||
67 | 378 | # Post the voucher and update links between statement and moves | ||
68 | 379 | if st_line.voucher_id: | ||
69 | 380 | voucher_pool = self.pool.get('account.voucher') | ||
70 | 381 | wf_service = netsvc.LocalService("workflow") | ||
71 | 382 | voucher_pool.write( | ||
72 | 383 | cr, uid, [st_line.voucher_id.id], {'number': st_line_number}, context=context) | ||
73 | 384 | if st_line.voucher_id.state == 'cancel': | ||
74 | 385 | voucher_pool.action_cancel_draft( | ||
75 | 386 | cr, uid, [st_line.voucher_id.id], context=context) | ||
76 | 387 | wf_service.trg_validate( | ||
77 | 388 | uid, 'account.voucher', st_line.voucher_id.id, 'proforma_voucher', cr) | ||
78 | 389 | v = voucher_pool.browse( | ||
79 | 390 | cr, uid, st_line.voucher_id.id, context=context) | ||
80 | 391 | account_bank_statement_line_obj.write(cr, uid, [st_line_id], { | ||
81 | 392 | 'move_ids': [(4, v.move_id.id, False)] | ||
82 | 393 | }) | ||
83 | 394 | account_move_line_obj.write( | ||
84 | 395 | cr, uid, [x.id for x in v.move_ids], | ||
85 | 396 | {'statement_id': st_line.statement_id.id}, context=context) | ||
86 | 397 | # End of account_voucher | ||
87 | 398 | st_line.refresh() | ||
88 | 399 | |||
89 | 400 | # AB: The voucher journal isn't automatically posted, so post it (if needed) | ||
90 | 401 | if not st_line.voucher_id.journal_id.entry_posted: | ||
91 | 402 | account_move_obj.post(cr, uid, [st_line.voucher_id.move_id.id], context={}) | ||
92 | 403 | return True | ||
93 | 404 | |||
94 | 357 | st = st_line.statement_id | 405 | st = st_line.statement_id |
95 | 358 | 406 | ||
96 | 359 | context.update({'date': st_line.date}) | 407 | context.update({'date': st_line.date}) |
97 | @@ -457,22 +505,23 @@ | |||
98 | 457 | # Bank statements will not consider boolean on journal entry_posted | 505 | # Bank statements will not consider boolean on journal entry_posted |
99 | 458 | account_move_obj.post(cr, uid, [move_id], context=context) | 506 | account_move_obj.post(cr, uid, [move_id], context=context) |
100 | 459 | 507 | ||
117 | 460 | # Shouldn't now be needed as payment and reconciliation of invoices | 508 | """ |
118 | 461 | # is done through account_voucher | 509 | Account-banking: |
119 | 462 | #""" | 510 | - Write stored reconcile_id |
120 | 463 | #Account-banking: | 511 | - Pay invoices through workflow |
121 | 464 | #- Write stored reconcile_id | 512 | |
122 | 465 | #- Pay invoices through workflow | 513 | Does not apply to voucher integration, but only to |
123 | 466 | #""" | 514 | payments and payment orders |
124 | 467 | #if st_line.reconcile_id: | 515 | """ |
125 | 468 | # account_move_line_obj.write(cr, uid, torec, { | 516 | if st_line.reconcile_id: |
126 | 469 | # (st_line.reconcile_id.line_partial_ids and | 517 | account_move_line_obj.write(cr, uid, torec, { |
127 | 470 | # 'reconcile_partial_id' or 'reconcile_id'): | 518 | (st_line.reconcile_id.line_partial_ids and |
128 | 471 | # st_line.reconcile_id.id }, context=context) | 519 | 'reconcile_partial_id' or 'reconcile_id'): |
129 | 472 | # for move_line in (st_line.reconcile_id.line_id or []) + ( | 520 | st_line.reconcile_id.id }, context=context) |
130 | 473 | # st_line.reconcile_id.line_partial_ids or []): | 521 | for move_line in (st_line.reconcile_id.line_id or []) + ( |
131 | 474 | # netsvc.LocalService("workflow").trg_trigger( | 522 | st_line.reconcile_id.line_partial_ids or []): |
132 | 475 | # uid, 'account.move.line', move_line.id, cr) | 523 | netsvc.LocalService("workflow").trg_trigger( |
133 | 524 | uid, 'account.move.line', move_line.id, cr) | ||
134 | 476 | #""" End account-banking """ | 525 | #""" End account-banking """ |
135 | 477 | 526 | ||
136 | 478 | return move_id | 527 | return move_id |
137 | @@ -935,7 +984,7 @@ | |||
138 | 935 | Previously (pre-v6) in account_payment/wizard/wizard_pay.py | 984 | Previously (pre-v6) in account_payment/wizard/wizard_pay.py |
139 | 936 | """ | 985 | """ |
140 | 937 | if context == None: | 986 | if context == None: |
142 | 938 | context={} | 987 | context = {} |
143 | 939 | result = {} | 988 | result = {} |
144 | 940 | orders = self.browse(cr, uid, ids, context) | 989 | orders = self.browse(cr, uid, ids, context) |
145 | 941 | order = orders[0] | 990 | order = orders[0] |
146 | @@ -1134,7 +1183,7 @@ | |||
147 | 1134 | ''' | 1183 | ''' |
148 | 1135 | Create dual function IBAN account for SEPA countries | 1184 | Create dual function IBAN account for SEPA countries |
149 | 1136 | ''' | 1185 | ''' |
151 | 1137 | if vals['state'] == 'iban': | 1186 | if vals.get('state') == 'iban': |
152 | 1138 | iban = vals.get('acc_number',False) or vals.get('acc_number_domestic',False) | 1187 | iban = vals.get('acc_number',False) or vals.get('acc_number_domestic',False) |
153 | 1139 | vals['acc_number'], vals['acc_number_domestic'] = ( | 1188 | vals['acc_number'], vals['acc_number_domestic'] = ( |
154 | 1140 | self._correct_IBAN(iban)) | 1189 | self._correct_IBAN(iban)) |
155 | @@ -1236,7 +1285,7 @@ | |||
156 | 1236 | fields.append('state') | 1285 | fields.append('state') |
157 | 1237 | records = self._founder.read(cr, uid, ids, fields, context, load) | 1286 | records = self._founder.read(cr, uid, ids, fields, context, load) |
158 | 1238 | is_list = True | 1287 | is_list = True |
160 | 1239 | if not isinstance(records, list): | 1288 | if not isinstance(records, list): |
161 | 1240 | records = [records,] | 1289 | records = [records,] |
162 | 1241 | is_list = False | 1290 | is_list = False |
163 | 1242 | for record in records: | 1291 | for record in records: |
164 | @@ -1529,7 +1578,7 @@ | |||
165 | 1529 | """ | 1578 | """ |
166 | 1530 | total = 0.0 | 1579 | total = 0.0 |
167 | 1531 | if not ids: | 1580 | if not ids: |
169 | 1532 | total | 1581 | return total |
170 | 1533 | for line in self.read( | 1582 | for line in self.read( |
171 | 1534 | cr, uid, ids, ['debit', 'credit'], context=context): | 1583 | cr, uid, ids, ['debit', 'credit'], context=context): |
172 | 1535 | total += (line['debit'] or 0.0) - (line['credit'] or 0.0) | 1584 | total += (line['debit'] or 0.0) - (line['credit'] or 0.0) |
173 | 1536 | 1585 | ||
174 | === modified file 'account_banking/account_banking_view.xml' | |||
175 | --- account_banking/account_banking_view.xml 2012-03-08 10:18:13 +0000 | |||
176 | +++ account_banking/account_banking_view.xml 2012-05-03 11:53:24 +0000 | |||
177 | @@ -192,7 +192,7 @@ | |||
178 | 192 | <data> | 192 | <data> |
179 | 193 | <field name="period_id" position="replace"/> | 193 | <field name="period_id" position="replace"/> |
180 | 194 | <xpath expr="/form/notebook/page[@string='Transaction']/field/tree" position="attributes"> | 194 | <xpath expr="/form/notebook/page[@string='Transaction']/field/tree" position="attributes"> |
182 | 195 | <attribute name="colors">black:state == 'confirmed';darkmagenta:match_multi == True;grey:state=='draft';crimson:duplicate == True;</attribute> | 195 | <attribute name="colors">black:state == 'confirmed';darkmagenta:match_multi == True;crimson:duplicate == True;grey:state == 'draft';</attribute> |
183 | 196 | </xpath> | 196 | </xpath> |
184 | 197 | <xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='name']" position="replace"> | 197 | <xpath expr="/form/notebook/page[@string='Transaction']/field/tree/field[@name='name']" position="replace"> |
185 | 198 | <field name="name" required="1"/> | 198 | <field name="name" required="1"/> |
186 | 199 | 199 | ||
187 | === modified file 'account_banking/banking_import_transaction.py' | |||
188 | --- account_banking/banking_import_transaction.py 2012-05-03 11:50:29 +0000 | |||
189 | +++ account_banking/banking_import_transaction.py 2012-05-03 11:53:24 +0000 | |||
190 | @@ -88,7 +88,7 @@ | |||
191 | 88 | elif not invoice_ids: | 88 | elif not invoice_ids: |
192 | 89 | # create supplier invoice | 89 | # create supplier invoice |
193 | 90 | partner_obj = self.pool.get('res.partner') | 90 | partner_obj = self.pool.get('res.partner') |
195 | 91 | invoice_lines = [(0,0,dict( | 91 | invoice_lines = [(0, 0, dict( |
196 | 92 | amount = 1, | 92 | amount = 1, |
197 | 93 | price_unit = amount, | 93 | price_unit = amount, |
198 | 94 | name = trans.message or trans.reference, | 94 | name = trans.message or trans.reference, |
199 | @@ -247,8 +247,8 @@ | |||
200 | 247 | # the interactive wizard | 247 | # the interactive wizard |
201 | 248 | return False | 248 | return False |
202 | 249 | 249 | ||
205 | 250 | '''Check if the move_line has been cached''' | 250 | #'''Check if the move_line has been cached''' |
206 | 251 | return move_line.id in linked_invoices | 251 | #return move_line.id in linked_invoices |
207 | 252 | 252 | ||
208 | 253 | def _cache(move_line, remaining=0.0): | 253 | def _cache(move_line, remaining=0.0): |
209 | 254 | '''Cache the move_line''' | 254 | '''Cache the move_line''' |
210 | @@ -430,6 +430,7 @@ | |||
211 | 430 | 430 | ||
212 | 431 | return trans, False, False | 431 | return trans, False, False |
213 | 432 | 432 | ||
214 | 433 | <<<<<<< TREE | ||
215 | 433 | def _do_move_reconcile( | 434 | def _do_move_reconcile( |
216 | 434 | self, cr, uid, move_line_ids, currency, amount, context=None): | 435 | self, cr, uid, move_line_ids, currency, amount, context=None): |
217 | 435 | """ | 436 | """ |
218 | @@ -537,6 +538,20 @@ | |||
219 | 537 | def _reconcile_move( | 538 | def _reconcile_move( |
220 | 538 | self, cr, uid, transaction_id, context=None): | 539 | self, cr, uid, transaction_id, context=None): |
221 | 539 | transaction = self.browse(cr, uid, transaction_id, context=context) | 540 | transaction = self.browse(cr, uid, transaction_id, context=context) |
222 | 541 | ======= | ||
223 | 542 | def _confirm_move(self, cr, uid, transaction_id, context=None): | ||
224 | 543 | """ | ||
225 | 544 | The line is matched against a move (invoice), so generate a payment | ||
226 | 545 | voucher with the write-off settings that the user requested. The move | ||
227 | 546 | lines will be generated by the voucher, handling rounding and currency | ||
228 | 547 | conversion. | ||
229 | 548 | """ | ||
230 | 549 | if context is None: | ||
231 | 550 | context = {} | ||
232 | 551 | |||
233 | 552 | statement_line_pool = self.pool.get('account.bank.statement.line') | ||
234 | 553 | transaction = self.browse(cr, uid, transaction_id, context) | ||
235 | 554 | >>>>>>> MERGE-SOURCE | ||
236 | 540 | if not transaction.move_line_id: | 555 | if not transaction.move_line_id: |
237 | 541 | if transaction.match_type == 'invoice': | 556 | if transaction.match_type == 'invoice': |
238 | 542 | raise osv.except_osv( | 557 | raise osv.except_osv( |
239 | @@ -558,42 +573,119 @@ | |||
240 | 558 | transaction.statement_line_id.statement_id.name, | 573 | transaction.statement_line_id.statement_id.name, |
241 | 559 | transaction.statement_line_id.name | 574 | transaction.statement_line_id.name |
242 | 560 | ))) | 575 | ))) |
253 | 561 | currency = transaction.statement_line_id.statement_id.currency | 576 | |
254 | 562 | line_ids = [transaction.move_line_id.id] | 577 | st_line = transaction.statement_line_id |
255 | 563 | if transaction.writeoff_move_line_id: | 578 | journal = st_line.statement_id.journal_id |
256 | 564 | line_ids.append(transaction.writeoff_move_line_id.id) | 579 | if st_line.amount < 0.0: |
257 | 565 | reconcile_id = self._do_move_reconcile( | 580 | voucher_type = 'payment' |
258 | 566 | cr, uid, line_ids, currency, | 581 | account_id = (journal.default_debit_account_id and |
259 | 567 | transaction.transferred_amount, context=context) | 582 | journal.default_debit_account_id.id or False) |
260 | 568 | return reconcile_id | 583 | else: |
261 | 569 | 584 | voucher_type = 'receipt' | |
262 | 570 | def _reconcile_storno( | 585 | account_id = (journal.default_credit_account_id and |
263 | 586 | journal.default_credit_account_id.id or False) | ||
264 | 587 | |||
265 | 588 | # Use the statement line's date determine the period | ||
266 | 589 | ctxt = context.copy() | ||
267 | 590 | ctxt['company_id'] = st_line.company_id.id | ||
268 | 591 | if 'period_id' in ctxt: | ||
269 | 592 | del ctxt['period_id'] | ||
270 | 593 | period_id = self.pool.get('account.period').find( | ||
271 | 594 | cr, uid, st_line.date, context=ctxt)[0] | ||
272 | 595 | |||
273 | 596 | # Convert the move line amount to the journal currency | ||
274 | 597 | move_line_amount = transaction.move_line_id.amount_residual_currency | ||
275 | 598 | to_curr_id = (st_line.statement_id.journal_id.currency and | ||
276 | 599 | st_line.statement_id.journal_id.currency.id or | ||
277 | 600 | st_line.statement_id.company_id.currency_id.id) | ||
278 | 601 | from_curr_id = (transaction.move_line_id.currency_id and | ||
279 | 602 | transaction.move_line_id.currency_id.id or | ||
280 | 603 | st_line.statement_id.company_id.currency_id.id) | ||
281 | 604 | if from_curr_id != to_curr_id: | ||
282 | 605 | amount_currency = statement_line_pool._convert_currency( | ||
283 | 606 | cr, uid, from_curr_id, to_curr_id, move_line_amount, | ||
284 | 607 | round=True, date=time.strftime('%Y-%m-%d'), | ||
285 | 608 | context=context) | ||
286 | 609 | else: | ||
287 | 610 | amount_currency = move_line_amount | ||
288 | 611 | |||
289 | 612 | # Check whether this is a full or partial reconciliation | ||
290 | 613 | if transaction.payment_option == 'with_writeoff': | ||
291 | 614 | writeoff = abs(st_line.amount) - abs(amount_currency) | ||
292 | 615 | line_amount = abs(amount_currency) | ||
293 | 616 | else: | ||
294 | 617 | writeoff = 0.0 | ||
295 | 618 | line_amount = abs(st_line.amount) | ||
296 | 619 | |||
297 | 620 | # Define the voucher | ||
298 | 621 | voucher = { | ||
299 | 622 | 'journal_id': st_line.statement_id.journal_id.id, | ||
300 | 623 | 'partner_id': st_line.partner_id and st_line.partner_id.id or False, | ||
301 | 624 | 'company_id': st_line.company_id.id, | ||
302 | 625 | 'type':voucher_type, | ||
303 | 626 | 'company_id': st_line.company_id.id, | ||
304 | 627 | 'account_id': account_id, | ||
305 | 628 | 'amount': abs(st_line.amount), | ||
306 | 629 | 'writeoff_amount': writeoff, | ||
307 | 630 | 'payment_option': transaction.payment_option, | ||
308 | 631 | 'writeoff_acc_id': transaction.writeoff_account_id.id, | ||
309 | 632 | 'analytic_id': transaction.writeoff_analytic_id.id, | ||
310 | 633 | 'date': st_line.date, | ||
311 | 634 | 'date_due': st_line.date, | ||
312 | 635 | 'period_id': period_id, | ||
313 | 636 | 'payment_rate_currency_id':to_curr_id, | ||
314 | 637 | } | ||
315 | 638 | |||
316 | 639 | # Define the voucher line | ||
317 | 640 | vch_line = { | ||
318 | 641 | #'voucher_id': v_id, | ||
319 | 642 | 'move_line_id': transaction.move_line_id.id, | ||
320 | 643 | 'reconcile': True, | ||
321 | 644 | 'amount': line_amount, | ||
322 | 645 | 'account_id': transaction.move_line_id.account_id.id, | ||
323 | 646 | 'type': transaction.move_line_id.credit and 'dr' or 'cr', | ||
324 | 647 | } | ||
325 | 648 | voucher['line_ids'] = [(0, 0, vch_line)] | ||
326 | 649 | voucher_id = self.pool.get('account.voucher').create( | ||
327 | 650 | cr, uid, voucher, context=context) | ||
328 | 651 | statement_line_pool.write( | ||
329 | 652 | cr, uid, st_line.id, | ||
330 | 653 | {'voucher_id': voucher_id}, context=context) | ||
331 | 654 | transaction.refresh() | ||
332 | 655 | |||
333 | 656 | def _confirm_storno( | ||
334 | 571 | self, cr, uid, transaction_id, context=None): | 657 | self, cr, uid, transaction_id, context=None): |
335 | 572 | """ | 658 | """ |
336 | 573 | Creation of the reconciliation has been delegated to | 659 | Creation of the reconciliation has been delegated to |
337 | 574 | *a* direct debit module, to allow for various direct debit styles | 660 | *a* direct debit module, to allow for various direct debit styles |
338 | 575 | """ | 661 | """ |
340 | 576 | payment_line_obj = self.pool.get('payment.line') | 662 | payment_line_pool = self.pool.get('payment.line') |
341 | 663 | statement_line_pool = self.pool.get('account.bank.statement.line') | ||
342 | 577 | transaction = self.browse(cr, uid, transaction_id, context=context) | 664 | transaction = self.browse(cr, uid, transaction_id, context=context) |
343 | 578 | if not transaction.payment_line_id: | 665 | if not transaction.payment_line_id: |
344 | 579 | raise osv.except_osv( | 666 | raise osv.except_osv( |
345 | 580 | _("Cannot link with storno"), | 667 | _("Cannot link with storno"), |
346 | 581 | _("No direct debit order item")) | 668 | _("No direct debit order item")) |
348 | 582 | return payment_line_obj.debit_storno( | 669 | reconcile_id = payment_line_pool.debit_storno( |
349 | 583 | cr, uid, | 670 | cr, uid, |
350 | 584 | transaction.payment_line_id.id, | 671 | transaction.payment_line_id.id, |
351 | 585 | transaction.statement_line_id.amount, | 672 | transaction.statement_line_id.amount, |
352 | 586 | transaction.statement_line_id.currency, | 673 | transaction.statement_line_id.currency, |
353 | 587 | transaction.storno_retry, | 674 | transaction.storno_retry, |
354 | 588 | context=context) | 675 | context=context) |
355 | 676 | statement_line_pool.write( | ||
356 | 677 | cr, uid, transaction.statement_line_id.id, | ||
357 | 678 | {'reconcile_id': reconcile_id}, context=context) | ||
358 | 679 | transaction.refresh() | ||
359 | 589 | 680 | ||
361 | 590 | def _reconcile_payment_order( | 681 | def _confirm_payment_order( |
362 | 591 | self, cr, uid, transaction_id, context=None): | 682 | self, cr, uid, transaction_id, context=None): |
363 | 592 | """ | 683 | """ |
364 | 593 | Creation of the reconciliation has been delegated to | 684 | Creation of the reconciliation has been delegated to |
365 | 594 | *a* direct debit module, to allow for various direct debit styles | 685 | *a* direct debit module, to allow for various direct debit styles |
366 | 595 | """ | 686 | """ |
367 | 596 | payment_order_obj = self.pool.get('payment.order') | 687 | payment_order_obj = self.pool.get('payment.order') |
368 | 688 | statement_line_pool = self.pool.get('account.bank.statement.line') | ||
369 | 597 | transaction = self.browse(cr, uid, transaction_id, context=context) | 689 | transaction = self.browse(cr, uid, transaction_id, context=context) |
370 | 598 | if not transaction.payment_order_id: | 690 | if not transaction.payment_order_id: |
371 | 599 | raise osv.except_osv( | 691 | raise osv.except_osv( |
372 | @@ -603,14 +695,17 @@ | |||
373 | 603 | raise osv.except_osv( | 695 | raise osv.except_osv( |
374 | 604 | _("Cannot reconcile"), | 696 | _("Cannot reconcile"), |
375 | 605 | _("Reconcile payment order not implemented")) | 697 | _("Reconcile payment order not implemented")) |
377 | 606 | return payment_order_obj.debit_reconcile_transfer( | 698 | reconcile_id = payment_order_obj.debit_reconcile_transfer( |
378 | 607 | cr, uid, | 699 | cr, uid, |
379 | 608 | transaction.payment_order_id.id, | 700 | transaction.payment_order_id.id, |
380 | 609 | transaction.statement_line_id.amount, | 701 | transaction.statement_line_id.amount, |
381 | 610 | transaction.statement_line_id.currency, | 702 | transaction.statement_line_id.currency, |
382 | 611 | context=context) | 703 | context=context) |
383 | 704 | statement_line_pool.write( | ||
384 | 705 | cr, uid, transaction.statement_line_id.id, | ||
385 | 706 | {'reconcile_id': reconcile_id}, context=context) | ||
386 | 612 | 707 | ||
388 | 613 | def _reconcile_payment( | 708 | def _confirm_payment( |
389 | 614 | self, cr, uid, transaction_id, context=None): | 709 | self, cr, uid, transaction_id, context=None): |
390 | 615 | """ | 710 | """ |
391 | 616 | Do some housekeeping on the payment line | 711 | Do some housekeeping on the payment line |
392 | @@ -624,7 +719,7 @@ | |||
393 | 624 | 'date_done': transaction.effective_date, | 719 | 'date_done': transaction.effective_date, |
394 | 625 | } | 720 | } |
395 | 626 | ) | 721 | ) |
397 | 627 | return self._reconcile_move(cr, uid, transaction_id, context=context) | 722 | self._confirm_move(cr, uid, transaction_id, context=context) |
398 | 628 | 723 | ||
399 | 629 | def _cancel_payment( | 724 | def _cancel_payment( |
400 | 630 | self, cr, uid, transaction_id, context=None): | 725 | self, cr, uid, transaction_id, context=None): |
401 | @@ -653,6 +748,7 @@ | |||
402 | 653 | transaction.statement_line_id.amount, | 748 | transaction.statement_line_id.amount, |
403 | 654 | transaction.statement_line_id.currency) | 749 | transaction.statement_line_id.currency) |
404 | 655 | 750 | ||
405 | 751 | <<<<<<< TREE | ||
406 | 656 | def _cancel_move( | 752 | def _cancel_move( |
407 | 657 | self, cr, uid, transaction_id, context=None): | 753 | self, cr, uid, transaction_id, context=None): |
408 | 658 | """ | 754 | """ |
409 | @@ -666,7 +762,76 @@ | |||
410 | 666 | """ | 762 | """ |
411 | 667 | statement_line_obj = self.pool.get('account.bank.statement.line') | 763 | statement_line_obj = self.pool.get('account.bank.statement.line') |
412 | 668 | transaction = self.browse(cr, uid, transaction_id, context=context) | 764 | transaction = self.browse(cr, uid, transaction_id, context=context) |
413 | 765 | ======= | ||
414 | 766 | def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None): | ||
415 | 767 | """ | ||
416 | 768 | Legacy method. Allow for canceling bank statement lines that | ||
417 | 769 | were confirmed using earlier versions of the interactive wizard branch. | ||
418 | 770 | |||
419 | 771 | Undo a reconciliation, removing the given move line ids. If no | ||
420 | 772 | meaningful (partial) reconciliation remains, delete it. | ||
421 | 773 | |||
422 | 774 | :param move_line_ids: List of ids. This will usually be the move | ||
423 | 775 | line of an associated invoice or payment, plus optionally the | ||
424 | 776 | move line of a writeoff. | ||
425 | 777 | :param currency: A res.currency *browse* object to perform math | ||
426 | 778 | operations on the amounts. | ||
427 | 779 | """ | ||
428 | 780 | move_line_obj = self.pool.get('account.move.line') | ||
429 | 781 | reconcile_obj = self.pool.get('account.move.reconcile') | ||
430 | 782 | is_zero = lambda amount: self.pool.get('res.currency').is_zero( | ||
431 | 783 | cr, uid, currency, amount) | ||
432 | 784 | move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context) | ||
433 | 785 | reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id | ||
434 | 786 | line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids] | ||
435 | 787 | for move_line_id in move_line_ids: | ||
436 | 788 | line_ids.remove(move_line_id) | ||
437 | 789 | if len(line_ids) > 1: | ||
438 | 790 | full = is_zero(move_line_obj.get_balance(cr, uid, line_ids)) | ||
439 | 791 | if full: | ||
440 | 792 | line_partial_ids = [] | ||
441 | 793 | else: | ||
442 | 794 | line_partial_ids = list(line_ids) | ||
443 | 795 | line_ids = [] | ||
444 | 796 | reconcile_obj.write( | ||
445 | 797 | cr, uid, reconcile.id, | ||
446 | 798 | { 'line_partial_ids': [(6, 0, line_partial_ids)], | ||
447 | 799 | 'line_id': [(6, 0, line_ids)], | ||
448 | 800 | }, context=context) | ||
449 | 801 | else: | ||
450 | 802 | reconcile_obj.unlink(cr, uid, reconcile.id, context=context) | ||
451 | 803 | for move_line in move_lines: | ||
452 | 804 | if move_line.invoice: | ||
453 | 805 | # reopening the invoice | ||
454 | 806 | netsvc.LocalService('workflow').trg_validate( | ||
455 | 807 | uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr) | ||
456 | 808 | return True | ||
457 | 809 | |||
458 | 810 | def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None): | ||
459 | 811 | """ | ||
460 | 812 | Legacy method to support upgrades older installations of the | ||
461 | 813 | interactive wizard branch. To be removed after 6.2 | ||
462 | 814 | clear up the writeoff move | ||
463 | 815 | """ | ||
464 | 816 | if transaction.writeoff_move_line_id: | ||
465 | 817 | move_pool = self.pool.get('account.move') | ||
466 | 818 | move_pool.button_cancel( | ||
467 | 819 | cr, uid, [transaction.writeoff_move_line_id.move_id.id], | ||
468 | 820 | context=context) | ||
469 | 821 | move_pool.unlink( | ||
470 | 822 | cr, uid, [transaction.writeoff_move_line_id.move_id.id], | ||
471 | 823 | context=context) | ||
472 | 824 | return True | ||
473 | 825 | |||
474 | 826 | def _legacy_cancel_move( | ||
475 | 827 | self, cr, uid, transaction, context=None): | ||
476 | 828 | """ | ||
477 | 829 | Legacy method to support upgrades from older installations | ||
478 | 830 | of the interactive wizard branch. | ||
479 | 831 | """ | ||
480 | 832 | >>>>>>> MERGE-SOURCE | ||
481 | 669 | currency = transaction.statement_line_id.statement_id.currency | 833 | currency = transaction.statement_line_id.statement_id.currency |
482 | 834 | <<<<<<< TREE | ||
483 | 670 | reconcile_id = ( | 835 | reconcile_id = ( |
484 | 671 | transaction.move_line_id.reconcile_id and | 836 | transaction.move_line_id.reconcile_id and |
485 | 672 | transaction.move_line_id.reconcile_id.id or | 837 | transaction.move_line_id.reconcile_id.id or |
486 | @@ -680,13 +845,42 @@ | |||
487 | 680 | break | 845 | break |
488 | 681 | line_ids = [st_line_line.id] | 846 | line_ids = [st_line_line.id] |
489 | 682 | # Add the write off line | 847 | # Add the write off line |
490 | 848 | ======= | ||
491 | 849 | line_ids = [transaction.move_line_id.id] | ||
492 | 850 | statement_line_obj = self.pool.get('account.bank.statement.line') | ||
493 | 851 | >>>>>>> MERGE-SOURCE | ||
494 | 683 | if transaction.writeoff_move_line_id: | 852 | if transaction.writeoff_move_line_id: |
495 | 684 | line_ids.append(transaction.writeoff_move_line_id.id) | 853 | line_ids.append(transaction.writeoff_move_line_id.id) |
497 | 685 | self._do_move_unreconcile( | 854 | self._legacy_do_move_unreconcile( |
498 | 686 | cr, uid, line_ids, currency, context=context) | 855 | cr, uid, line_ids, currency, context=context) |
499 | 687 | statement_line_obj.write( | 856 | statement_line_obj.write( |
500 | 688 | cr, uid, transaction.statement_line_id.id, | 857 | cr, uid, transaction.statement_line_id.id, |
501 | 689 | {'reconcile_id': False}, context=context) | 858 | {'reconcile_id': False}, context=context) |
502 | 859 | |||
503 | 860 | def _cancel_voucher( | ||
504 | 861 | self, cr, uid, transaction_id, context=None): | ||
505 | 862 | voucher_pool = self.pool.get('account.voucher') | ||
506 | 863 | transaction = self.browse(cr, uid, transaction_id, context=context) | ||
507 | 864 | st_line = transaction.statement_line_id | ||
508 | 865 | if transaction.match_type: | ||
509 | 866 | if st_line.voucher_id: | ||
510 | 867 | # Although vouchers can be associated with statement lines | ||
511 | 868 | # in standard OpenERP, we consider ourselves owner of the voucher | ||
512 | 869 | # if the line has an associated transaction | ||
513 | 870 | # Upon canceling of the statement line/transaction, | ||
514 | 871 | # we cancel and delete the vouchers. | ||
515 | 872 | # Otherwise, the statement line will leave the voucher | ||
516 | 873 | # unless the statement line itself is deleted. | ||
517 | 874 | voucher_pool.cancel_voucher( | ||
518 | 875 | cr, uid, [st_line.voucher_id.id], context=context) | ||
519 | 876 | voucher_pool.action_cancel_draft( | ||
520 | 877 | cr, uid, [st_line.voucher_id.id], context=context) | ||
521 | 878 | voucher_pool.unlink( | ||
522 | 879 | cr, uid, [st_line.voucher_id.id], context=context) | ||
523 | 880 | # Allow canceling of legacy entries | ||
524 | 881 | if not st_line.voucher_id and st_line.reconcile_id: | ||
525 | 882 | self._legacy_cancel_move(cr, uid, transaction, context=context) | ||
526 | 883 | |||
527 | 690 | return True | 884 | return True |
528 | 691 | 885 | ||
529 | 692 | def _cancel_storno( | 886 | def _cancel_storno( |
530 | @@ -714,11 +908,15 @@ | |||
531 | 714 | else: | 908 | else: |
532 | 715 | account_id = journal.default_debit_account_id.id | 909 | account_id = journal.default_debit_account_id.id |
533 | 716 | cancel_line = False | 910 | cancel_line = False |
535 | 717 | for line in transaction.statement_line_id.move_id.line_id: | 911 | move_lines = [] |
536 | 912 | for move in transaction.statement_line_id.move_ids: | ||
537 | 913 | # There should usually be just one move, I think | ||
538 | 914 | move_lines += move.line_id | ||
539 | 915 | for line in move_lines: | ||
540 | 718 | if line.account_id.id != account_id: | 916 | if line.account_id.id != account_id: |
541 | 719 | cancel_line = line | 917 | cancel_line = line |
542 | 720 | break | 918 | break |
544 | 721 | if not cancel_line: # debug | 919 | if not cancel_line: |
545 | 722 | raise osv.except_osv( | 920 | raise osv.except_osv( |
546 | 723 | _("Cannot cancel link with storno"), | 921 | _("Cannot cancel link with storno"), |
547 | 724 | _("Line id not found")) | 922 | _("Line id not found")) |
548 | @@ -744,16 +942,16 @@ | |||
549 | 744 | 942 | ||
550 | 745 | cancel_map = { | 943 | cancel_map = { |
551 | 746 | 'storno': _cancel_storno, | 944 | 'storno': _cancel_storno, |
555 | 747 | 'invoice': _cancel_move, | 945 | 'invoice': _cancel_voucher, |
556 | 748 | 'manual': _cancel_move, | 946 | 'manual': _cancel_voucher, |
557 | 749 | 'move': _cancel_move, | 947 | 'move': _cancel_voucher, |
558 | 750 | 'payment_order': _cancel_payment_order, | 948 | 'payment_order': _cancel_payment_order, |
559 | 751 | 'payment': _cancel_payment, | 949 | 'payment': _cancel_payment, |
560 | 752 | } | 950 | } |
561 | 951 | |||
562 | 753 | def cancel(self, cr, uid, ids, context=None): | 952 | def cancel(self, cr, uid, ids, context=None): |
563 | 754 | if ids and isinstance(ids, (int, float)): | 953 | if ids and isinstance(ids, (int, float)): |
564 | 755 | ids = [ids] | 954 | ids = [ids] |
565 | 756 | move_obj = self.pool.get('account.move') | ||
566 | 757 | for transaction in self.browse(cr, uid, ids, context): | 955 | for transaction in self.browse(cr, uid, ids, context): |
567 | 758 | if not transaction.match_type: | 956 | if not transaction.match_type: |
568 | 759 | continue | 957 | continue |
569 | @@ -763,31 +961,25 @@ | |||
570 | 763 | _("No method found to cancel this type")) | 961 | _("No method found to cancel this type")) |
571 | 764 | self.cancel_map[transaction.match_type]( | 962 | self.cancel_map[transaction.match_type]( |
572 | 765 | self, cr, uid, transaction.id, context) | 963 | self, cr, uid, transaction.id, context) |
581 | 766 | # clear up the writeoff move | 964 | self._legacy_clear_up_writeoff(cr, uid, transaction, context=context) |
574 | 767 | if transaction.writeoff_move_line_id: | ||
575 | 768 | move_obj.button_cancel( | ||
576 | 769 | cr, uid, [transaction.writeoff_move_line_id.move_id.id], | ||
577 | 770 | context=context) | ||
578 | 771 | move_obj.unlink( | ||
579 | 772 | cr, uid, [transaction.writeoff_move_line_id.move_id.id], | ||
580 | 773 | context=context) | ||
582 | 774 | return True | 965 | return True |
583 | 775 | 966 | ||
591 | 776 | reconcile_map = { | 967 | confirm_map = { |
592 | 777 | 'storno': _reconcile_storno, | 968 | 'storno': _confirm_storno, |
593 | 778 | 'invoice': _reconcile_move, | 969 | 'invoice': _confirm_move, |
594 | 779 | 'manual': _reconcile_move, | 970 | 'manual': _confirm_move, |
595 | 780 | 'payment_order': _reconcile_payment_order, | 971 | 'payment_order': _confirm_payment_order, |
596 | 781 | 'payment': _reconcile_payment, | 972 | 'payment': _confirm_payment, |
597 | 782 | 'move': _reconcile_move, | 973 | 'move': _confirm_move, |
598 | 783 | } | 974 | } |
600 | 784 | def reconcile(self, cr, uid, ids, context=None): | 975 | |
601 | 976 | def confirm(self, cr, uid, ids, context=None): | ||
602 | 785 | if ids and isinstance(ids, (int, float)): | 977 | if ids and isinstance(ids, (int, float)): |
603 | 786 | ids = [ids] | 978 | ids = [ids] |
604 | 787 | for transaction in self.browse(cr, uid, ids, context): | 979 | for transaction in self.browse(cr, uid, ids, context): |
605 | 788 | if not transaction.match_type: | 980 | if not transaction.match_type: |
606 | 789 | continue | 981 | continue |
608 | 790 | if transaction.match_type not in self.reconcile_map: | 982 | if transaction.match_type not in self.confirm_map: |
609 | 791 | raise osv.except_osv( | 983 | raise osv.except_osv( |
610 | 792 | _("Cannot reconcile"), | 984 | _("Cannot reconcile"), |
611 | 793 | _("Cannot reconcile type %s. No method found to " + | 985 | _("Cannot reconcile type %s. No method found to " + |
612 | @@ -802,19 +994,11 @@ | |||
613 | 802 | "this match type.") % | 994 | "this match type.") % |
614 | 803 | transaction.statement_line_id.name | 995 | transaction.statement_line_id.name |
615 | 804 | ) | 996 | ) |
620 | 805 | self._generate_writeoff_move( | 997 | # Generalize this bit and move to the confirmation |
621 | 806 | cr, uid, transaction.id, context=context) | 998 | # methods that actually do create a voucher? |
622 | 807 | # run the method that is appropriate for this match type | 999 | self.confirm_map[transaction.match_type]( |
619 | 808 | reconcile_id = self.reconcile_map[transaction.match_type]( | ||
623 | 809 | self, cr, uid, transaction.id, context) | 1000 | self, cr, uid, transaction.id, context) |
624 | 810 | self.pool.get('account.bank.statement.line').write( | ||
625 | 811 | cr, uid, transaction.statement_line_id.id, | ||
626 | 812 | {'reconcile_id': reconcile_id}, context=context) | ||
627 | 813 | 1001 | ||
628 | 814 | # TODO | ||
629 | 815 | # update the statement line bank account reference | ||
630 | 816 | # as follows (from _match_invoice) | ||
631 | 817 | |||
632 | 818 | """ | 1002 | """ |
633 | 819 | account_ids = [ | 1003 | account_ids = [ |
634 | 820 | x.id for x in bank_account_ids | 1004 | x.id for x in bank_account_ids |
635 | @@ -822,64 +1006,7 @@ | |||
636 | 822 | ][0] | 1006 | ][0] |
637 | 823 | """ | 1007 | """ |
638 | 824 | return True | 1008 | return True |
697 | 825 | 1009 | ||
640 | 826 | |||
641 | 827 | def _generate_writeoff_move(self, cr, uid, ids, context): | ||
642 | 828 | if ids and isinstance(ids, (int, float)): | ||
643 | 829 | ids = [ids] | ||
644 | 830 | move_line_obj = self.pool.get('account.move.line') | ||
645 | 831 | move_obj = self.pool.get('account.move') | ||
646 | 832 | for trans in self.browse(cr, uid, ids, context=context): | ||
647 | 833 | # Get the period for the company and date | ||
648 | 834 | ctxt = context.copy() | ||
649 | 835 | ctxt['company_id'] = trans.company_id.id | ||
650 | 836 | periods = self.pool.get('account.period').find( | ||
651 | 837 | cr, uid, trans.statement_line_id.date, context=ctxt) | ||
652 | 838 | period_id = periods and periods[0] or False | ||
653 | 839 | |||
654 | 840 | move_id = move_obj.create(cr, uid, { | ||
655 | 841 | 'journal_id': trans.writeoff_journal_id.id, | ||
656 | 842 | 'period_id': period_id, | ||
657 | 843 | 'date': trans.statement_line_id.date, | ||
658 | 844 | 'name': '(write-off) %s' % ( | ||
659 | 845 | trans.move_line_id.move_id.name or ''), | ||
660 | 846 | }, context=context) | ||
661 | 847 | if trans.residual > 0: | ||
662 | 848 | writeoff_debit = trans.residual | ||
663 | 849 | writeoff_credit = False | ||
664 | 850 | else: | ||
665 | 851 | writeoff_debit = False | ||
666 | 852 | writeoff_credit = - trans.residual | ||
667 | 853 | vals = { | ||
668 | 854 | 'name': trans.statement_line_id.name, | ||
669 | 855 | 'date': trans.statement_line_id.date, | ||
670 | 856 | 'ref': trans.statement_line_id.ref, | ||
671 | 857 | 'move_id': move_id, | ||
672 | 858 | 'partner_id': (trans.statement_line_id.partner_id and | ||
673 | 859 | trans.statement_line_id.partner_id.id or False), | ||
674 | 860 | 'account_id': trans.statement_line_id.account_id.id, | ||
675 | 861 | 'credit': writeoff_debit, | ||
676 | 862 | 'debit': writeoff_credit, | ||
677 | 863 | 'journal_id': trans.writeoff_journal_id.id, | ||
678 | 864 | 'period_id': period_id, | ||
679 | 865 | 'currency_id': trans.statement_line_id.statement_id.currency.id, | ||
680 | 866 | 'analytic_account_id': trans.writeoff_analytic_id.id, | ||
681 | 867 | } | ||
682 | 868 | move_line_id = move_line_obj.create( | ||
683 | 869 | cr, uid, vals, context=context) | ||
684 | 870 | self.write( | ||
685 | 871 | cr, uid, trans.id, | ||
686 | 872 | {'writeoff_move_line_id': move_line_id}, context=context) | ||
687 | 873 | vals.update({ | ||
688 | 874 | 'account_id': trans.writeoff_account_id.id, | ||
689 | 875 | 'credit': writeoff_credit, | ||
690 | 876 | 'debit': writeoff_debit, | ||
691 | 877 | }) | ||
692 | 878 | move_line_obj.create( | ||
693 | 879 | cr, uid, vals, context=context) | ||
694 | 880 | move_obj.post( | ||
695 | 881 | cr, uid, [move_id], context=context) | ||
696 | 882 | |||
698 | 883 | def _match_storno( | 1010 | def _match_storno( |
699 | 884 | self, cr, uid, trans, log, context=None): | 1011 | self, cr, uid, trans, log, context=None): |
700 | 885 | payment_line_obj = self.pool.get('payment.line') | 1012 | payment_line_obj = self.pool.get('payment.line') |
701 | @@ -1251,7 +1378,7 @@ | |||
702 | 1251 | provision_costs_description = False, | 1378 | provision_costs_description = False, |
703 | 1252 | ), context=context) | 1379 | ), context=context) |
704 | 1253 | # rebrowse the current record after writing | 1380 | # rebrowse the current record after writing |
706 | 1254 | transaction=self.browse(cr, uid, transaction.id, context=context) | 1381 | transaction = self.browse(cr, uid, transaction.id, context=context) |
707 | 1255 | # Match full direct debit orders | 1382 | # Match full direct debit orders |
708 | 1256 | if transaction.type == bt.DIRECT_DEBIT: | 1383 | if transaction.type == bt.DIRECT_DEBIT: |
709 | 1257 | move_info = self._match_debit_order( | 1384 | move_info = self._match_debit_order( |
710 | @@ -1476,10 +1603,15 @@ | |||
711 | 1476 | """ | 1603 | """ |
712 | 1477 | if not ids: | 1604 | if not ids: |
713 | 1478 | return {} | 1605 | return {} |
715 | 1479 | res = {} | 1606 | res = dict([(x, False) for x in ids]) |
716 | 1480 | for transaction in self.browse(cr, uid, ids, context): | 1607 | for transaction in self.browse(cr, uid, ids, context): |
719 | 1481 | res[transaction.id] = abs(transaction.transferred_amount) - abs(transaction.move_currency_amount) | 1608 | res[transaction.id] = ( |
720 | 1482 | 1609 | not(transaction.move_currency_amount is False) | |
721 | 1610 | and ( | ||
722 | 1611 | transaction.transferred_amount - | ||
723 | 1612 | transaction.move_currency_amount | ||
724 | 1613 | ) | ||
725 | 1614 | or False) | ||
726 | 1483 | return res | 1615 | return res |
727 | 1484 | 1616 | ||
728 | 1485 | def _get_match_multi(self, cr, uid, ids, name, args, context=None): | 1617 | def _get_match_multi(self, cr, uid, ids, name, args, context=None): |
729 | @@ -1530,12 +1662,11 @@ | |||
730 | 1530 | This will be used to calculate the write-off amount (in statement currency). | 1662 | This will be used to calculate the write-off amount (in statement currency). |
731 | 1531 | """ | 1663 | """ |
732 | 1532 | if not ids: | 1664 | if not ids: |
734 | 1533 | return {} | 1665 | return {} |
735 | 1666 | res = dict([(x, False) for x in ids]) | ||
736 | 1534 | 1667 | ||
737 | 1535 | stline_pool = self.pool.get('account.bank.statement.line') | 1668 | stline_pool = self.pool.get('account.bank.statement.line') |
738 | 1536 | 1669 | ||
739 | 1537 | res = {} | ||
740 | 1538 | |||
741 | 1539 | for transaction in self.browse(cr, uid, ids, context): | 1670 | for transaction in self.browse(cr, uid, ids, context): |
742 | 1540 | 1671 | ||
743 | 1541 | if transaction.move_line_id: | 1672 | if transaction.move_line_id: |
744 | @@ -1632,15 +1763,25 @@ | |||
745 | 1632 | 'invoice_id', 'transaction_id', 'Matching invoices'), | 1763 | 'invoice_id', 'transaction_id', 'Matching invoices'), |
746 | 1633 | 'invoice_id': fields.many2one( | 1764 | 'invoice_id': fields.many2one( |
747 | 1634 | 'account.invoice', 'Invoice to reconcile'), | 1765 | 'account.invoice', 'Invoice to reconcile'), |
748 | 1635 | 'payment_line_id': fields.many2one('payment.line', 'Payment line'), | ||
749 | 1636 | 'residual': fields.function( | 1766 | 'residual': fields.function( |
750 | 1637 | _get_residual, method=True, string='Residual', type='float'), | 1767 | _get_residual, method=True, string='Residual', type='float'), |
751 | 1638 | 'writeoff_account_id': fields.many2one( | 1768 | 'writeoff_account_id': fields.many2one( |
752 | 1639 | 'account.account', 'Write-off account', | 1769 | 'account.account', 'Write-off account', |
753 | 1640 | domain=[('type', '!=', 'view')]), | 1770 | domain=[('type', '!=', 'view')]), |
756 | 1641 | 'payment_option':fields.selection([('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')], 'Payment Difference', | 1771 | 'payment_option':fields.selection( |
757 | 1642 | required=True, help="This field helps you to choose what you want to do with the eventual difference between the paid amount and the sum of allocated amounts. You can either choose to keep open this difference on the partner's account, or reconcile it with the payment(s)"), | 1772 | [ |
758 | 1773 | ('without_writeoff', 'Keep Open'), | ||
759 | 1774 | ('with_writeoff', 'Reconcile Payment Balance') | ||
760 | 1775 | ], 'Payment Difference', | ||
761 | 1776 | required=True, | ||
762 | 1777 | help=("This field helps you to choose what you want to do with " | ||
763 | 1778 | "the eventual difference between the paid amount and the " | ||
764 | 1779 | "sum of allocated amounts. You can either choose to keep " | ||
765 | 1780 | "open this difference on the partner's account, " | ||
766 | 1781 | "or reconcile it with the payment(s)"), | ||
767 | 1782 | ), | ||
768 | 1643 | 'writeoff_amount': fields.float('Difference Amount'), | 1783 | 'writeoff_amount': fields.float('Difference Amount'), |
769 | 1784 | # Legacy field: to be removed after 6.2 | ||
770 | 1644 | 'writeoff_move_line_id': fields.many2one( | 1785 | 'writeoff_move_line_id': fields.many2one( |
771 | 1645 | 'account.move.line', 'Write off move line'), | 1786 | 'account.move.line', 'Write off move line'), |
772 | 1646 | 'writeoff_analytic_id': fields.many2one( | 1787 | 'writeoff_analytic_id': fields.many2one( |
773 | @@ -1668,8 +1809,9 @@ | |||
774 | 1668 | 'import_transaction_id', 'match_multi', type='boolean', | 1809 | 'import_transaction_id', 'match_multi', type='boolean', |
775 | 1669 | string='Multi match', readonly=True), | 1810 | string='Multi match', readonly=True), |
776 | 1670 | 'residual': fields.related( | 1811 | 'residual': fields.related( |
779 | 1671 | 'import_transaction_id', 'residual', type='float', | 1812 | 'import_transaction_id', 'residual', type='float', |
780 | 1672 | string='Residual'), | 1813 | string='Residual', readonly=True, |
781 | 1814 | ), | ||
782 | 1673 | 'duplicate': fields.related( | 1815 | 'duplicate': fields.related( |
783 | 1674 | 'import_transaction_id', 'duplicate', type='boolean', | 1816 | 'import_transaction_id', 'duplicate', type='boolean', |
784 | 1675 | string='Possible duplicate import', readonly=True), | 1817 | string='Possible duplicate import', readonly=True), |
785 | @@ -1680,16 +1822,9 @@ | |||
786 | 1680 | ('payment_order', 'Payment order'), | 1822 | ('payment_order', 'Payment order'), |
787 | 1681 | ('storno', 'Storno')], | 1823 | ('storno', 'Storno')], |
788 | 1682 | string='Match type', readonly=True,), | 1824 | string='Match type', readonly=True,), |
789 | 1683 | 'residual': fields.related( | ||
790 | 1684 | 'import_transaction_id', 'residual', type='float', | ||
791 | 1685 | string='Residual', readonly=True, | ||
792 | 1686 | ), | ||
793 | 1687 | 'state': fields.selection( | 1825 | 'state': fields.selection( |
794 | 1688 | [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', | 1826 | [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', |
795 | 1689 | readonly=True, required=True), | 1827 | readonly=True, required=True), |
796 | 1690 | 'move_id': fields.many2one( | ||
797 | 1691 | 'account.move', 'Move', readonly=True, | ||
798 | 1692 | help="The accounting move associated with this line"), | ||
799 | 1693 | } | 1828 | } |
800 | 1694 | 1829 | ||
801 | 1695 | _defaults = { | 1830 | _defaults = { |
802 | @@ -1710,8 +1845,9 @@ | |||
803 | 1710 | res = wizard_obj.create_act_window(cr, uid, res_id, context=context) | 1845 | res = wizard_obj.create_act_window(cr, uid, res_id, context=context) |
804 | 1711 | return res | 1846 | return res |
805 | 1712 | 1847 | ||
808 | 1713 | 1848 | def _convert_currency( | |
809 | 1714 | def _convert_currency(self, cr, uid, from_curr_id, to_curr_id, from_amount, round=False, date=None, context=None): | 1849 | self, cr, uid, from_curr_id, to_curr_id, from_amount, |
810 | 1850 | round=False, date=None, context=None): | ||
811 | 1715 | """Convert currency amount using the company rate on a specific date""" | 1851 | """Convert currency amount using the company rate on a specific date""" |
812 | 1716 | curr_obj = self.pool.get('res.currency') | 1852 | curr_obj = self.pool.get('res.currency') |
813 | 1717 | if context: | 1853 | if context: |
814 | @@ -1721,10 +1857,11 @@ | |||
815 | 1721 | if date: | 1857 | if date: |
816 | 1722 | ctxt["date"] = date | 1858 | ctxt["date"] = date |
817 | 1723 | 1859 | ||
819 | 1724 | amount = curr_obj.compute(cr, uid, from_curr_id, to_curr_id, from_amount, round=round, context=ctxt) | 1860 | amount = curr_obj.compute( |
820 | 1861 | cr, uid, from_curr_id, to_curr_id, from_amount, | ||
821 | 1862 | round=round, context=ctxt) | ||
822 | 1725 | return amount | 1863 | return amount |
823 | 1726 | 1864 | ||
824 | 1727 | |||
825 | 1728 | def confirm(self, cr, uid, ids, context=None): | 1865 | def confirm(self, cr, uid, ids, context=None): |
826 | 1729 | """ | 1866 | """ |
827 | 1730 | Create (or update) a voucher for each statement line, and then generate | 1867 | Create (or update) a voucher for each statement line, and then generate |
828 | @@ -1732,10 +1869,10 @@ | |||
829 | 1732 | If a line does not have a move line against it, but has an account, then | 1869 | If a line does not have a move line against it, but has an account, then |
830 | 1733 | generate a journal entry that moves the line amount to the specified account. | 1870 | generate a journal entry that moves the line amount to the specified account. |
831 | 1734 | """ | 1871 | """ |
832 | 1735 | voucher_pool = self.pool.get('account.voucher') | ||
833 | 1736 | statement_pool = self.pool.get('account.bank.statement') | 1872 | statement_pool = self.pool.get('account.bank.statement') |
834 | 1737 | obj_seq = self.pool.get('ir.sequence') | 1873 | obj_seq = self.pool.get('ir.sequence') |
835 | 1738 | move_pool = self.pool.get('account.move') | 1874 | move_pool = self.pool.get('account.move') |
836 | 1875 | import_transaction_obj = self.pool.get('banking.import.transaction') | ||
837 | 1739 | 1876 | ||
838 | 1740 | for st_line in self.browse(cr, uid, ids, context): | 1877 | for st_line in self.browse(cr, uid, ids, context): |
839 | 1741 | if st_line.state != 'draft': | 1878 | if st_line.state != 'draft': |
840 | @@ -1754,157 +1891,47 @@ | |||
841 | 1754 | "journal!") % (st_line.statement_id.journal_id.name,)) | 1891 | "journal!") % (st_line.statement_id.journal_id.name,)) |
842 | 1755 | if not st_line.amount: | 1892 | if not st_line.amount: |
843 | 1756 | continue | 1893 | continue |
845 | 1757 | 1894 | if not st_line.period_id: | |
846 | 1895 | self.write( | ||
847 | 1896 | cr, uid, [st_line.id], { | ||
848 | 1897 | 'period_id': self._get_period( | ||
849 | 1898 | cr, uid, {'date': st_line.date}) | ||
850 | 1899 | }) | ||
851 | 1900 | st_line.refresh() | ||
852 | 1758 | # Generate the statement number, if it is not already done | 1901 | # Generate the statement number, if it is not already done |
853 | 1759 | st = st_line.statement_id | 1902 | st = st_line.statement_id |
854 | 1760 | if not st.name == '/': | 1903 | if not st.name == '/': |
855 | 1761 | st_number = st.name | 1904 | st_number = st.name |
856 | 1762 | else: | 1905 | else: |
857 | 1763 | if st.journal_id.sequence_id: | 1906 | if st.journal_id.sequence_id: |
859 | 1764 | c = {'fiscalyear_id': st.period_id.fiscalyear_id.id} | 1907 | period = st.period_id or st_line.period_id |
860 | 1908 | c = {'fiscalyear_id': period.fiscalyear_id.id} | ||
861 | 1765 | st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c) | 1909 | st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c) |
862 | 1766 | else: | 1910 | else: |
863 | 1767 | st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement') | 1911 | st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement') |
882 | 1768 | statement_obj.write(cr, uid, [st.id], {'name': st_number}, context=context) | 1912 | statement_pool.write(cr, uid, [st.id], {'name': st_number}, context=context) |
883 | 1769 | 1913 | ||
884 | 1770 | # Check if this line has been matched against a journal item | 1914 | if st_line.import_transaction_id: |
885 | 1771 | if st_line.import_transaction_id.move_line_id: | 1915 | import_transaction_obj.confirm( |
886 | 1772 | # Line has been matched, so post it via a voucher | 1916 | cr, uid, st_line.import_transaction_id.id, context) |
887 | 1773 | self._post_with_voucher(cr, uid, ids, st_line, voucher_pool, move_pool, context=context) | 1917 | st_line.refresh() |
888 | 1774 | 1918 | st_line_number = statement_pool.get_next_st_line_number( | |
889 | 1775 | else: | 1919 | cr, uid, st_number, st_line, context) |
890 | 1776 | # Check to see if the line has an account that can be used to generate a journal entry | 1920 | company_currency_id = st.journal_id.company_id.currency_id.id |
891 | 1777 | if st_line.account_id: | 1921 | statement_pool.create_move_from_st_line( |
892 | 1778 | # Generate a journal for the entry using the standard bank statement code | 1922 | cr, uid, st_line.id, company_currency_id, st_line_number, context) |
893 | 1779 | self._create_move(cr, uid, st_line, statement_pool, st, st_number, context=context) | 1923 | self.write( |
894 | 1780 | else: | 1924 | cr, uid, st_line.id, {'state': 'confirmed'}, context) |
877 | 1781 | raise osv.except_osv( | ||
878 | 1782 | _('Statement line has no account'), | ||
879 | 1783 | _("You cannot confirm a bank statement line that has no account against it (%s.%s)") % | ||
880 | 1784 | (st_line.statement_id.name, st_line.name,)) | ||
881 | 1785 | |||
895 | 1786 | return True | 1925 | return True |
896 | 1787 | 1926 | ||
897 | 1788 | def _create_move(self, cr, uid, st_line, statement_pool, st, st_number, context): | ||
898 | 1789 | """ | ||
899 | 1790 | The line is not matched against a move, but the account has been defined for the line. | ||
900 | 1791 | Generate a journal entry for the statement line that transfers the full amount against the account. | ||
901 | 1792 | """ | ||
902 | 1793 | st_line_number = statement_pool.get_next_st_line_number(cr, uid, st_number, st_line, context) | ||
903 | 1794 | company_currency_id = st.journal_id.company_id.currency_id.id | ||
904 | 1795 | move_id = statement_pool.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context) | ||
905 | 1796 | self.write(cr, uid, st_line.id, {'state': 'confirmed', 'move_id': move_id}, context) | ||
906 | 1797 | |||
907 | 1798 | |||
908 | 1799 | def _post_with_voucher(self, cr, uid, ids, st_line, voucher_pool, move_pool, context): | ||
909 | 1800 | # Check if a voucher has already been created | ||
910 | 1801 | if st_line.voucher_id: | ||
911 | 1802 | # There's an existing voucher on the statement line which was probably created | ||
912 | 1803 | # manually. This may have been done because it was a single payment for multiple | ||
913 | 1804 | # invoices. Just get the voucher ID. | ||
914 | 1805 | voucher_id = st_line.voucher_id.id | ||
915 | 1806 | else: | ||
916 | 1807 | # Create a voucher and store the ID on the statement line | ||
917 | 1808 | voucher_id = self._create_voucher(cr, uid, ids, st_line, context=context) | ||
918 | 1809 | self.pool.get('account.bank.statement.line').write(cr,uid,st_line.id,{'voucher_id':voucher_id} , context=context) | ||
919 | 1810 | |||
920 | 1811 | # If the voucher is in draft mode, then post it | ||
921 | 1812 | voucher = voucher_pool.browse(cr, uid, voucher_id, context=context) | ||
922 | 1813 | if voucher.state in ('draft','proforma'): | ||
923 | 1814 | voucher.action_move_line_create() | ||
924 | 1815 | |||
925 | 1816 | # Update the statement line to indicate that it has been posted | ||
926 | 1817 | # ... no longer need to set the move_id on the voucher? | ||
927 | 1818 | self.write(cr, uid, st_line.id, {'state': 'confirmed'}, context) | ||
928 | 1819 | |||
929 | 1820 | # The voucher journal isn't automatically posted, so post it (if needed) | ||
930 | 1821 | if not voucher.journal_id.entry_posted: | ||
931 | 1822 | voucher = voucher_pool.browse(cr, uid, voucher_id, context=context) | ||
932 | 1823 | move_pool.post(cr, uid, [voucher.move_id.id], context={}) | ||
933 | 1824 | |||
934 | 1825 | |||
935 | 1826 | def _create_voucher(self, cr, uid, ids, st_line, context): | ||
936 | 1827 | """ | ||
937 | 1828 | The line is matched against a move (invoice), so generate a payment voucher with the write-off settings that the | ||
938 | 1829 | user requested. The move lines will be generated by the voucher, handling rounding and currency conversion. | ||
939 | 1830 | """ | ||
940 | 1831 | journal = st_line.statement_id.journal_id | ||
941 | 1832 | if st_line.amount < 0.0: | ||
942 | 1833 | voucher_type = 'payment' | ||
943 | 1834 | account_id = journal.default_debit_account_id and journal.default_debit_account_id.id or False | ||
944 | 1835 | else: | ||
945 | 1836 | voucher_type = 'receipt' | ||
946 | 1837 | account_id = journal.default_credit_account_id and journal.default_credit_account_id.id or False | ||
947 | 1838 | |||
948 | 1839 | # Use the statement line's date determine the period | ||
949 | 1840 | ctxt = context.copy() | ||
950 | 1841 | ctxt['company_id'] = st_line.company_id.id | ||
951 | 1842 | if 'period_id' in ctxt: | ||
952 | 1843 | del ctxt['period_id'] | ||
953 | 1844 | period_id = self.pool.get('account.period').find(cr, uid, st_line.date, context=ctxt)[0] | ||
954 | 1845 | |||
955 | 1846 | # Convert the move line amount to the journal currency | ||
956 | 1847 | move_line_amount = st_line.import_transaction_id.move_line_id.amount_residual_currency | ||
957 | 1848 | to_curr_id = st_line.statement_id.journal_id.currency and st_line.statement_id.journal_id.currency.id or st_line.statement_id.company_id.currency_id.id | ||
958 | 1849 | from_curr_id = st_line.import_transaction_id.move_line_id.currency_id and st_line.import_transaction_id.move_line_id.currency_id.id or st_line.statement_id.company_id.currency_id.id | ||
959 | 1850 | if from_curr_id != to_curr_id: | ||
960 | 1851 | amount_currency = self._convert_currency(cr, uid, from_curr_id, to_curr_id, move_line_amount, round=True, | ||
961 | 1852 | date=time.strftime('%Y-%m-%d'), context=context) | ||
962 | 1853 | else: | ||
963 | 1854 | amount_currency = move_line_amount | ||
964 | 1855 | |||
965 | 1856 | # Check whether this is a full or partial reconciliation | ||
966 | 1857 | if st_line.import_transaction_id.payment_option=='with_writeoff': | ||
967 | 1858 | writeoff = abs(st_line.amount)-abs(amount_currency) | ||
968 | 1859 | line_amount = abs(amount_currency) | ||
969 | 1860 | else: | ||
970 | 1861 | writeoff = 0.0 | ||
971 | 1862 | line_amount = abs(st_line.amount) | ||
972 | 1863 | |||
973 | 1864 | # Define the voucher | ||
974 | 1865 | voucher = { | ||
975 | 1866 | 'journal_id': st_line.statement_id.journal_id.id, | ||
976 | 1867 | 'partner_id': st_line.partner_id and st_line.partner_id.id or False, | ||
977 | 1868 | 'company_id': st_line.company_id.id, | ||
978 | 1869 | 'type':voucher_type, | ||
979 | 1870 | 'company_id': st_line.company_id.id, | ||
980 | 1871 | 'account_id': account_id, | ||
981 | 1872 | 'amount': abs(st_line.amount), | ||
982 | 1873 | 'writeoff_amount': writeoff, | ||
983 | 1874 | 'payment_option': st_line.import_transaction_id.payment_option, | ||
984 | 1875 | 'writeoff_acc_id': st_line.import_transaction_id.writeoff_account_id.id, | ||
985 | 1876 | 'analytic_id': st_line.import_transaction_id.writeoff_analytic_id.id, | ||
986 | 1877 | 'date': st_line.date, | ||
987 | 1878 | 'date_due': st_line.date, | ||
988 | 1879 | 'period_id': period_id, | ||
989 | 1880 | 'payment_rate_currency_id':to_curr_id, | ||
990 | 1881 | } | ||
991 | 1882 | |||
992 | 1883 | # Define the voucher line | ||
993 | 1884 | vch_line = { | ||
994 | 1885 | #'voucher_id': v_id, | ||
995 | 1886 | 'move_line_id': st_line.import_transaction_id.move_line_id.id, | ||
996 | 1887 | 'reconcile': True, | ||
997 | 1888 | 'amount': line_amount, | ||
998 | 1889 | 'account_id': st_line.import_transaction_id.move_line_id.account_id.id, | ||
999 | 1890 | 'type': st_line.import_transaction_id.move_line_id.credit and 'dr' or 'cr', | ||
1000 | 1891 | } | ||
1001 | 1892 | voucher['line_ids'] = [(0,0,vch_line)] | ||
1002 | 1893 | v_id = self.pool.get('account.voucher').create(cr, uid, voucher, context=context) | ||
1003 | 1894 | |||
1004 | 1895 | return v_id | ||
1005 | 1896 | |||
1006 | 1897 | |||
1007 | 1898 | def cancel(self, cr, uid, ids, context=None): | 1927 | def cancel(self, cr, uid, ids, context=None): |
1008 | 1899 | if ids and isinstance(ids, (int, float)): | 1928 | if ids and isinstance(ids, (int, float)): |
1009 | 1900 | ids = [ids] | 1929 | ids = [ids] |
1010 | 1901 | account_move_obj = self.pool.get('account.move') | ||
1011 | 1902 | import_transaction_obj = self.pool.get('banking.import.transaction') | 1930 | import_transaction_obj = self.pool.get('banking.import.transaction') |
1013 | 1903 | voucher_pool = self.pool.get('account.voucher') | 1931 | move_pool = self.pool.get('account.move') |
1014 | 1904 | transaction_cancel_ids = [] | 1932 | transaction_cancel_ids = [] |
1016 | 1905 | voucher_cancel_ids = [] | 1933 | set_draft_ids = [] |
1017 | 1906 | move_unlink_ids = [] | 1934 | move_unlink_ids = [] |
1018 | 1907 | set_draft_ids = [] | ||
1019 | 1908 | # harvest ids for various actions | 1935 | # harvest ids for various actions |
1020 | 1909 | for st_line in self.browse(cr, uid, ids, context): | 1936 | for st_line in self.browse(cr, uid, ids, context): |
1021 | 1910 | if st_line.state != 'confirmed': | 1937 | if st_line.state != 'confirmed': |
1022 | @@ -1915,32 +1942,23 @@ | |||
1023 | 1915 | _("The bank statement that this transaction belongs to has " | 1942 | _("The bank statement that this transaction belongs to has " |
1024 | 1916 | "already been confirmed")) | 1943 | "already been confirmed")) |
1025 | 1917 | 1944 | ||
1040 | 1918 | # Check if the transaction has a voucher | 1945 | if st_line.import_transaction_id: |
1041 | 1919 | if st_line.voucher_id: | 1946 | # Cancel transaction immediately. |
1042 | 1920 | voucher_cancel_ids.append(st_line.voucher_id.id) | 1947 | # If it has voucher, this will clean up |
1043 | 1921 | else: | 1948 | # the moves on the st_line. |
1044 | 1922 | if st_line.import_transaction_id: | 1949 | import_transaction_obj.cancel( |
1045 | 1923 | transaction_cancel_ids.append(st_line.import_transaction_id.id) | 1950 | cr, uid, [st_line.import_transaction_id.id], context=context) |
1046 | 1924 | if st_line.move_id: | 1951 | st_line.refresh() |
1047 | 1925 | move_unlink_ids.append(st_line.move_id.id) | 1952 | for line in st_line.move_ids: |
1048 | 1926 | else: | 1953 | # We allow for people canceling and removing |
1049 | 1927 | raise osv.except_osv( | 1954 | # the associated payments, which can lead to confirmed |
1050 | 1928 | _("Cannot cancel bank transaction"), | 1955 | # statement lines without an associated move |
1051 | 1929 | _("Cannot cancel this bank transaction. The information " | 1956 | move_unlink_ids.append(line.id) |
1038 | 1930 | "needed to undo the accounting entries has not been " | ||
1039 | 1931 | "recorded")) | ||
1052 | 1932 | set_draft_ids.append(st_line.id) | 1957 | set_draft_ids.append(st_line.id) |
1053 | 1933 | 1958 | ||
1064 | 1934 | # Cancel and delete the vouchers | 1959 | move_pool.button_cancel( |
1065 | 1935 | voucher_pool.cancel_voucher(cr, uid, voucher_cancel_ids, context=context) | 1960 | cr, uid, move_unlink_ids, context=context) |
1066 | 1936 | voucher_pool.action_cancel_draft(cr, uid, voucher_cancel_ids, context=context) | 1961 | move_pool.unlink(cr, uid, move_unlink_ids, context=context) |
1057 | 1937 | voucher_pool.unlink(cr, uid, voucher_cancel_ids, context=context) | ||
1058 | 1938 | |||
1059 | 1939 | # Perform actions | ||
1060 | 1940 | import_transaction_obj.cancel( | ||
1061 | 1941 | cr, uid, transaction_cancel_ids, context=context) | ||
1062 | 1942 | account_move_obj.button_cancel(cr, uid, move_unlink_ids, context) | ||
1063 | 1943 | account_move_obj.unlink(cr, uid, move_unlink_ids, context) | ||
1067 | 1944 | self.write( | 1962 | self.write( |
1068 | 1945 | cr, uid, set_draft_ids, {'state': 'draft'}, context=context) | 1963 | cr, uid, set_draft_ids, {'state': 'draft'}, context=context) |
1069 | 1946 | return True | 1964 | return True |
1070 | @@ -1954,8 +1972,12 @@ | |||
1071 | 1954 | ids = [ids] | 1972 | ids = [ids] |
1072 | 1955 | for line in self.browse(cr, uid, ids, context=context): | 1973 | for line in self.browse(cr, uid, ids, context=context): |
1073 | 1956 | if line.state == 'confirmed': | 1974 | if line.state == 'confirmed': |
1076 | 1957 | raise osv.except_osv(_('Confirmed Statement Line'), _("You cannot delete a confirmed Statement Line: '%s'" % line.name)) | 1975 | raise osv.except_osv( |
1077 | 1958 | return super(account_bank_statement_line,self).unlink(cr, uid, ids, context=context) | 1976 | _('Confirmed Statement Line'), |
1078 | 1977 | _("You cannot delete a confirmed Statement Line" | ||
1079 | 1978 | ": '%s'" % line.name)) | ||
1080 | 1979 | return super(account_bank_statement_line, self).unlink( | ||
1081 | 1980 | cr, uid, ids, context=context) | ||
1082 | 1959 | 1981 | ||
1083 | 1960 | account_bank_statement_line() | 1982 | account_bank_statement_line() |
1084 | 1961 | 1983 | ||
1085 | @@ -2000,7 +2022,7 @@ | |||
1086 | 2000 | 2022 | ||
1087 | 2001 | # protect against misguided manual changes | 2023 | # protect against misguided manual changes |
1088 | 2002 | for line in st.move_line_ids: | 2024 | for line in st.move_line_ids: |
1090 | 2003 | if line.state <> 'valid': | 2025 | if line.state != 'valid': |
1091 | 2004 | raise osv.except_osv(_('Error !'), | 2026 | raise osv.except_osv(_('Error !'), |
1092 | 2005 | _('The account entries lines are not in valid state.')) | 2027 | _('The account entries lines are not in valid state.')) |
1093 | 2006 | 2028 | ||
1094 | 2007 | 2029 | ||
1095 | === modified file 'account_banking/wizard/banking_transaction_wizard.py' | |||
1096 | --- account_banking/wizard/banking_transaction_wizard.py 2012-03-07 23:02:52 +0000 | |||
1097 | +++ account_banking/wizard/banking_transaction_wizard.py 2012-05-03 11:53:24 +0000 | |||
1098 | @@ -21,6 +21,7 @@ | |||
1099 | 21 | # | 21 | # |
1100 | 22 | ############################################################################## | 22 | ############################################################################## |
1101 | 23 | from osv import osv, fields | 23 | from osv import osv, fields |
1102 | 24 | from openerp.tools.translate import _ | ||
1103 | 24 | 25 | ||
1104 | 25 | """ | 26 | """ |
1105 | 26 | 27 | ||
1106 | @@ -38,7 +39,7 @@ | |||
1107 | 38 | """ | 39 | """ |
1108 | 39 | Return a popup window for this model | 40 | Return a popup window for this model |
1109 | 40 | """ | 41 | """ |
1111 | 41 | if isinstance(ids, (int,long)): | 42 | if isinstance(ids, (int, long)): |
1112 | 42 | ids = [ids] | 43 | ids = [ids] |
1113 | 43 | return { | 44 | return { |
1114 | 44 | 'name': self._description, | 45 | 'name': self._description, |
1115 | @@ -160,9 +161,7 @@ | |||
1116 | 160 | statement_line_obj = self.pool.get('account.bank.statement.line') | 161 | statement_line_obj = self.pool.get('account.bank.statement.line') |
1117 | 161 | for wiz in self.browse( | 162 | for wiz in self.browse( |
1118 | 162 | cr, uid, ids, context=context): | 163 | cr, uid, ids, context=context): |
1119 | 163 | invoice_ids = False | ||
1120 | 164 | move_line_id = False | 164 | move_line_id = False |
1121 | 165 | move_line_ids = False | ||
1122 | 166 | invoice_id = manual_invoice_id | 165 | invoice_id = manual_invoice_id |
1123 | 167 | if invoice_id: | 166 | if invoice_id: |
1124 | 168 | invoice = invoice_obj.browse( | 167 | invoice = invoice_obj.browse( |
1125 | 169 | 168 | ||
1126 | === modified file 'account_direct_debit/model/account_payment.py' | |||
1127 | --- account_direct_debit/model/account_payment.py 2012-01-12 10:58:49 +0000 | |||
1128 | +++ account_direct_debit/model/account_payment.py 2012-05-03 11:53:24 +0000 | |||
1129 | @@ -104,7 +104,6 @@ | |||
1130 | 104 | _("Cannot unreconcile"), | 104 | _("Cannot unreconcile"), |
1131 | 105 | _("Cannot unreconcile debit order: "+ | 105 | _("Cannot unreconcile debit order: "+ |
1132 | 106 | "Workflow will not allow it.")) | 106 | "Workflow will not allow it.")) |
1133 | 107 | |||
1134 | 108 | return True | 107 | return True |
1135 | 109 | 108 | ||
1136 | 110 | def test_undo_done(self, cr, uid, ids, context=None): | 109 | def test_undo_done(self, cr, uid, ids, context=None): |
1137 | 111 | 110 | ||
1138 | === modified file 'account_direct_debit/view/account_invoice.xml' | |||
1139 | --- account_direct_debit/view/account_invoice.xml 2011-12-21 13:06:26 +0000 | |||
1140 | +++ account_direct_debit/view/account_invoice.xml 2012-05-03 11:53:24 +0000 | |||
1141 | @@ -13,9 +13,9 @@ | |||
1142 | 13 | Maybe apply trick in fields_view_get instead, for | 13 | Maybe apply trick in fields_view_get instead, for |
1143 | 14 | better compatibility with other modules? | 14 | better compatibility with other modules? |
1144 | 15 | --> | 15 | --> |
1146 | 16 | <button name="invoice_open" position="attributes"> | 16 | <!-- button name="invoice_open" position="attributes"> |
1147 | 17 | <attribute name="states">draft,proforma2,debit_denied</attribute> | 17 | <attribute name="states">draft,proforma2,debit_denied</attribute> |
1149 | 18 | </button> | 18 | </button --> |
1150 | 19 | <button string='Re-Open' position="attributes"> | 19 | <button string='Re-Open' position="attributes"> |
1151 | 20 | <attribute name="states">paid,debit_denied</attribute> | 20 | <attribute name="states">paid,debit_denied</attribute> |
1152 | 21 | <!-- | 21 | <!-- |
1153 | 22 | 22 | ||
1154 | === modified file 'account_direct_debit/workflow/account_invoice.xml' | |||
1155 | --- account_direct_debit/workflow/account_invoice.xml 2011-12-21 13:06:26 +0000 | |||
1156 | +++ account_direct_debit/workflow/account_invoice.xml 2012-05-03 11:53:24 +0000 | |||
1157 | @@ -8,20 +8,44 @@ | |||
1158 | 8 | <field name="kind">function</field> | 8 | <field name="kind">function</field> |
1159 | 9 | </record> | 9 | </record> |
1160 | 10 | <record id="paid_to_debit_denied" model="workflow.transition"> | 10 | <record id="paid_to_debit_denied" model="workflow.transition"> |
1161 | 11 | <!-- | ||
1162 | 12 | Set an invoice to state debit denied, either manually | ||
1163 | 13 | or by confirming a bank statement line that constitutes | ||
1164 | 14 | a fatal storno | ||
1165 | 15 | --> | ||
1166 | 11 | <field name="act_from" ref="account.act_paid"/> | 16 | <field name="act_from" ref="account.act_paid"/> |
1167 | 12 | <field name="act_to" ref="act_debit_denied"/> | 17 | <field name="act_to" ref="act_debit_denied"/> |
1168 | 13 | <field name="signal">invoice_debit_denied</field> | 18 | <field name="signal">invoice_debit_denied</field> |
1169 | 14 | </record> | 19 | </record> |
1170 | 20 | <record id="open_test_to_debit_denied" model="workflow.transition"> | ||
1171 | 21 | <!-- | ||
1172 | 22 | A storno leads to unreconciling the move line, which | ||
1173 | 23 | reopens the invoice. We need to allow a transition from | ||
1174 | 24 | this state to the debit denied state if the storno is fatal. | ||
1175 | 25 | --> | ||
1176 | 26 | <field name="act_from" ref="account.act_open_test"/> | ||
1177 | 27 | <field name="act_to" ref="act_debit_denied"/> | ||
1178 | 28 | <field name="signal">invoice_debit_denied</field> | ||
1179 | 29 | </record> | ||
1180 | 15 | <record id="debit_denied_to_paid" model="workflow.transition"> | 30 | <record id="debit_denied_to_paid" model="workflow.transition"> |
1181 | 31 | <!-- | ||
1182 | 32 | Cancel a bank statement line that constitutes a fatal | ||
1183 | 33 | storno | ||
1184 | 34 | --> | ||
1185 | 16 | <field name="act_from" ref="act_debit_denied"/> | 35 | <field name="act_from" ref="act_debit_denied"/> |
1186 | 17 | <field name="act_to" ref="account.act_paid"/> | 36 | <field name="act_to" ref="account.act_paid"/> |
1187 | 18 | <field name="condition">test_undo_debit_denied()</field> | 37 | <field name="condition">test_undo_debit_denied()</field> |
1188 | 19 | <field name="signal">undo_debit_denied</field> | 38 | <field name="signal">undo_debit_denied</field> |
1189 | 20 | </record> | 39 | </record> |
1190 | 21 | <record id="debit_denied_to_open" model="workflow.transition"> | 40 | <record id="debit_denied_to_open" model="workflow.transition"> |
1191 | 41 | <!-- | ||
1192 | 42 | Allow the user to manually reset a debit denied status | ||
1193 | 43 | on a paid invoice (but only after manually unreconciling | ||
1194 | 44 | the invoice) | ||
1195 | 45 | --> | ||
1196 | 22 | <field name="act_from" ref="act_debit_denied"/> | 46 | <field name="act_from" ref="act_debit_denied"/> |
1199 | 23 | <field name="act_to" ref="account.act_open"/> | 47 | <field name="act_to" ref="account.act_open_test"/> |
1200 | 24 | <field name="signal">invoice_open</field> | 48 | <field name="signal">open_test</field> |
1201 | 25 | </record> | 49 | </record> |
1202 | 26 | </data> | 50 | </data> |
1203 | 27 | </openerp> | 51 | </openerp> |
Added two more fixes. Otherwise, tested succesfully.