Merge lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 into lp:banking-addons/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
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.

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

Added two more fixes. Otherwise, tested succesfully.

review: Needs Resubmitting

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account_banking/account_banking.py'
--- account_banking/account_banking.py 2012-04-14 09:16:54 +0000
+++ account_banking/account_banking.py 2012-05-03 11:53:24 +0000
@@ -58,13 +58,11 @@
58 Rejected payments from the bank receive on import the status 'rejected'.58 Rejected payments from the bank receive on import the status 'rejected'.
59'''59'''
60import time60import time
61import sys
62import sepa61import sepa
63from osv import osv, fields62from osv import osv, fields
64from tools.translate import _63from tools.translate import _
65from wizard.banktools import get_or_create_bank64from wizard.banktools import get_or_create_bank
66import decimal_precision as dp65import decimal_precision as dp
67import pooler
68import netsvc66import netsvc
69from openerp import SUPERUSER_ID67from openerp import SUPERUSER_ID
7068
@@ -322,6 +320,26 @@
322 # 'currency': _currency,320 # 'currency': _currency,
323 }321 }
324322
323 def _check_company_id(self, cr, uid, ids, context=None):
324 """
325 Adapt this constraint method from the account module to reflect the
326 move of period_id to the statement line
327 """
328 for statement in self.browse(cr, uid, ids, context=context):
329 if (statement.period_id and
330 statement.company_id.id != statement.period_id.company_id.id):
331 return False
332 for line in statement.line_ids:
333 if (line.period_id and
334 statement.company_id.id != line.period_id.company_id.id):
335 return False
336 return True
337
338 # Redefine the constraint, or it still refer to the original method
339 _constraints = [
340 (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
341 ]
342
325 def _get_period(self, cursor, uid, date, context=None):343 def _get_period(self, cursor, uid, date, context=None):
326 '''344 '''
327 Find matching period for date, not meant for _defaults.345 Find matching period for date, not meant for _defaults.
@@ -341,10 +359,12 @@
341 context=None):359 context=None):
342 # This is largely a copy of the original code in account360 # This is largely a copy of the original code in account
343 # Modifications are marked with AB361 # Modifications are marked with AB
362 # Modifications by account_voucher are merged below.
344 # As there is no valid inheritance mechanism for large actions, this363 # As there is no valid inheritance mechanism for large actions, this
345 # is the only option to add functionality to existing actions.364 # is the only option to add functionality to existing actions.
346 # WARNING: when the original code changes, this trigger has to be365 # WARNING: when the original code changes, this trigger has to be
347 # updated in sync.366 # updated in sync.
367
348 if context is None:368 if context is None:
349 context = {}369 context = {}
350 res_currency_obj = self.pool.get('res.currency')370 res_currency_obj = self.pool.get('res.currency')
@@ -352,8 +372,36 @@
352 account_move_line_obj = self.pool.get('account.move.line')372 account_move_line_obj = self.pool.get('account.move.line')
353 account_bank_statement_line_obj = self.pool.get(373 account_bank_statement_line_obj = self.pool.get(
354 'account.bank.statement.line')374 'account.bank.statement.line')
355 st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id,375 st_line = account_bank_statement_line_obj.browse(
356 context=context)376 cr, uid, st_line_id, context=context)
377 # Start account voucher
378 # Post the voucher and update links between statement and moves
379 if st_line.voucher_id:
380 voucher_pool = self.pool.get('account.voucher')
381 wf_service = netsvc.LocalService("workflow")
382 voucher_pool.write(
383 cr, uid, [st_line.voucher_id.id], {'number': st_line_number}, context=context)
384 if st_line.voucher_id.state == 'cancel':
385 voucher_pool.action_cancel_draft(
386 cr, uid, [st_line.voucher_id.id], context=context)
387 wf_service.trg_validate(
388 uid, 'account.voucher', st_line.voucher_id.id, 'proforma_voucher', cr)
389 v = voucher_pool.browse(
390 cr, uid, st_line.voucher_id.id, context=context)
391 account_bank_statement_line_obj.write(cr, uid, [st_line_id], {
392 'move_ids': [(4, v.move_id.id, False)]
393 })
394 account_move_line_obj.write(
395 cr, uid, [x.id for x in v.move_ids],
396 {'statement_id': st_line.statement_id.id}, context=context)
397 # End of account_voucher
398 st_line.refresh()
399
400 # AB: The voucher journal isn't automatically posted, so post it (if needed)
401 if not st_line.voucher_id.journal_id.entry_posted:
402 account_move_obj.post(cr, uid, [st_line.voucher_id.move_id.id], context={})
403 return True
404
357 st = st_line.statement_id405 st = st_line.statement_id
358406
359 context.update({'date': st_line.date})407 context.update({'date': st_line.date})
@@ -457,22 +505,23 @@
457 # Bank statements will not consider boolean on journal entry_posted505 # Bank statements will not consider boolean on journal entry_posted
458 account_move_obj.post(cr, uid, [move_id], context=context)506 account_move_obj.post(cr, uid, [move_id], context=context)
459 507
460 # Shouldn't now be needed as payment and reconciliation of invoices508 """
461 # is done through account_voucher509 Account-banking:
462 #""" 510 - Write stored reconcile_id
463 #Account-banking:511 - Pay invoices through workflow
464 #- Write stored reconcile_id512
465 #- Pay invoices through workflow 513 Does not apply to voucher integration, but only to
466 #"""514 payments and payment orders
467 #if st_line.reconcile_id:515 """
468 # account_move_line_obj.write(cr, uid, torec, {516 if st_line.reconcile_id:
469 # (st_line.reconcile_id.line_partial_ids and 517 account_move_line_obj.write(cr, uid, torec, {
470 # 'reconcile_partial_id' or 'reconcile_id'): 518 (st_line.reconcile_id.line_partial_ids and
471 # st_line.reconcile_id.id }, context=context)519 'reconcile_partial_id' or 'reconcile_id'):
472 # for move_line in (st_line.reconcile_id.line_id or []) + (520 st_line.reconcile_id.id }, context=context)
473 # st_line.reconcile_id.line_partial_ids or []):521 for move_line in (st_line.reconcile_id.line_id or []) + (
474 # netsvc.LocalService("workflow").trg_trigger(522 st_line.reconcile_id.line_partial_ids or []):
475 # uid, 'account.move.line', move_line.id, cr)523 netsvc.LocalService("workflow").trg_trigger(
524 uid, 'account.move.line', move_line.id, cr)
476 #""" End account-banking """525 #""" End account-banking """
477526
478 return move_id527 return move_id
@@ -935,7 +984,7 @@
935 Previously (pre-v6) in account_payment/wizard/wizard_pay.py984 Previously (pre-v6) in account_payment/wizard/wizard_pay.py
936 """985 """
937 if context == None:986 if context == None:
938 context={}987 context = {}
939 result = {}988 result = {}
940 orders = self.browse(cr, uid, ids, context)989 orders = self.browse(cr, uid, ids, context)
941 order = orders[0]990 order = orders[0]
@@ -1134,7 +1183,7 @@
1134 '''1183 '''
1135 Create dual function IBAN account for SEPA countries1184 Create dual function IBAN account for SEPA countries
1136 '''1185 '''
1137 if vals['state'] == 'iban':1186 if vals.get('state') == 'iban':
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)
1139 vals['acc_number'], vals['acc_number_domestic'] = (1188 vals['acc_number'], vals['acc_number_domestic'] = (
1140 self._correct_IBAN(iban))1189 self._correct_IBAN(iban))
@@ -1236,7 +1285,7 @@
1236 fields.append('state')1285 fields.append('state')
1237 records = self._founder.read(cr, uid, ids, fields, context, load)1286 records = self._founder.read(cr, uid, ids, fields, context, load)
1238 is_list = True1287 is_list = True
1239 if not isinstance(records, list):1288 if not isinstance(records, list):
1240 records = [records,]1289 records = [records,]
1241 is_list = False1290 is_list = False
1242 for record in records:1291 for record in records:
@@ -1529,7 +1578,7 @@
1529 """1578 """
1530 total = 0.01579 total = 0.0
1531 if not ids:1580 if not ids:
1532 total1581 return total
1533 for line in self.read(1582 for line in self.read(
1534 cr, uid, ids, ['debit', 'credit'], context=context):1583 cr, uid, ids, ['debit', 'credit'], context=context):
1535 total += (line['debit'] or 0.0) - (line['credit'] or 0.0)1584 total += (line['debit'] or 0.0) - (line['credit'] or 0.0)
15361585
=== modified file 'account_banking/account_banking_view.xml'
--- account_banking/account_banking_view.xml 2012-03-08 10:18:13 +0000
+++ account_banking/account_banking_view.xml 2012-05-03 11:53:24 +0000
@@ -192,7 +192,7 @@
192 <data>192 <data>
193 <field name="period_id" position="replace"/>193 <field name="period_id" position="replace"/>
194 <xpath expr="/form/notebook/page[@string='Transaction']/field/tree" position="attributes">194 <xpath expr="/form/notebook/page[@string='Transaction']/field/tree" position="attributes">
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>
196 </xpath>196 </xpath>
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">
198 <field name="name" required="1"/>198 <field name="name" required="1"/>
199199
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2012-05-03 11:50:29 +0000
+++ account_banking/banking_import_transaction.py 2012-05-03 11:53:24 +0000
@@ -88,7 +88,7 @@
88 elif not invoice_ids:88 elif not invoice_ids:
89 # create supplier invoice89 # create supplier invoice
90 partner_obj = self.pool.get('res.partner')90 partner_obj = self.pool.get('res.partner')
91 invoice_lines = [(0,0,dict(91 invoice_lines = [(0, 0, dict(
92 amount = 1,92 amount = 1,
93 price_unit = amount,93 price_unit = amount,
94 name = trans.message or trans.reference,94 name = trans.message or trans.reference,
@@ -247,8 +247,8 @@
247 # the interactive wizard247 # the interactive wizard
248 return False248 return False
249249
250 '''Check if the move_line has been cached'''250 #'''Check if the move_line has been cached'''
251 return move_line.id in linked_invoices251 #return move_line.id in linked_invoices
252252
253 def _cache(move_line, remaining=0.0):253 def _cache(move_line, remaining=0.0):
254 '''Cache the move_line'''254 '''Cache the move_line'''
@@ -430,6 +430,7 @@
430430
431 return trans, False, False431 return trans, False, False
432432
433<<<<<<< TREE
433 def _do_move_reconcile(434 def _do_move_reconcile(
434 self, cr, uid, move_line_ids, currency, amount, context=None):435 self, cr, uid, move_line_ids, currency, amount, context=None):
435 """436 """
@@ -537,6 +538,20 @@
537 def _reconcile_move(538 def _reconcile_move(
538 self, cr, uid, transaction_id, context=None):539 self, cr, uid, transaction_id, context=None):
539 transaction = self.browse(cr, uid, transaction_id, context=context)540 transaction = self.browse(cr, uid, transaction_id, context=context)
541=======
542 def _confirm_move(self, cr, uid, transaction_id, context=None):
543 """
544 The line is matched against a move (invoice), so generate a payment
545 voucher with the write-off settings that the user requested. The move
546 lines will be generated by the voucher, handling rounding and currency
547 conversion.
548 """
549 if context is None:
550 context = {}
551
552 statement_line_pool = self.pool.get('account.bank.statement.line')
553 transaction = self.browse(cr, uid, transaction_id, context)
554>>>>>>> MERGE-SOURCE
540 if not transaction.move_line_id:555 if not transaction.move_line_id:
541 if transaction.match_type == 'invoice':556 if transaction.match_type == 'invoice':
542 raise osv.except_osv(557 raise osv.except_osv(
@@ -558,42 +573,119 @@
558 transaction.statement_line_id.statement_id.name,573 transaction.statement_line_id.statement_id.name,
559 transaction.statement_line_id.name574 transaction.statement_line_id.name
560 )))575 )))
561 currency = transaction.statement_line_id.statement_id.currency576
562 line_ids = [transaction.move_line_id.id]577 st_line = transaction.statement_line_id
563 if transaction.writeoff_move_line_id:578 journal = st_line.statement_id.journal_id
564 line_ids.append(transaction.writeoff_move_line_id.id)579 if st_line.amount < 0.0:
565 reconcile_id = self._do_move_reconcile(580 voucher_type = 'payment'
566 cr, uid, line_ids, currency,581 account_id = (journal.default_debit_account_id and
567 transaction.transferred_amount, context=context)582 journal.default_debit_account_id.id or False)
568 return reconcile_id583 else:
569584 voucher_type = 'receipt'
570 def _reconcile_storno(585 account_id = (journal.default_credit_account_id and
586 journal.default_credit_account_id.id or False)
587
588 # Use the statement line's date determine the period
589 ctxt = context.copy()
590 ctxt['company_id'] = st_line.company_id.id
591 if 'period_id' in ctxt:
592 del ctxt['period_id']
593 period_id = self.pool.get('account.period').find(
594 cr, uid, st_line.date, context=ctxt)[0]
595
596 # Convert the move line amount to the journal currency
597 move_line_amount = transaction.move_line_id.amount_residual_currency
598 to_curr_id = (st_line.statement_id.journal_id.currency and
599 st_line.statement_id.journal_id.currency.id or
600 st_line.statement_id.company_id.currency_id.id)
601 from_curr_id = (transaction.move_line_id.currency_id and
602 transaction.move_line_id.currency_id.id or
603 st_line.statement_id.company_id.currency_id.id)
604 if from_curr_id != to_curr_id:
605 amount_currency = statement_line_pool._convert_currency(
606 cr, uid, from_curr_id, to_curr_id, move_line_amount,
607 round=True, date=time.strftime('%Y-%m-%d'),
608 context=context)
609 else:
610 amount_currency = move_line_amount
611
612 # Check whether this is a full or partial reconciliation
613 if transaction.payment_option == 'with_writeoff':
614 writeoff = abs(st_line.amount) - abs(amount_currency)
615 line_amount = abs(amount_currency)
616 else:
617 writeoff = 0.0
618 line_amount = abs(st_line.amount)
619
620 # Define the voucher
621 voucher = {
622 'journal_id': st_line.statement_id.journal_id.id,
623 'partner_id': st_line.partner_id and st_line.partner_id.id or False,
624 'company_id': st_line.company_id.id,
625 'type':voucher_type,
626 'company_id': st_line.company_id.id,
627 'account_id': account_id,
628 'amount': abs(st_line.amount),
629 'writeoff_amount': writeoff,
630 'payment_option': transaction.payment_option,
631 'writeoff_acc_id': transaction.writeoff_account_id.id,
632 'analytic_id': transaction.writeoff_analytic_id.id,
633 'date': st_line.date,
634 'date_due': st_line.date,
635 'period_id': period_id,
636 'payment_rate_currency_id':to_curr_id,
637 }
638
639 # Define the voucher line
640 vch_line = {
641 #'voucher_id': v_id,
642 'move_line_id': transaction.move_line_id.id,
643 'reconcile': True,
644 'amount': line_amount,
645 'account_id': transaction.move_line_id.account_id.id,
646 'type': transaction.move_line_id.credit and 'dr' or 'cr',
647 }
648 voucher['line_ids'] = [(0, 0, vch_line)]
649 voucher_id = self.pool.get('account.voucher').create(
650 cr, uid, voucher, context=context)
651 statement_line_pool.write(
652 cr, uid, st_line.id,
653 {'voucher_id': voucher_id}, context=context)
654 transaction.refresh()
655
656 def _confirm_storno(
571 self, cr, uid, transaction_id, context=None):657 self, cr, uid, transaction_id, context=None):
572 """658 """
573 Creation of the reconciliation has been delegated to659 Creation of the reconciliation has been delegated to
574 *a* direct debit module, to allow for various direct debit styles660 *a* direct debit module, to allow for various direct debit styles
575 """661 """
576 payment_line_obj = self.pool.get('payment.line')662 payment_line_pool = self.pool.get('payment.line')
663 statement_line_pool = self.pool.get('account.bank.statement.line')
577 transaction = self.browse(cr, uid, transaction_id, context=context)664 transaction = self.browse(cr, uid, transaction_id, context=context)
578 if not transaction.payment_line_id:665 if not transaction.payment_line_id:
579 raise osv.except_osv(666 raise osv.except_osv(
580 _("Cannot link with storno"),667 _("Cannot link with storno"),
581 _("No direct debit order item"))668 _("No direct debit order item"))
582 return payment_line_obj.debit_storno(669 reconcile_id = payment_line_pool.debit_storno(
583 cr, uid,670 cr, uid,
584 transaction.payment_line_id.id, 671 transaction.payment_line_id.id,
585 transaction.statement_line_id.amount,672 transaction.statement_line_id.amount,
586 transaction.statement_line_id.currency,673 transaction.statement_line_id.currency,
587 transaction.storno_retry,674 transaction.storno_retry,
588 context=context)675 context=context)
676 statement_line_pool.write(
677 cr, uid, transaction.statement_line_id.id,
678 {'reconcile_id': reconcile_id}, context=context)
679 transaction.refresh()
589680
590 def _reconcile_payment_order(681 def _confirm_payment_order(
591 self, cr, uid, transaction_id, context=None):682 self, cr, uid, transaction_id, context=None):
592 """683 """
593 Creation of the reconciliation has been delegated to684 Creation of the reconciliation has been delegated to
594 *a* direct debit module, to allow for various direct debit styles685 *a* direct debit module, to allow for various direct debit styles
595 """686 """
596 payment_order_obj = self.pool.get('payment.order')687 payment_order_obj = self.pool.get('payment.order')
688 statement_line_pool = self.pool.get('account.bank.statement.line')
597 transaction = self.browse(cr, uid, transaction_id, context=context)689 transaction = self.browse(cr, uid, transaction_id, context=context)
598 if not transaction.payment_order_id:690 if not transaction.payment_order_id:
599 raise osv.except_osv(691 raise osv.except_osv(
@@ -603,14 +695,17 @@
603 raise osv.except_osv(695 raise osv.except_osv(
604 _("Cannot reconcile"),696 _("Cannot reconcile"),
605 _("Reconcile payment order not implemented"))697 _("Reconcile payment order not implemented"))
606 return payment_order_obj.debit_reconcile_transfer(698 reconcile_id = payment_order_obj.debit_reconcile_transfer(
607 cr, uid,699 cr, uid,
608 transaction.payment_order_id.id,700 transaction.payment_order_id.id,
609 transaction.statement_line_id.amount,701 transaction.statement_line_id.amount,
610 transaction.statement_line_id.currency,702 transaction.statement_line_id.currency,
611 context=context)703 context=context)
704 statement_line_pool.write(
705 cr, uid, transaction.statement_line_id.id,
706 {'reconcile_id': reconcile_id}, context=context)
612707
613 def _reconcile_payment(708 def _confirm_payment(
614 self, cr, uid, transaction_id, context=None):709 self, cr, uid, transaction_id, context=None):
615 """710 """
616 Do some housekeeping on the payment line711 Do some housekeeping on the payment line
@@ -624,7 +719,7 @@
624 'date_done': transaction.effective_date,719 'date_done': transaction.effective_date,
625 }720 }
626 )721 )
627 return self._reconcile_move(cr, uid, transaction_id, context=context)722 self._confirm_move(cr, uid, transaction_id, context=context)
628 723
629 def _cancel_payment(724 def _cancel_payment(
630 self, cr, uid, transaction_id, context=None):725 self, cr, uid, transaction_id, context=None):
@@ -653,6 +748,7 @@
653 transaction.statement_line_id.amount,748 transaction.statement_line_id.amount,
654 transaction.statement_line_id.currency)749 transaction.statement_line_id.currency)
655750
751<<<<<<< TREE
656 def _cancel_move(752 def _cancel_move(
657 self, cr, uid, transaction_id, context=None):753 self, cr, uid, transaction_id, context=None):
658 """754 """
@@ -666,7 +762,76 @@
666 """762 """
667 statement_line_obj = self.pool.get('account.bank.statement.line')763 statement_line_obj = self.pool.get('account.bank.statement.line')
668 transaction = self.browse(cr, uid, transaction_id, context=context)764 transaction = self.browse(cr, uid, transaction_id, context=context)
765=======
766 def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
767 """
768 Legacy method. Allow for canceling bank statement lines that
769 were confirmed using earlier versions of the interactive wizard branch.
770
771 Undo a reconciliation, removing the given move line ids. If no
772 meaningful (partial) reconciliation remains, delete it.
773
774 :param move_line_ids: List of ids. This will usually be the move
775 line of an associated invoice or payment, plus optionally the
776 move line of a writeoff.
777 :param currency: A res.currency *browse* object to perform math
778 operations on the amounts.
779 """
780 move_line_obj = self.pool.get('account.move.line')
781 reconcile_obj = self.pool.get('account.move.reconcile')
782 is_zero = lambda amount: self.pool.get('res.currency').is_zero(
783 cr, uid, currency, amount)
784 move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context)
785 reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id
786 line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids]
787 for move_line_id in move_line_ids:
788 line_ids.remove(move_line_id)
789 if len(line_ids) > 1:
790 full = is_zero(move_line_obj.get_balance(cr, uid, line_ids))
791 if full:
792 line_partial_ids = []
793 else:
794 line_partial_ids = list(line_ids)
795 line_ids = []
796 reconcile_obj.write(
797 cr, uid, reconcile.id,
798 { 'line_partial_ids': [(6, 0, line_partial_ids)],
799 'line_id': [(6, 0, line_ids)],
800 }, context=context)
801 else:
802 reconcile_obj.unlink(cr, uid, reconcile.id, context=context)
803 for move_line in move_lines:
804 if move_line.invoice:
805 # reopening the invoice
806 netsvc.LocalService('workflow').trg_validate(
807 uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr)
808 return True
809
810 def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None):
811 """
812 Legacy method to support upgrades older installations of the
813 interactive wizard branch. To be removed after 6.2
814 clear up the writeoff move
815 """
816 if transaction.writeoff_move_line_id:
817 move_pool = self.pool.get('account.move')
818 move_pool.button_cancel(
819 cr, uid, [transaction.writeoff_move_line_id.move_id.id],
820 context=context)
821 move_pool.unlink(
822 cr, uid, [transaction.writeoff_move_line_id.move_id.id],
823 context=context)
824 return True
825
826 def _legacy_cancel_move(
827 self, cr, uid, transaction, context=None):
828 """
829 Legacy method to support upgrades from older installations
830 of the interactive wizard branch.
831 """
832>>>>>>> MERGE-SOURCE
669 currency = transaction.statement_line_id.statement_id.currency833 currency = transaction.statement_line_id.statement_id.currency
834<<<<<<< TREE
670 reconcile_id = (835 reconcile_id = (
671 transaction.move_line_id.reconcile_id and836 transaction.move_line_id.reconcile_id and
672 transaction.move_line_id.reconcile_id.id or837 transaction.move_line_id.reconcile_id.id or
@@ -680,13 +845,42 @@
680 break845 break
681 line_ids = [st_line_line.id]846 line_ids = [st_line_line.id]
682 # Add the write off line847 # Add the write off line
848=======
849 line_ids = [transaction.move_line_id.id]
850 statement_line_obj = self.pool.get('account.bank.statement.line')
851>>>>>>> MERGE-SOURCE
683 if transaction.writeoff_move_line_id:852 if transaction.writeoff_move_line_id:
684 line_ids.append(transaction.writeoff_move_line_id.id)853 line_ids.append(transaction.writeoff_move_line_id.id)
685 self._do_move_unreconcile(854 self._legacy_do_move_unreconcile(
686 cr, uid, line_ids, currency, context=context)855 cr, uid, line_ids, currency, context=context)
687 statement_line_obj.write(856 statement_line_obj.write(
688 cr, uid, transaction.statement_line_id.id,857 cr, uid, transaction.statement_line_id.id,
689 {'reconcile_id': False}, context=context)858 {'reconcile_id': False}, context=context)
859
860 def _cancel_voucher(
861 self, cr, uid, transaction_id, context=None):
862 voucher_pool = self.pool.get('account.voucher')
863 transaction = self.browse(cr, uid, transaction_id, context=context)
864 st_line = transaction.statement_line_id
865 if transaction.match_type:
866 if st_line.voucher_id:
867 # Although vouchers can be associated with statement lines
868 # in standard OpenERP, we consider ourselves owner of the voucher
869 # if the line has an associated transaction
870 # Upon canceling of the statement line/transaction,
871 # we cancel and delete the vouchers.
872 # Otherwise, the statement line will leave the voucher
873 # unless the statement line itself is deleted.
874 voucher_pool.cancel_voucher(
875 cr, uid, [st_line.voucher_id.id], context=context)
876 voucher_pool.action_cancel_draft(
877 cr, uid, [st_line.voucher_id.id], context=context)
878 voucher_pool.unlink(
879 cr, uid, [st_line.voucher_id.id], context=context)
880 # Allow canceling of legacy entries
881 if not st_line.voucher_id and st_line.reconcile_id:
882 self._legacy_cancel_move(cr, uid, transaction, context=context)
883
690 return True884 return True
691885
692 def _cancel_storno(886 def _cancel_storno(
@@ -714,11 +908,15 @@
714 else:908 else:
715 account_id = journal.default_debit_account_id.id909 account_id = journal.default_debit_account_id.id
716 cancel_line = False910 cancel_line = False
717 for line in transaction.statement_line_id.move_id.line_id:911 move_lines = []
912 for move in transaction.statement_line_id.move_ids:
913 # There should usually be just one move, I think
914 move_lines += move.line_id
915 for line in move_lines:
718 if line.account_id.id != account_id:916 if line.account_id.id != account_id:
719 cancel_line = line917 cancel_line = line
720 break918 break
721 if not cancel_line: # debug919 if not cancel_line:
722 raise osv.except_osv(920 raise osv.except_osv(
723 _("Cannot cancel link with storno"),921 _("Cannot cancel link with storno"),
724 _("Line id not found"))922 _("Line id not found"))
@@ -744,16 +942,16 @@
744942
745 cancel_map = {943 cancel_map = {
746 'storno': _cancel_storno,944 'storno': _cancel_storno,
747 'invoice': _cancel_move,945 'invoice': _cancel_voucher,
748 'manual': _cancel_move,946 'manual': _cancel_voucher,
749 'move': _cancel_move,947 'move': _cancel_voucher,
750 'payment_order': _cancel_payment_order,948 'payment_order': _cancel_payment_order,
751 'payment': _cancel_payment,949 'payment': _cancel_payment,
752 }950 }
951
753 def cancel(self, cr, uid, ids, context=None):952 def cancel(self, cr, uid, ids, context=None):
754 if ids and isinstance(ids, (int, float)):953 if ids and isinstance(ids, (int, float)):
755 ids = [ids]954 ids = [ids]
756 move_obj = self.pool.get('account.move')
757 for transaction in self.browse(cr, uid, ids, context):955 for transaction in self.browse(cr, uid, ids, context):
758 if not transaction.match_type:956 if not transaction.match_type:
759 continue957 continue
@@ -763,31 +961,25 @@
763 _("No method found to cancel this type"))961 _("No method found to cancel this type"))
764 self.cancel_map[transaction.match_type](962 self.cancel_map[transaction.match_type](
765 self, cr, uid, transaction.id, context)963 self, cr, uid, transaction.id, context)
766 # clear up the writeoff move964 self._legacy_clear_up_writeoff(cr, uid, transaction, context=context)
767 if transaction.writeoff_move_line_id:
768 move_obj.button_cancel(
769 cr, uid, [transaction.writeoff_move_line_id.move_id.id],
770 context=context)
771 move_obj.unlink(
772 cr, uid, [transaction.writeoff_move_line_id.move_id.id],
773 context=context)
774 return True965 return True
775966
776 reconcile_map = {967 confirm_map = {
777 'storno': _reconcile_storno,968 'storno': _confirm_storno,
778 'invoice': _reconcile_move,969 'invoice': _confirm_move,
779 'manual': _reconcile_move,970 'manual': _confirm_move,
780 'payment_order': _reconcile_payment_order,971 'payment_order': _confirm_payment_order,
781 'payment': _reconcile_payment,972 'payment': _confirm_payment,
782 'move': _reconcile_move,973 'move': _confirm_move,
783 }974 }
784 def reconcile(self, cr, uid, ids, context=None):975
976 def confirm(self, cr, uid, ids, context=None):
785 if ids and isinstance(ids, (int, float)):977 if ids and isinstance(ids, (int, float)):
786 ids = [ids]978 ids = [ids]
787 for transaction in self.browse(cr, uid, ids, context):979 for transaction in self.browse(cr, uid, ids, context):
788 if not transaction.match_type:980 if not transaction.match_type:
789 continue981 continue
790 if transaction.match_type not in self.reconcile_map:982 if transaction.match_type not in self.confirm_map:
791 raise osv.except_osv(983 raise osv.except_osv(
792 _("Cannot reconcile"),984 _("Cannot reconcile"),
793 _("Cannot reconcile type %s. No method found to " +985 _("Cannot reconcile type %s. No method found to " +
@@ -802,19 +994,11 @@
802 "this match type.") %994 "this match type.") %
803 transaction.statement_line_id.name995 transaction.statement_line_id.name
804 )996 )
805 self._generate_writeoff_move(997 # Generalize this bit and move to the confirmation
806 cr, uid, transaction.id, context=context)998 # methods that actually do create a voucher?
807 # run the method that is appropriate for this match type999 self.confirm_map[transaction.match_type](
808 reconcile_id = self.reconcile_map[transaction.match_type](
809 self, cr, uid, transaction.id, context)1000 self, cr, uid, transaction.id, context)
810 self.pool.get('account.bank.statement.line').write(
811 cr, uid, transaction.statement_line_id.id,
812 {'reconcile_id': reconcile_id}, context=context)
8131001
814 # TODO
815 # update the statement line bank account reference
816 # as follows (from _match_invoice)
817
818 """1002 """
819 account_ids = [1003 account_ids = [
820 x.id for x in bank_account_ids 1004 x.id for x in bank_account_ids
@@ -822,64 +1006,7 @@
822 ][0]1006 ][0]
823 """1007 """
824 return True1008 return True
8251009
826
827 def _generate_writeoff_move(self, cr, uid, ids, context):
828 if ids and isinstance(ids, (int, float)):
829 ids = [ids]
830 move_line_obj = self.pool.get('account.move.line')
831 move_obj = self.pool.get('account.move')
832 for trans in self.browse(cr, uid, ids, context=context):
833 # Get the period for the company and date
834 ctxt = context.copy()
835 ctxt['company_id'] = trans.company_id.id
836 periods = self.pool.get('account.period').find(
837 cr, uid, trans.statement_line_id.date, context=ctxt)
838 period_id = periods and periods[0] or False
839
840 move_id = move_obj.create(cr, uid, {
841 'journal_id': trans.writeoff_journal_id.id,
842 'period_id': period_id,
843 'date': trans.statement_line_id.date,
844 'name': '(write-off) %s' % (
845 trans.move_line_id.move_id.name or ''),
846 }, context=context)
847 if trans.residual > 0:
848 writeoff_debit = trans.residual
849 writeoff_credit = False
850 else:
851 writeoff_debit = False
852 writeoff_credit = - trans.residual
853 vals = {
854 'name': trans.statement_line_id.name,
855 'date': trans.statement_line_id.date,
856 'ref': trans.statement_line_id.ref,
857 'move_id': move_id,
858 'partner_id': (trans.statement_line_id.partner_id and
859 trans.statement_line_id.partner_id.id or False),
860 'account_id': trans.statement_line_id.account_id.id,
861 'credit': writeoff_debit,
862 'debit': writeoff_credit,
863 'journal_id': trans.writeoff_journal_id.id,
864 'period_id': period_id,
865 'currency_id': trans.statement_line_id.statement_id.currency.id,
866 'analytic_account_id': trans.writeoff_analytic_id.id,
867 }
868 move_line_id = move_line_obj.create(
869 cr, uid, vals, context=context)
870 self.write(
871 cr, uid, trans.id,
872 {'writeoff_move_line_id': move_line_id}, context=context)
873 vals.update({
874 'account_id': trans.writeoff_account_id.id,
875 'credit': writeoff_credit,
876 'debit': writeoff_debit,
877 })
878 move_line_obj.create(
879 cr, uid, vals, context=context)
880 move_obj.post(
881 cr, uid, [move_id], context=context)
882
883 def _match_storno(1010 def _match_storno(
884 self, cr, uid, trans, log, context=None):1011 self, cr, uid, trans, log, context=None):
885 payment_line_obj = self.pool.get('payment.line')1012 payment_line_obj = self.pool.get('payment.line')
@@ -1251,7 +1378,7 @@
1251 provision_costs_description = False,1378 provision_costs_description = False,
1252 ), context=context)1379 ), context=context)
1253 # rebrowse the current record after writing1380 # rebrowse the current record after writing
1254 transaction=self.browse(cr, uid, transaction.id, context=context)1381 transaction = self.browse(cr, uid, transaction.id, context=context)
1255 # Match full direct debit orders1382 # Match full direct debit orders
1256 if transaction.type == bt.DIRECT_DEBIT:1383 if transaction.type == bt.DIRECT_DEBIT:
1257 move_info = self._match_debit_order(1384 move_info = self._match_debit_order(
@@ -1476,10 +1603,15 @@
1476 """1603 """
1477 if not ids:1604 if not ids:
1478 return {}1605 return {}
1479 res = {}1606 res = dict([(x, False) for x in ids])
1480 for transaction in self.browse(cr, uid, ids, context):1607 for transaction in self.browse(cr, uid, ids, context):
1481 res[transaction.id] = abs(transaction.transferred_amount) - abs(transaction.move_currency_amount)1608 res[transaction.id] = (
14821609 not(transaction.move_currency_amount is False)
1610 and (
1611 transaction.transferred_amount -
1612 transaction.move_currency_amount
1613 )
1614 or False)
1483 return res1615 return res
1484 1616
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):
@@ -1530,12 +1662,11 @@
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).
1531 """1663 """
1532 if not ids:1664 if not ids:
1533 return {}1665 return {}
1666 res = dict([(x, False) for x in ids])
15341667
1535 stline_pool = self.pool.get('account.bank.statement.line')1668 stline_pool = self.pool.get('account.bank.statement.line')
15361669
1537 res = {}
1538
1539 for transaction in self.browse(cr, uid, ids, context):1670 for transaction in self.browse(cr, uid, ids, context):
15401671
1541 if transaction.move_line_id:1672 if transaction.move_line_id:
@@ -1632,15 +1763,25 @@
1632 'invoice_id', 'transaction_id', 'Matching invoices'),1763 'invoice_id', 'transaction_id', 'Matching invoices'),
1633 'invoice_id': fields.many2one(1764 'invoice_id': fields.many2one(
1634 'account.invoice', 'Invoice to reconcile'),1765 'account.invoice', 'Invoice to reconcile'),
1635 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
1636 'residual': fields.function(1766 'residual': fields.function(
1637 _get_residual, method=True, string='Residual', type='float'),1767 _get_residual, method=True, string='Residual', type='float'),
1638 'writeoff_account_id': fields.many2one(1768 'writeoff_account_id': fields.many2one(
1639 'account.account', 'Write-off account',1769 'account.account', 'Write-off account',
1640 domain=[('type', '!=', 'view')]),1770 domain=[('type', '!=', 'view')]),
1641 'payment_option':fields.selection([('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')], 'Payment Difference', 1771 'payment_option':fields.selection(
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 [
1773 ('without_writeoff', 'Keep Open'),
1774 ('with_writeoff', 'Reconcile Payment Balance')
1775 ], 'Payment Difference',
1776 required=True,
1777 help=("This field helps you to choose what you want to do with "
1778 "the eventual difference between the paid amount and the "
1779 "sum of allocated amounts. You can either choose to keep "
1780 "open this difference on the partner's account, "
1781 "or reconcile it with the payment(s)"),
1782 ),
1643 'writeoff_amount': fields.float('Difference Amount'),1783 'writeoff_amount': fields.float('Difference Amount'),
1784 # Legacy field: to be removed after 6.2
1644 'writeoff_move_line_id': fields.many2one(1785 'writeoff_move_line_id': fields.many2one(
1645 'account.move.line', 'Write off move line'),1786 'account.move.line', 'Write off move line'),
1646 'writeoff_analytic_id': fields.many2one(1787 'writeoff_analytic_id': fields.many2one(
@@ -1668,8 +1809,9 @@
1668 'import_transaction_id', 'match_multi', type='boolean',1809 'import_transaction_id', 'match_multi', type='boolean',
1669 string='Multi match', readonly=True),1810 string='Multi match', readonly=True),
1670 'residual': fields.related(1811 'residual': fields.related(
1671 'import_transaction_id', 'residual', type='float', 1812 'import_transaction_id', 'residual', type='float',
1672 string='Residual'),1813 string='Residual', readonly=True,
1814 ),
1673 'duplicate': fields.related(1815 'duplicate': fields.related(
1674 'import_transaction_id', 'duplicate', type='boolean',1816 'import_transaction_id', 'duplicate', type='boolean',
1675 string='Possible duplicate import', readonly=True),1817 string='Possible duplicate import', readonly=True),
@@ -1680,16 +1822,9 @@
1680 ('payment_order', 'Payment order'),1822 ('payment_order', 'Payment order'),
1681 ('storno', 'Storno')], 1823 ('storno', 'Storno')],
1682 string='Match type', readonly=True,),1824 string='Match type', readonly=True,),
1683 'residual': fields.related(
1684 'import_transaction_id', 'residual', type='float',
1685 string='Residual', readonly=True,
1686 ),
1687 'state': fields.selection(1825 'state': fields.selection(
1688 [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',1826 [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
1689 readonly=True, required=True),1827 readonly=True, required=True),
1690 'move_id': fields.many2one(
1691 'account.move', 'Move', readonly=True,
1692 help="The accounting move associated with this line"),
1693 }1828 }
16941829
1695 _defaults = {1830 _defaults = {
@@ -1710,8 +1845,9 @@
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)
1711 return res1846 return res
17121847
17131848 def _convert_currency(
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,
1850 round=False, date=None, context=None):
1715 """Convert currency amount using the company rate on a specific date"""1851 """Convert currency amount using the company rate on a specific date"""
1716 curr_obj = self.pool.get('res.currency')1852 curr_obj = self.pool.get('res.currency')
1717 if context:1853 if context:
@@ -1721,10 +1857,11 @@
1721 if date:1857 if date:
1722 ctxt["date"] = date1858 ctxt["date"] = date
17231859
1724 amount = curr_obj.compute(cr, uid, from_curr_id, to_curr_id, from_amount, round=round, context=ctxt)1860 amount = curr_obj.compute(
1861 cr, uid, from_curr_id, to_curr_id, from_amount,
1862 round=round, context=ctxt)
1725 return amount1863 return amount
17261864
1727
1728 def confirm(self, cr, uid, ids, context=None):1865 def confirm(self, cr, uid, ids, context=None):
1729 """1866 """
1730 Create (or update) a voucher for each statement line, and then generate1867 Create (or update) a voucher for each statement line, and then generate
@@ -1732,10 +1869,10 @@
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
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.
1734 """1871 """
1735 voucher_pool = self.pool.get('account.voucher')
1736 statement_pool = self.pool.get('account.bank.statement')1872 statement_pool = self.pool.get('account.bank.statement')
1737 obj_seq = self.pool.get('ir.sequence')1873 obj_seq = self.pool.get('ir.sequence')
1738 move_pool = self.pool.get('account.move')1874 move_pool = self.pool.get('account.move')
1875 import_transaction_obj = self.pool.get('banking.import.transaction')
17391876
1740 for st_line in self.browse(cr, uid, ids, context):1877 for st_line in self.browse(cr, uid, ids, context):
1741 if st_line.state != 'draft':1878 if st_line.state != 'draft':
@@ -1754,157 +1891,47 @@
1754 "journal!") % (st_line.statement_id.journal_id.name,))1891 "journal!") % (st_line.statement_id.journal_id.name,))
1755 if not st_line.amount:1892 if not st_line.amount:
1756 continue1893 continue
17571894 if not st_line.period_id:
1895 self.write(
1896 cr, uid, [st_line.id], {
1897 'period_id': self._get_period(
1898 cr, uid, {'date': st_line.date})
1899 })
1900 st_line.refresh()
1758 # Generate the statement number, if it is not already done1901 # Generate the statement number, if it is not already done
1759 st = st_line.statement_id1902 st = st_line.statement_id
1760 if not st.name == '/':1903 if not st.name == '/':
1761 st_number = st.name1904 st_number = st.name
1762 else:1905 else:
1763 if st.journal_id.sequence_id:1906 if st.journal_id.sequence_id:
1764 c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}1907 period = st.period_id or st_line.period_id
1908 c = {'fiscalyear_id': period.fiscalyear_id.id}
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)
1766 else:1910 else:
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')
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)
17691913
1770 # Check if this line has been matched against a journal item1914 if st_line.import_transaction_id:
1771 if st_line.import_transaction_id.move_line_id:1915 import_transaction_obj.confirm(
1772 # Line has been matched, so post it via a voucher1916 cr, uid, st_line.import_transaction_id.id, context)
1773 self._post_with_voucher(cr, uid, ids, st_line, voucher_pool, move_pool, context=context)1917 st_line.refresh()
17741918 st_line_number = statement_pool.get_next_st_line_number(
1775 else:1919 cr, uid, st_number, st_line, context)
1776 # Check to see if the line has an account that can be used to generate a journal entry1920 company_currency_id = st.journal_id.company_id.currency_id.id
1777 if st_line.account_id:1921 statement_pool.create_move_from_st_line(
1778 # Generate a journal for the entry using the standard bank statement code1922 cr, uid, st_line.id, company_currency_id, st_line_number, context)
1779 self._create_move(cr, uid, st_line, statement_pool, st, st_number, context=context)1923 self.write(
1780 else:1924 cr, uid, st_line.id, {'state': 'confirmed'}, context)
1781 raise osv.except_osv(
1782 _('Statement line has no account'),
1783 _("You cannot confirm a bank statement line that has no account against it (%s.%s)") %
1784 (st_line.statement_id.name, st_line.name,))
1785
1786 return True1925 return True
17871926
1788 def _create_move(self, cr, uid, st_line, statement_pool, st, st_number, context):
1789 """
1790 The line is not matched against a move, but the account has been defined for the line.
1791 Generate a journal entry for the statement line that transfers the full amount against the account.
1792 """
1793 st_line_number = statement_pool.get_next_st_line_number(cr, uid, st_number, st_line, context)
1794 company_currency_id = st.journal_id.company_id.currency_id.id
1795 move_id = statement_pool.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context)
1796 self.write(cr, uid, st_line.id, {'state': 'confirmed', 'move_id': move_id}, context)
1797
1798
1799 def _post_with_voucher(self, cr, uid, ids, st_line, voucher_pool, move_pool, context):
1800 # Check if a voucher has already been created
1801 if st_line.voucher_id:
1802 # There's an existing voucher on the statement line which was probably created
1803 # manually. This may have been done because it was a single payment for multiple
1804 # invoices. Just get the voucher ID.
1805 voucher_id = st_line.voucher_id.id
1806 else:
1807 # Create a voucher and store the ID on the statement line
1808 voucher_id = self._create_voucher(cr, uid, ids, st_line, context=context)
1809 self.pool.get('account.bank.statement.line').write(cr,uid,st_line.id,{'voucher_id':voucher_id} , context=context)
1810
1811 # If the voucher is in draft mode, then post it
1812 voucher = voucher_pool.browse(cr, uid, voucher_id, context=context)
1813 if voucher.state in ('draft','proforma'):
1814 voucher.action_move_line_create()
1815
1816 # Update the statement line to indicate that it has been posted
1817 # ... no longer need to set the move_id on the voucher?
1818 self.write(cr, uid, st_line.id, {'state': 'confirmed'}, context)
1819
1820 # The voucher journal isn't automatically posted, so post it (if needed)
1821 if not voucher.journal_id.entry_posted:
1822 voucher = voucher_pool.browse(cr, uid, voucher_id, context=context)
1823 move_pool.post(cr, uid, [voucher.move_id.id], context={})
1824
1825
1826 def _create_voucher(self, cr, uid, ids, st_line, context):
1827 """
1828 The line is matched against a move (invoice), so generate a payment voucher with the write-off settings that the
1829 user requested. The move lines will be generated by the voucher, handling rounding and currency conversion.
1830 """
1831 journal = st_line.statement_id.journal_id
1832 if st_line.amount < 0.0:
1833 voucher_type = 'payment'
1834 account_id = journal.default_debit_account_id and journal.default_debit_account_id.id or False
1835 else:
1836 voucher_type = 'receipt'
1837 account_id = journal.default_credit_account_id and journal.default_credit_account_id.id or False
1838
1839 # Use the statement line's date determine the period
1840 ctxt = context.copy()
1841 ctxt['company_id'] = st_line.company_id.id
1842 if 'period_id' in ctxt:
1843 del ctxt['period_id']
1844 period_id = self.pool.get('account.period').find(cr, uid, st_line.date, context=ctxt)[0]
1845
1846 # Convert the move line amount to the journal currency
1847 move_line_amount = st_line.import_transaction_id.move_line_id.amount_residual_currency
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
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
1850 if from_curr_id != to_curr_id:
1851 amount_currency = self._convert_currency(cr, uid, from_curr_id, to_curr_id, move_line_amount, round=True,
1852 date=time.strftime('%Y-%m-%d'), context=context)
1853 else:
1854 amount_currency = move_line_amount
1855
1856 # Check whether this is a full or partial reconciliation
1857 if st_line.import_transaction_id.payment_option=='with_writeoff':
1858 writeoff = abs(st_line.amount)-abs(amount_currency)
1859 line_amount = abs(amount_currency)
1860 else:
1861 writeoff = 0.0
1862 line_amount = abs(st_line.amount)
1863
1864 # Define the voucher
1865 voucher = {
1866 'journal_id': st_line.statement_id.journal_id.id,
1867 'partner_id': st_line.partner_id and st_line.partner_id.id or False,
1868 'company_id': st_line.company_id.id,
1869 'type':voucher_type,
1870 'company_id': st_line.company_id.id,
1871 'account_id': account_id,
1872 'amount': abs(st_line.amount),
1873 'writeoff_amount': writeoff,
1874 'payment_option': st_line.import_transaction_id.payment_option,
1875 'writeoff_acc_id': st_line.import_transaction_id.writeoff_account_id.id,
1876 'analytic_id': st_line.import_transaction_id.writeoff_analytic_id.id,
1877 'date': st_line.date,
1878 'date_due': st_line.date,
1879 'period_id': period_id,
1880 'payment_rate_currency_id':to_curr_id,
1881 }
1882
1883 # Define the voucher line
1884 vch_line = {
1885 #'voucher_id': v_id,
1886 'move_line_id': st_line.import_transaction_id.move_line_id.id,
1887 'reconcile': True,
1888 'amount': line_amount,
1889 'account_id': st_line.import_transaction_id.move_line_id.account_id.id,
1890 'type': st_line.import_transaction_id.move_line_id.credit and 'dr' or 'cr',
1891 }
1892 voucher['line_ids'] = [(0,0,vch_line)]
1893 v_id = self.pool.get('account.voucher').create(cr, uid, voucher, context=context)
1894
1895 return v_id
1896
1897
1898 def cancel(self, cr, uid, ids, context=None):1927 def cancel(self, cr, uid, ids, context=None):
1899 if ids and isinstance(ids, (int, float)):1928 if ids and isinstance(ids, (int, float)):
1900 ids = [ids]1929 ids = [ids]
1901 account_move_obj = self.pool.get('account.move')
1902 import_transaction_obj = self.pool.get('banking.import.transaction')1930 import_transaction_obj = self.pool.get('banking.import.transaction')
1903 voucher_pool = self.pool.get('account.voucher')1931 move_pool = self.pool.get('account.move')
1904 transaction_cancel_ids = []1932 transaction_cancel_ids = []
1905 voucher_cancel_ids = []1933 set_draft_ids = []
1906 move_unlink_ids = []1934 move_unlink_ids = []
1907 set_draft_ids = []
1908 # harvest ids for various actions1935 # harvest ids for various actions
1909 for st_line in self.browse(cr, uid, ids, context):1936 for st_line in self.browse(cr, uid, ids, context):
1910 if st_line.state != 'confirmed':1937 if st_line.state != 'confirmed':
@@ -1915,32 +1942,23 @@
1915 _("The bank statement that this transaction belongs to has "1942 _("The bank statement that this transaction belongs to has "
1916 "already been confirmed"))1943 "already been confirmed"))
19171944
1918 # Check if the transaction has a voucher1945 if st_line.import_transaction_id:
1919 if st_line.voucher_id:1946 # Cancel transaction immediately.
1920 voucher_cancel_ids.append(st_line.voucher_id.id)1947 # If it has voucher, this will clean up
1921 else:1948 # the moves on the st_line.
1922 if st_line.import_transaction_id:1949 import_transaction_obj.cancel(
1923 transaction_cancel_ids.append(st_line.import_transaction_id.id)1950 cr, uid, [st_line.import_transaction_id.id], context=context)
1924 if st_line.move_id:1951 st_line.refresh()
1925 move_unlink_ids.append(st_line.move_id.id)1952 for line in st_line.move_ids:
1926 else:1953 # We allow for people canceling and removing
1927 raise osv.except_osv(1954 # the associated payments, which can lead to confirmed
1928 _("Cannot cancel bank transaction"),1955 # statement lines without an associated move
1929 _("Cannot cancel this bank transaction. The information "1956 move_unlink_ids.append(line.id)
1930 "needed to undo the accounting entries has not been "
1931 "recorded"))
1932 set_draft_ids.append(st_line.id)1957 set_draft_ids.append(st_line.id)
19331958
1934 # Cancel and delete the vouchers1959 move_pool.button_cancel(
1935 voucher_pool.cancel_voucher(cr, uid, voucher_cancel_ids, context=context)1960 cr, uid, move_unlink_ids, context=context)
1936 voucher_pool.action_cancel_draft(cr, uid, voucher_cancel_ids, context=context)1961 move_pool.unlink(cr, uid, move_unlink_ids, context=context)
1937 voucher_pool.unlink(cr, uid, voucher_cancel_ids, context=context)
1938
1939 # Perform actions
1940 import_transaction_obj.cancel(
1941 cr, uid, transaction_cancel_ids, context=context)
1942 account_move_obj.button_cancel(cr, uid, move_unlink_ids, context)
1943 account_move_obj.unlink(cr, uid, move_unlink_ids, context)
1944 self.write(1962 self.write(
1945 cr, uid, set_draft_ids, {'state': 'draft'}, context=context)1963 cr, uid, set_draft_ids, {'state': 'draft'}, context=context)
1946 return True1964 return True
@@ -1954,8 +1972,12 @@
1954 ids = [ids]1972 ids = [ids]
1955 for line in self.browse(cr, uid, ids, context=context):1973 for line in self.browse(cr, uid, ids, context=context):
1956 if line.state == 'confirmed':1974 if line.state == 'confirmed':
1957 raise osv.except_osv(_('Confirmed Statement Line'), _("You cannot delete a confirmed Statement Line: '%s'" % line.name))1975 raise osv.except_osv(
1958 return super(account_bank_statement_line,self).unlink(cr, uid, ids, context=context)1976 _('Confirmed Statement Line'),
1977 _("You cannot delete a confirmed Statement Line"
1978 ": '%s'" % line.name))
1979 return super(account_bank_statement_line, self).unlink(
1980 cr, uid, ids, context=context)
19591981
1960account_bank_statement_line()1982account_bank_statement_line()
19611983
@@ -2000,7 +2022,7 @@
20002022
2001 # protect against misguided manual changes2023 # protect against misguided manual changes
2002 for line in st.move_line_ids:2024 for line in st.move_line_ids:
2003 if line.state <> 'valid':2025 if line.state != 'valid':
2004 raise osv.except_osv(_('Error !'),2026 raise osv.except_osv(_('Error !'),
2005 _('The account entries lines are not in valid state.'))2027 _('The account entries lines are not in valid state.'))
20062028
20072029
=== modified file 'account_banking/wizard/banking_transaction_wizard.py'
--- account_banking/wizard/banking_transaction_wizard.py 2012-03-07 23:02:52 +0000
+++ account_banking/wizard/banking_transaction_wizard.py 2012-05-03 11:53:24 +0000
@@ -21,6 +21,7 @@
21#21#
22##############################################################################22##############################################################################
23from osv import osv, fields23from osv import osv, fields
24from openerp.tools.translate import _
2425
25"""26"""
2627
@@ -38,7 +39,7 @@
38 """ 39 """
39 Return a popup window for this model40 Return a popup window for this model
40 """41 """
41 if isinstance(ids, (int,long)):42 if isinstance(ids, (int, long)):
42 ids = [ids]43 ids = [ids]
43 return {44 return {
44 'name': self._description,45 'name': self._description,
@@ -160,9 +161,7 @@
160 statement_line_obj = self.pool.get('account.bank.statement.line')161 statement_line_obj = self.pool.get('account.bank.statement.line')
161 for wiz in self.browse(162 for wiz in self.browse(
162 cr, uid, ids, context=context):163 cr, uid, ids, context=context):
163 invoice_ids = False
164 move_line_id = False164 move_line_id = False
165 move_line_ids = False
166 invoice_id = manual_invoice_id165 invoice_id = manual_invoice_id
167 if invoice_id:166 if invoice_id:
168 invoice = invoice_obj.browse(167 invoice = invoice_obj.browse(
169168
=== modified file 'account_direct_debit/model/account_payment.py'
--- account_direct_debit/model/account_payment.py 2012-01-12 10:58:49 +0000
+++ account_direct_debit/model/account_payment.py 2012-05-03 11:53:24 +0000
@@ -104,7 +104,6 @@
104 _("Cannot unreconcile"),104 _("Cannot unreconcile"),
105 _("Cannot unreconcile debit order: "+105 _("Cannot unreconcile debit order: "+
106 "Workflow will not allow it."))106 "Workflow will not allow it."))
107
108 return True107 return True
109108
110 def test_undo_done(self, cr, uid, ids, context=None):109 def test_undo_done(self, cr, uid, ids, context=None):
111110
=== modified file 'account_direct_debit/view/account_invoice.xml'
--- account_direct_debit/view/account_invoice.xml 2011-12-21 13:06:26 +0000
+++ account_direct_debit/view/account_invoice.xml 2012-05-03 11:53:24 +0000
@@ -13,9 +13,9 @@
13 Maybe apply trick in fields_view_get instead, for13 Maybe apply trick in fields_view_get instead, for
14 better compatibility with other modules?14 better compatibility with other modules?
15 -->15 -->
16 <button name="invoice_open" position="attributes">16 <!-- button name="invoice_open" position="attributes">
17 <attribute name="states">draft,proforma2,debit_denied</attribute>17 <attribute name="states">draft,proforma2,debit_denied</attribute>
18 </button>18 </button -->
19 <button string='Re-Open' position="attributes">19 <button string='Re-Open' position="attributes">
20 <attribute name="states">paid,debit_denied</attribute>20 <attribute name="states">paid,debit_denied</attribute>
21 <!--21 <!--
2222
=== modified file 'account_direct_debit/workflow/account_invoice.xml'
--- account_direct_debit/workflow/account_invoice.xml 2011-12-21 13:06:26 +0000
+++ account_direct_debit/workflow/account_invoice.xml 2012-05-03 11:53:24 +0000
@@ -8,20 +8,44 @@
8 <field name="kind">function</field>8 <field name="kind">function</field>
9 </record>9 </record>
10 <record id="paid_to_debit_denied" model="workflow.transition">10 <record id="paid_to_debit_denied" model="workflow.transition">
11 <!--
12 Set an invoice to state debit denied, either manually
13 or by confirming a bank statement line that constitutes
14 a fatal storno
15 -->
11 <field name="act_from" ref="account.act_paid"/>16 <field name="act_from" ref="account.act_paid"/>
12 <field name="act_to" ref="act_debit_denied"/>17 <field name="act_to" ref="act_debit_denied"/>
13 <field name="signal">invoice_debit_denied</field>18 <field name="signal">invoice_debit_denied</field>
14 </record>19 </record>
20 <record id="open_test_to_debit_denied" model="workflow.transition">
21 <!--
22 A storno leads to unreconciling the move line, which
23 reopens the invoice. We need to allow a transition from
24 this state to the debit denied state if the storno is fatal.
25 -->
26 <field name="act_from" ref="account.act_open_test"/>
27 <field name="act_to" ref="act_debit_denied"/>
28 <field name="signal">invoice_debit_denied</field>
29 </record>
15 <record id="debit_denied_to_paid" model="workflow.transition">30 <record id="debit_denied_to_paid" model="workflow.transition">
31 <!--
32 Cancel a bank statement line that constitutes a fatal
33 storno
34 -->
16 <field name="act_from" ref="act_debit_denied"/>35 <field name="act_from" ref="act_debit_denied"/>
17 <field name="act_to" ref="account.act_paid"/>36 <field name="act_to" ref="account.act_paid"/>
18 <field name="condition">test_undo_debit_denied()</field>37 <field name="condition">test_undo_debit_denied()</field>
19 <field name="signal">undo_debit_denied</field>38 <field name="signal">undo_debit_denied</field>
20 </record>39 </record>
21 <record id="debit_denied_to_open" model="workflow.transition">40 <record id="debit_denied_to_open" model="workflow.transition">
41 <!--
42 Allow the user to manually reset a debit denied status
43 on a paid invoice (but only after manually unreconciling
44 the invoice)
45 -->
22 <field name="act_from" ref="act_debit_denied"/>46 <field name="act_from" ref="act_debit_denied"/>
23 <field name="act_to" ref="account.act_open"/>47 <field name="act_to" ref="account.act_open_test"/>
24 <field name="signal">invoice_open</field>48 <field name="signal">open_test</field>
25 </record>49 </record>
26 </data>50 </data>
27</openerp>51</openerp>

Subscribers

People subscribed via source and target branches