banking-addons-team team mailing list archive
-
banking-addons-team team
-
Mailing list archive
-
Message #00077
lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 into lp:~banking-addons-team/banking-addons/6.1-dev
Stefan Rijnhart (Therp) has proposed merging lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 into lp:~banking-addons-team/banking-addons/6.1-dev.
Requested reviews:
Banking Addons Team (banking-addons-team)
Related bugs:
Bug #992141 in Banking Addons: "Conflito com instalação do modulo POS"
https://bugs.launchpad.net/banking-addons/+bug/992141
For more details, see:
https://code.launchpad.net/~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2/+merge/104384
Merge request is tentative, as it constitutes a lot of changes. Let's first see what the diff looks like.
In principle, 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.
--
https://code.launchpad.net/~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2/+merge/104384
Your team Banking Addons Team is requested to review the proposed merge of lp:~therp-nl/banking-addons/6.1-dev-fixes_from_testing_iteration_2 into lp:~banking-addons-team/banking-addons/6.1-dev.
=== 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-02 13:35:21 +0000
@@ -58,13 +58,11 @@
Rejected payments from the bank receive on import the status 'rejected'.
'''
import time
-import sys
import sepa
from osv import osv, fields
from tools.translate import _
from wizard.banktools import get_or_create_bank
import decimal_precision as dp
-import pooler
import netsvc
from openerp import SUPERUSER_ID
@@ -322,6 +320,26 @@
# 'currency': _currency,
}
+ def _check_company_id(self, cr, uid, ids, context=None):
+ """
+ Adapt this constraint method from the account module to reflect the
+ move of period_id to the statement line
+ """
+ for statement in self.browse(cr, uid, ids, context=context):
+ if (statement.period_id and
+ statement.company_id.id != statement.period_id.company_id.id):
+ return False
+ for line in statement.line_ids:
+ if (line.period_id and
+ statement.company_id.id != line.period_id.company_id.id):
+ return False
+ return True
+
+ # Redefine the constraint, or it still refer to the original method
+ _constraints = [
+ (_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
+ ]
+
def _get_period(self, cursor, uid, date, context=None):
'''
Find matching period for date, not meant for _defaults.
@@ -341,10 +359,12 @@
context=None):
# This is largely a copy of the original code in account
# Modifications are marked with AB
+ # Modifications by account_voucher are merged below.
# As there is no valid inheritance mechanism for large actions, this
# is the only option to add functionality to existing actions.
# WARNING: when the original code changes, this trigger has to be
# updated in sync.
+
if context is None:
context = {}
res_currency_obj = self.pool.get('res.currency')
@@ -352,8 +372,36 @@
account_move_line_obj = self.pool.get('account.move.line')
account_bank_statement_line_obj = self.pool.get(
'account.bank.statement.line')
- st_line = account_bank_statement_line_obj.browse(cr, uid, st_line_id,
- context=context)
+ st_line = account_bank_statement_line_obj.browse(
+ cr, uid, st_line_id, context=context)
+ # Start account voucher
+ # Post the voucher and update links between statement and moves
+ if st_line.voucher_id:
+ voucher_pool = self.pool.get('account.voucher')
+ wf_service = netsvc.LocalService("workflow")
+ voucher_pool.write(
+ cr, uid, [st_line.voucher_id.id], {'number': st_line_number}, context=context)
+ if st_line.voucher_id.state == 'cancel':
+ voucher_pool.action_cancel_draft(
+ cr, uid, [st_line.voucher_id.id], context=context)
+ wf_service.trg_validate(
+ uid, 'account.voucher', st_line.voucher_id.id, 'proforma_voucher', cr)
+ v = voucher_pool.browse(
+ cr, uid, st_line.voucher_id.id, context=context)
+ account_bank_statement_line_obj.write(cr, uid, [st_line_id], {
+ 'move_ids': [(4, v.move_id.id, False)]
+ })
+ account_move_line_obj.write(
+ cr, uid, [x.id for x in v.move_ids],
+ {'statement_id': st_line.statement_id.id}, context=context)
+ # End of account_voucher
+ st_line.refresh()
+
+ # AB: The voucher journal isn't automatically posted, so post it (if needed)
+ if not st_line.voucher_id.journal_id.entry_posted:
+ account_move_obj.post(cr, uid, [st_line.voucher_id.move_id.id], context={})
+ return True
+
st = st_line.statement_id
context.update({'date': st_line.date})
@@ -457,22 +505,23 @@
# Bank statements will not consider boolean on journal entry_posted
account_move_obj.post(cr, uid, [move_id], context=context)
- # Shouldn't now be needed as payment and reconciliation of invoices
- # is done through account_voucher
- #"""
- #Account-banking:
- #- Write stored reconcile_id
- #- Pay invoices through workflow
- #"""
- #if st_line.reconcile_id:
- # account_move_line_obj.write(cr, uid, torec, {
- # (st_line.reconcile_id.line_partial_ids and
- # 'reconcile_partial_id' or 'reconcile_id'):
- # st_line.reconcile_id.id }, context=context)
- # for move_line in (st_line.reconcile_id.line_id or []) + (
- # st_line.reconcile_id.line_partial_ids or []):
- # netsvc.LocalService("workflow").trg_trigger(
- # uid, 'account.move.line', move_line.id, cr)
+ """
+ Account-banking:
+ - Write stored reconcile_id
+ - Pay invoices through workflow
+
+ Does not apply to voucher integration, but only to
+ payments and payment orders
+ """
+ if st_line.reconcile_id:
+ account_move_line_obj.write(cr, uid, torec, {
+ (st_line.reconcile_id.line_partial_ids and
+ 'reconcile_partial_id' or 'reconcile_id'):
+ st_line.reconcile_id.id }, context=context)
+ for move_line in (st_line.reconcile_id.line_id or []) + (
+ st_line.reconcile_id.line_partial_ids or []):
+ netsvc.LocalService("workflow").trg_trigger(
+ uid, 'account.move.line', move_line.id, cr)
#""" End account-banking """
return move_id
@@ -935,7 +984,7 @@
Previously (pre-v6) in account_payment/wizard/wizard_pay.py
"""
if context == None:
- context={}
+ context = {}
result = {}
orders = self.browse(cr, uid, ids, context)
order = orders[0]
@@ -1134,7 +1183,7 @@
'''
Create dual function IBAN account for SEPA countries
'''
- if vals['state'] == 'iban':
+ if vals.get('state') == 'iban':
iban = vals.get('acc_number',False) or vals.get('acc_number_domestic',False)
vals['acc_number'], vals['acc_number_domestic'] = (
self._correct_IBAN(iban))
@@ -1236,7 +1285,7 @@
fields.append('state')
records = self._founder.read(cr, uid, ids, fields, context, load)
is_list = True
- if not isinstance(records, list):
+ if not isinstance(records, list):
records = [records,]
is_list = False
for record in records:
@@ -1529,7 +1578,7 @@
"""
total = 0.0
if not ids:
- total
+ return total
for line in self.read(
cr, uid, ids, ['debit', 'credit'], context=context):
total += (line['debit'] or 0.0) - (line['credit'] or 0.0)
=== modified file 'account_banking/banking_import_transaction.py'
--- account_banking/banking_import_transaction.py 2012-04-17 10:58:38 +0000
+++ account_banking/banking_import_transaction.py 2012-05-02 13:35:21 +0000
@@ -88,7 +88,7 @@
elif not invoice_ids:
# create supplier invoice
partner_obj = self.pool.get('res.partner')
- invoice_lines = [(0,0,dict(
+ invoice_lines = [(0, 0, dict(
amount = 1,
price_unit = amount,
name = trans.message or trans.reference,
@@ -247,8 +247,8 @@
# the interactive wizard
return False
- '''Check if the move_line has been cached'''
- return move_line.id in linked_invoices
+ #'''Check if the move_line has been cached'''
+ #return move_line.id in linked_invoices
def _cache(move_line, remaining=0.0):
'''Cache the move_line'''
@@ -430,113 +430,18 @@
return trans, False, False
- def _do_move_reconcile(
- self, cr, uid, move_line_ids, currency, amount, context=None):
- """
- Prepare a reconciliation for a bank transaction of the given
- amount. The caller MUST add the move line associated with the
- bank transaction to the returned reconciliation resource.
-
- If adding the amount does not make the total add up,
- prepare a partial reconciliation. An existing reconciliation on
- the move lines will be taken into account.
-
- :param move_line_ids: List of ids. This will usually be the move
- line of an associated invoice or payment, plus optionally the
- move line of a writeoff.
- :param currency: A res.currency *browse* object to perform math
- operations on the amounts.
- :param amount: the amount of the bank transaction. Amount < 0 in
- case of a credit move on the bank account.
- """
- move_line_obj = self.pool.get('account.move.line')
- reconcile_obj = self.pool.get('account.move.reconcile')
- is_zero = lambda amount: self.pool.get('res.currency').is_zero(
- cr, uid, currency, amount)
- move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context)
- reconcile = False
- for move_line in move_lines:
- if move_line.reconcile_id:
- raise osv.except_osv(
- _('Entry is already reconciled'),
- _("You cannot reconcile the bank transaction with this entry, " +
- "it is already reconciled")
- )
- if move_line.reconcile_partial_id:
- if reconcile and reconcile.id != move_line.reconcile_partial_id.id:
- raise osv.except_osv(
- _('Cannot reconcile'),
- _('Move lines are already partially reconciled, ' +
- 'but not with each other.'))
- reconcile = move_line.reconcile_partial_id
- line_ids = list(set(move_line_ids + (
- [x.id for x in reconcile and ( # reconcile.line_id or
- reconcile.line_partial_ids) or []])))
- if not reconcile:
- reconcile_id = reconcile_obj.create(
- cr, uid, {'type': 'auto' }, context=context)
- reconcile = reconcile_obj.browse(cr, uid, reconcile_id, context=context)
- full = is_zero(
- move_line_obj.get_balance(cr, uid, line_ids) - amount)
- # we should not have to check whether there is a surplus writeoff
- # as any surplus amount *should* have been split off in the matching routine
- if full:
- line_partial_ids = []
- else:
- line_partial_ids = line_ids[:]
- line_ids = []
- reconcile_obj.write(
- cr, uid, reconcile.id,
- { 'line_id': [(6, 0, line_ids)],
- 'line_partial_ids': [(6, 0, line_partial_ids)],
- }, context=context)
- return reconcile.id
-
- def _do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
- """
- Undo a reconciliation, removing the given move line ids. If no
- meaningful (partial) reconciliation remains, delete it.
-
- :param move_line_ids: List of ids. This will usually be the move
- line of an associated invoice or payment, plus optionally the
- move line of a writeoff.
- :param currency: A res.currency *browse* object to perform math
- operations on the amounts.
- """
-
- move_line_obj = self.pool.get('account.move.line')
- reconcile_obj = self.pool.get('account.move.reconcile')
- is_zero = lambda amount: self.pool.get('res.currency').is_zero(
- cr, uid, currency, amount)
- move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context)
- reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id
- line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids]
- for move_line_id in move_line_ids:
- line_ids.remove(move_line_id)
- if len(line_ids) > 1:
- full = is_zero(move_line_obj.get_balance(cr, uid, line_ids))
- if full:
- line_partial_ids = []
- else:
- line_partial_ids = line_ids.copy()
- line_ids = []
- reconcile_obj.write(
- cr, uid, reconcile.id,
- { 'line_partial_ids': [(6, 0, line_ids)],
- 'line_id': [(6, 0, line_partial_ids)],
- }, context=context)
- else:
- reconcile_obj.unlink(cr, uid, reconcile.id, context=context)
- for move_line in move_lines:
- if move_line.invoice:
- # reopening the invoice
- netsvc.LocalService('workflow').trg_validate(
- uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr)
- return True
-
- def _reconcile_move(
- self, cr, uid, transaction_id, context=None):
- transaction = self.browse(cr, uid, transaction_id, context=context)
+ def _confirm_move(self, cr, uid, transaction_id, context=None):
+ """
+ The line is matched against a move (invoice), so generate a payment
+ voucher with the write-off settings that the user requested. The move
+ lines will be generated by the voucher, handling rounding and currency
+ conversion.
+ """
+ if context is None:
+ context = {}
+
+ statement_line_pool = self.pool.get('account.bank.statement.line')
+ transaction = self.browse(cr, uid, transaction_id, context)
if not transaction.move_line_id:
if transaction.match_type == 'invoice':
raise osv.except_osv(
@@ -558,42 +463,119 @@
transaction.statement_line_id.statement_id.name,
transaction.statement_line_id.name
)))
- currency = transaction.statement_line_id.statement_id.currency
- line_ids = [transaction.move_line_id.id]
- if transaction.writeoff_move_line_id:
- line_ids.append(transaction.writeoff_move_line_id.id)
- reconcile_id = self._do_move_reconcile(
- cr, uid, line_ids, currency,
- transaction.transferred_amount, context=context)
- return reconcile_id
-
- def _reconcile_storno(
+
+ st_line = transaction.statement_line_id
+ journal = st_line.statement_id.journal_id
+ if st_line.amount < 0.0:
+ voucher_type = 'payment'
+ account_id = (journal.default_debit_account_id and
+ journal.default_debit_account_id.id or False)
+ else:
+ voucher_type = 'receipt'
+ account_id = (journal.default_credit_account_id and
+ journal.default_credit_account_id.id or False)
+
+ # Use the statement line's date determine the period
+ ctxt = context.copy()
+ ctxt['company_id'] = st_line.company_id.id
+ if 'period_id' in ctxt:
+ del ctxt['period_id']
+ period_id = self.pool.get('account.period').find(
+ cr, uid, st_line.date, context=ctxt)[0]
+
+ # Convert the move line amount to the journal currency
+ move_line_amount = transaction.move_line_id.amount_residual_currency
+ 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)
+ from_curr_id = (transaction.move_line_id.currency_id and
+ transaction.move_line_id.currency_id.id or
+ st_line.statement_id.company_id.currency_id.id)
+ if from_curr_id != to_curr_id:
+ amount_currency = statement_line_pool._convert_currency(
+ cr, uid, from_curr_id, to_curr_id, move_line_amount,
+ round=True, date=time.strftime('%Y-%m-%d'),
+ context=context)
+ else:
+ amount_currency = move_line_amount
+
+ # Check whether this is a full or partial reconciliation
+ if transaction.payment_option == 'with_writeoff':
+ writeoff = abs(st_line.amount) - abs(amount_currency)
+ line_amount = abs(amount_currency)
+ else:
+ writeoff = 0.0
+ line_amount = abs(st_line.amount)
+
+ # Define the voucher
+ voucher = {
+ 'journal_id': st_line.statement_id.journal_id.id,
+ 'partner_id': st_line.partner_id and st_line.partner_id.id or False,
+ 'company_id': st_line.company_id.id,
+ 'type':voucher_type,
+ 'company_id': st_line.company_id.id,
+ 'account_id': account_id,
+ 'amount': abs(st_line.amount),
+ 'writeoff_amount': writeoff,
+ 'payment_option': transaction.payment_option,
+ 'writeoff_acc_id': transaction.writeoff_account_id.id,
+ 'analytic_id': transaction.writeoff_analytic_id.id,
+ 'date': st_line.date,
+ 'date_due': st_line.date,
+ 'period_id': period_id,
+ 'payment_rate_currency_id':to_curr_id,
+ }
+
+ # Define the voucher line
+ vch_line = {
+ #'voucher_id': v_id,
+ 'move_line_id': transaction.move_line_id.id,
+ 'reconcile': True,
+ 'amount': line_amount,
+ 'account_id': transaction.move_line_id.account_id.id,
+ 'type': transaction.move_line_id.credit and 'dr' or 'cr',
+ }
+ voucher['line_ids'] = [(0, 0, vch_line)]
+ voucher_id = self.pool.get('account.voucher').create(
+ cr, uid, voucher, context=context)
+ statement_line_pool.write(
+ cr, uid, st_line.id,
+ {'voucher_id': voucher_id}, context=context)
+ transaction.refresh()
+
+ def _confirm_storno(
self, cr, uid, transaction_id, context=None):
"""
Creation of the reconciliation has been delegated to
*a* direct debit module, to allow for various direct debit styles
"""
- payment_line_obj = self.pool.get('payment.line')
+ payment_line_pool = self.pool.get('payment.line')
+ statement_line_pool = self.pool.get('account.bank.statement.line')
transaction = self.browse(cr, uid, transaction_id, context=context)
if not transaction.payment_line_id:
raise osv.except_osv(
_("Cannot link with storno"),
_("No direct debit order item"))
- return payment_line_obj.debit_storno(
+ reconcile_id = payment_line_pool.debit_storno(
cr, uid,
transaction.payment_line_id.id,
transaction.statement_line_id.amount,
transaction.statement_line_id.currency,
transaction.storno_retry,
context=context)
+ statement_line_pool.write(
+ cr, uid, transaction.statement_line_id.id,
+ {'reconcile_id': reconcile_id}, context=context)
+ transaction.refresh()
- def _reconcile_payment_order(
+ def _confirm_payment_order(
self, cr, uid, transaction_id, context=None):
"""
Creation of the reconciliation has been delegated to
*a* direct debit module, to allow for various direct debit styles
"""
payment_order_obj = self.pool.get('payment.order')
+ statement_line_pool = self.pool.get('account.bank.statement.line')
transaction = self.browse(cr, uid, transaction_id, context=context)
if not transaction.payment_order_id:
raise osv.except_osv(
@@ -603,14 +585,17 @@
raise osv.except_osv(
_("Cannot reconcile"),
_("Reconcile payment order not implemented"))
- return payment_order_obj.debit_reconcile_transfer(
+ reconcile_id = payment_order_obj.debit_reconcile_transfer(
cr, uid,
transaction.payment_order_id.id,
transaction.statement_line_id.amount,
transaction.statement_line_id.currency,
context=context)
+ statement_line_pool.write(
+ cr, uid, transaction.statement_line_id.id,
+ {'reconcile_id': reconcile_id}, context=context)
- def _reconcile_payment(
+ def _confirm_payment(
self, cr, uid, transaction_id, context=None):
"""
Do some housekeeping on the payment line
@@ -624,7 +609,7 @@
'date_done': transaction.effective_date,
}
)
- return self._reconcile_move(cr, uid, transaction_id, context=context)
+ self._confirm_move(cr, uid, transaction_id, context=context)
def _cancel_payment(
self, cr, uid, transaction_id, context=None):
@@ -653,20 +638,107 @@
transaction.statement_line_id.amount,
transaction.statement_line_id.currency)
- def _cancel_move(
- self, cr, uid, transaction_id, context=None):
- statement_line_obj = self.pool.get('account.bank.statement.line')
- transaction = self.browse(cr, uid, transaction_id, context=context)
- move_line_id = transaction.move_line_id.id
+ def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None):
+ """
+ Legacy method. Allow for canceling bank statement lines that
+ were confirmed using earlier versions of the interactive wizard branch.
+
+ Undo a reconciliation, removing the given move line ids. If no
+ meaningful (partial) reconciliation remains, delete it.
+
+ :param move_line_ids: List of ids. This will usually be the move
+ line of an associated invoice or payment, plus optionally the
+ move line of a writeoff.
+ :param currency: A res.currency *browse* object to perform math
+ operations on the amounts.
+ """
+ move_line_obj = self.pool.get('account.move.line')
+ reconcile_obj = self.pool.get('account.move.reconcile')
+ is_zero = lambda amount: self.pool.get('res.currency').is_zero(
+ cr, uid, currency, amount)
+ move_lines = move_line_obj.browse(cr, uid, move_line_ids, context=context)
+ reconcile = move_lines[0].reconcile_id or move_lines[0].reconcile_partial_id
+ line_ids = [x.id for x in reconcile.line_id or reconcile.line_partial_ids]
+ for move_line_id in move_line_ids:
+ line_ids.remove(move_line_id)
+ if len(line_ids) > 1:
+ full = is_zero(move_line_obj.get_balance(cr, uid, line_ids))
+ if full:
+ line_partial_ids = []
+ else:
+ line_partial_ids = list(line_ids)
+ line_ids = []
+ reconcile_obj.write(
+ cr, uid, reconcile.id,
+ { 'line_partial_ids': [(6, 0, line_partial_ids)],
+ 'line_id': [(6, 0, line_ids)],
+ }, context=context)
+ else:
+ reconcile_obj.unlink(cr, uid, reconcile.id, context=context)
+ for move_line in move_lines:
+ if move_line.invoice:
+ # reopening the invoice
+ netsvc.LocalService('workflow').trg_validate(
+ uid, 'account.invoice', move_line.invoice.id, 'undo_paid', cr)
+ return True
+
+ def _legacy_clear_up_writeoff(self, cr, uid, transaction, context=None):
+ """
+ Legacy method to support upgrades older installations of the
+ interactive wizard branch. To be removed after 6.2
+ clear up the writeoff move
+ """
+ if transaction.writeoff_move_line_id:
+ move_pool = self.pool.get('account.move')
+ move_pool.button_cancel(
+ cr, uid, [transaction.writeoff_move_line_id.move_id.id],
+ context=context)
+ move_pool.unlink(
+ cr, uid, [transaction.writeoff_move_line_id.move_id.id],
+ context=context)
+ return True
+
+ def _legacy_cancel_move(
+ self, cr, uid, transaction, context=None):
+ """
+ Legacy method to support upgrades from older installations
+ of the interactive wizard branch.
+ """
currency = transaction.statement_line_id.statement_id.currency
line_ids = [transaction.move_line_id.id]
+ statement_line_obj = self.pool.get('account.bank.statement.line')
if transaction.writeoff_move_line_id:
line_ids.append(transaction.writeoff_move_line_id.id)
- self._do_move_unreconcile(
+ self._legacy_do_move_unreconcile(
cr, uid, line_ids, currency, context=context)
statement_line_obj.write(
cr, uid, transaction.statement_line_id.id,
{'reconcile_id': False}, context=context)
+
+ def _cancel_voucher(
+ self, cr, uid, transaction_id, context=None):
+ voucher_pool = self.pool.get('account.voucher')
+ transaction = self.browse(cr, uid, transaction_id, context=context)
+ st_line = transaction.statement_line_id
+ if transaction.match_type:
+ if st_line.voucher_id:
+ # Although vouchers can be associated with statement lines
+ # in standard OpenERP, we consider ourselves owner of the voucher
+ # if the line has an associated transaction
+ # Upon canceling of the statement line/transaction,
+ # we cancel and delete the vouchers.
+ # Otherwise, the statement line will leave the voucher
+ # unless the statement line itself is deleted.
+ voucher_pool.cancel_voucher(
+ cr, uid, [st_line.voucher_id.id], context=context)
+ voucher_pool.action_cancel_draft(
+ cr, uid, [st_line.voucher_id.id], context=context)
+ voucher_pool.unlink(
+ cr, uid, [st_line.voucher_id.id], context=context)
+ # Allow canceling of legacy entries
+ if not st_line.voucher_id and st_line.reconcile_id:
+ self._legacy_cancel_move(cr, uid, transaction, context=context)
+
return True
def _cancel_storno(
@@ -694,11 +766,15 @@
else:
account_id = journal.default_debit_account_id.id
cancel_line = False
- for line in transaction.statement_line_id.move_id.line_id:
+ move_lines = [
+ # There should usually be just one move, I think
+ move.line_id for move in transaction.statement_line_id.move_ids
+ ]
+ for line in move_lines:
if line.account_id.id != account_id:
cancel_line = line
break
- if not cancel_line: # debug
+ if not cancel_line:
raise osv.except_osv(
_("Cannot cancel link with storno"),
_("Line id not found"))
@@ -724,16 +800,16 @@
cancel_map = {
'storno': _cancel_storno,
- 'invoice': _cancel_move,
- 'manual': _cancel_move,
- 'move': _cancel_move,
+ 'invoice': _cancel_voucher,
+ 'manual': _cancel_voucher,
+ 'move': _cancel_voucher,
'payment_order': _cancel_payment_order,
'payment': _cancel_payment,
}
+
def cancel(self, cr, uid, ids, context=None):
if ids and isinstance(ids, (int, float)):
ids = [ids]
- move_obj = self.pool.get('account.move')
for transaction in self.browse(cr, uid, ids, context):
if not transaction.match_type:
continue
@@ -743,31 +819,25 @@
_("No method found to cancel this type"))
self.cancel_map[transaction.match_type](
self, cr, uid, transaction.id, context)
- # clear up the writeoff move
- if transaction.writeoff_move_line_id:
- move_obj.button_cancel(
- cr, uid, [transaction.writeoff_move_line_id.move_id.id],
- context=context)
- move_obj.unlink(
- cr, uid, [transaction.writeoff_move_line_id.move_id.id],
- context=context)
+ self._legacy_clear_up_writeoff(cr, uid, transaction, context=context)
return True
- reconcile_map = {
- 'storno': _reconcile_storno,
- 'invoice': _reconcile_move,
- 'manual': _reconcile_move,
- 'payment_order': _reconcile_payment_order,
- 'payment': _reconcile_payment,
- 'move': _reconcile_move,
+ confirm_map = {
+ 'storno': _confirm_storno,
+ 'invoice': _confirm_move,
+ 'manual': _confirm_move,
+ 'payment_order': _confirm_payment_order,
+ 'payment': _confirm_payment,
+ 'move': _confirm_move,
}
- def reconcile(self, cr, uid, ids, context=None):
+
+ def confirm(self, cr, uid, ids, context=None):
if ids and isinstance(ids, (int, float)):
ids = [ids]
for transaction in self.browse(cr, uid, ids, context):
if not transaction.match_type:
continue
- if transaction.match_type not in self.reconcile_map:
+ if transaction.match_type not in self.confirm_map:
raise osv.except_osv(
_("Cannot reconcile"),
_("Cannot reconcile type %s. No method found to " +
@@ -782,19 +852,11 @@
"this match type.") %
transaction.statement_line_id.name
)
- self._generate_writeoff_move(
- cr, uid, transaction.id, context=context)
- # run the method that is appropriate for this match type
- reconcile_id = self.reconcile_map[transaction.match_type](
+ # Generalize this bit and move to the confirmation
+ # methods that actually do create a voucher?
+ self.confirm_map[transaction.match_type](
self, cr, uid, transaction.id, context)
- self.pool.get('account.bank.statement.line').write(
- cr, uid, transaction.statement_line_id.id,
- {'reconcile_id': reconcile_id}, context=context)
- # TODO
- # update the statement line bank account reference
- # as follows (from _match_invoice)
-
"""
account_ids = [
x.id for x in bank_account_ids
@@ -802,64 +864,7 @@
][0]
"""
return True
-
-
- def _generate_writeoff_move(self, cr, uid, ids, context):
- if ids and isinstance(ids, (int, float)):
- ids = [ids]
- move_line_obj = self.pool.get('account.move.line')
- move_obj = self.pool.get('account.move')
- for trans in self.browse(cr, uid, ids, context=context):
- # Get the period for the company and date
- ctxt = context.copy()
- ctxt['company_id'] = trans.company_id.id
- periods = self.pool.get('account.period').find(
- cr, uid, trans.statement_line_id.date, context=ctxt)
- period_id = periods and periods[0] or False
-
- move_id = move_obj.create(cr, uid, {
- 'journal_id': trans.writeoff_journal_id.id,
- 'period_id': period_id,
- 'date': trans.statement_line_id.date,
- 'name': '(write-off) %s' % (
- trans.move_line_id.move_id.name or ''),
- }, context=context)
- if trans.residual > 0:
- writeoff_debit = trans.residual
- writeoff_credit = False
- else:
- writeoff_debit = False
- writeoff_credit = - trans.residual
- vals = {
- 'name': trans.statement_line_id.name,
- 'date': trans.statement_line_id.date,
- 'ref': trans.statement_line_id.ref,
- 'move_id': move_id,
- 'partner_id': (trans.statement_line_id.partner_id and
- trans.statement_line_id.partner_id.id or False),
- 'account_id': trans.statement_line_id.account_id.id,
- 'credit': writeoff_debit,
- 'debit': writeoff_credit,
- 'journal_id': trans.writeoff_journal_id.id,
- 'period_id': period_id,
- 'currency_id': trans.statement_line_id.statement_id.currency.id,
- 'analytic_account_id': trans.writeoff_analytic_id.id,
- }
- move_line_id = move_line_obj.create(
- cr, uid, vals, context=context)
- self.write(
- cr, uid, trans.id,
- {'writeoff_move_line_id': move_line_id}, context=context)
- vals.update({
- 'account_id': trans.writeoff_account_id.id,
- 'credit': writeoff_credit,
- 'debit': writeoff_debit,
- })
- move_line_obj.create(
- cr, uid, vals, context=context)
- move_obj.post(
- cr, uid, [move_id], context=context)
-
+
def _match_storno(
self, cr, uid, trans, log, context=None):
payment_line_obj = self.pool.get('payment.line')
@@ -1231,7 +1236,7 @@
provision_costs_description = False,
), context=context)
# rebrowse the current record after writing
- transaction=self.browse(cr, uid, transaction.id, context=context)
+ transaction = self.browse(cr, uid, transaction.id, context=context)
# Match full direct debit orders
if transaction.type == bt.DIRECT_DEBIT:
move_info = self._match_debit_order(
@@ -1456,10 +1461,15 @@
"""
if not ids:
return {}
- res = {}
+ res = dict([(x, False) for x in ids])
for transaction in self.browse(cr, uid, ids, context):
- res[transaction.id] = abs(transaction.transferred_amount) - abs(transaction.move_currency_amount)
-
+ res[transaction.id] = (
+ not(transaction.move_currency_amount is False)
+ and (
+ transaction.transferred_amount -
+ transaction.move_currency_amount
+ )
+ or False)
return res
def _get_match_multi(self, cr, uid, ids, name, args, context=None):
@@ -1510,12 +1520,11 @@
This will be used to calculate the write-off amount (in statement currency).
"""
if not ids:
- return {}
+ return {}
+ res = dict([(x, False) for x in ids])
stline_pool = self.pool.get('account.bank.statement.line')
- res = {}
-
for transaction in self.browse(cr, uid, ids, context):
if transaction.move_line_id:
@@ -1612,15 +1621,25 @@
'invoice_id', 'transaction_id', 'Matching invoices'),
'invoice_id': fields.many2one(
'account.invoice', 'Invoice to reconcile'),
- 'payment_line_id': fields.many2one('payment.line', 'Payment line'),
'residual': fields.function(
_get_residual, method=True, string='Residual', type='float'),
'writeoff_account_id': fields.many2one(
'account.account', 'Write-off account',
domain=[('type', '!=', 'view')]),
- 'payment_option':fields.selection([('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')], 'Payment Difference',
- 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)"),
+ 'payment_option':fields.selection(
+ [
+ ('without_writeoff', 'Keep Open'),
+ ('with_writeoff', 'Reconcile Payment Balance')
+ ], 'Payment Difference',
+ 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)"),
+ ),
'writeoff_amount': fields.float('Difference Amount'),
+ # Legacy field: to be removed after 6.2
'writeoff_move_line_id': fields.many2one(
'account.move.line', 'Write off move line'),
'writeoff_analytic_id': fields.many2one(
@@ -1648,8 +1667,9 @@
'import_transaction_id', 'match_multi', type='boolean',
string='Multi match', readonly=True),
'residual': fields.related(
- 'import_transaction_id', 'residual', type='float',
- string='Residual'),
+ 'import_transaction_id', 'residual', type='float',
+ string='Residual', readonly=True,
+ ),
'duplicate': fields.related(
'import_transaction_id', 'duplicate', type='boolean',
string='Possible duplicate import', readonly=True),
@@ -1660,16 +1680,9 @@
('payment_order', 'Payment order'),
('storno', 'Storno')],
string='Match type', readonly=True,),
- 'residual': fields.related(
- 'import_transaction_id', 'residual', type='float',
- string='Residual', readonly=True,
- ),
'state': fields.selection(
[('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
readonly=True, required=True),
- 'move_id': fields.many2one(
- 'account.move', 'Move', readonly=True,
- help="The accounting move associated with this line"),
}
_defaults = {
@@ -1690,8 +1703,9 @@
res = wizard_obj.create_act_window(cr, uid, res_id, context=context)
return res
-
- def _convert_currency(self, cr, uid, from_curr_id, to_curr_id, from_amount, round=False, date=None, context=None):
+ def _convert_currency(
+ self, cr, uid, from_curr_id, to_curr_id, from_amount,
+ round=False, date=None, context=None):
"""Convert currency amount using the company rate on a specific date"""
curr_obj = self.pool.get('res.currency')
if context:
@@ -1701,10 +1715,11 @@
if date:
ctxt["date"] = date
- amount = curr_obj.compute(cr, uid, from_curr_id, to_curr_id, from_amount, round=round, context=ctxt)
+ amount = curr_obj.compute(
+ cr, uid, from_curr_id, to_curr_id, from_amount,
+ round=round, context=ctxt)
return amount
-
def confirm(self, cr, uid, ids, context=None):
"""
Create (or update) a voucher for each statement line, and then generate
@@ -1712,10 +1727,10 @@
If a line does not have a move line against it, but has an account, then
generate a journal entry that moves the line amount to the specified account.
"""
- voucher_pool = self.pool.get('account.voucher')
statement_pool = self.pool.get('account.bank.statement')
obj_seq = self.pool.get('ir.sequence')
move_pool = self.pool.get('account.move')
+ import_transaction_obj = self.pool.get('banking.import.transaction')
for st_line in self.browse(cr, uid, ids, context):
if st_line.state != 'draft':
@@ -1734,157 +1749,47 @@
"journal!") % (st_line.statement_id.journal_id.name,))
if not st_line.amount:
continue
-
+ if not st_line.period_id:
+ self.write(
+ cr, uid, [st_line.id], {
+ 'period_id': self._get_period(
+ cr, uid, {'date': st_line.date})
+ })
+ st_line.refresh()
# Generate the statement number, if it is not already done
st = st_line.statement_id
if not st.name == '/':
st_number = st.name
else:
if st.journal_id.sequence_id:
- c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}
+ period = st.period_id or st_line.period_id
+ c = {'fiscalyear_id': period.fiscalyear_id.id}
st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c)
else:
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement')
- statement_obj.write(cr, uid, [st.id], {'name': st_number}, context=context)
-
- # Check if this line has been matched against a journal item
- if st_line.import_transaction_id.move_line_id:
- # Line has been matched, so post it via a voucher
- self._post_with_voucher(cr, uid, ids, st_line, voucher_pool, move_pool, context=context)
-
- else:
- # Check to see if the line has an account that can be used to generate a journal entry
- if st_line.account_id:
- # Generate a journal for the entry using the standard bank statement code
- self._create_move(cr, uid, st_line, statement_pool, st, st_number, context=context)
- else:
- raise osv.except_osv(
- _('Statement line has no account'),
- _("You cannot confirm a bank statement line that has no account against it (%s.%s)") %
- (st_line.statement_id.name, st_line.name,))
-
+ statement_pool.write(cr, uid, [st.id], {'name': st_number}, context=context)
+
+ if st_line.import_transaction_id:
+ import_transaction_obj.confirm(
+ cr, uid, st_line.import_transaction_id.id, context)
+ st_line.refresh()
+ st_line_number = statement_pool.get_next_st_line_number(
+ cr, uid, st_number, st_line, context)
+ company_currency_id = st.journal_id.company_id.currency_id.id
+ statement_pool.create_move_from_st_line(
+ cr, uid, st_line.id, company_currency_id, st_line_number, context)
+ self.write(
+ cr, uid, st_line.id, {'state': 'confirmed'}, context)
return True
- def _create_move(self, cr, uid, st_line, statement_pool, st, st_number, context):
- """
- The line is not matched against a move, but the account has been defined for the line.
- Generate a journal entry for the statement line that transfers the full amount against the account.
- """
- st_line_number = statement_pool.get_next_st_line_number(cr, uid, st_number, st_line, context)
- company_currency_id = st.journal_id.company_id.currency_id.id
- move_id = statement_pool.create_move_from_st_line(cr, uid, st_line.id, company_currency_id, st_line_number, context)
- self.write(cr, uid, st_line.id, {'state': 'confirmed', 'move_id': move_id}, context)
-
-
- def _post_with_voucher(self, cr, uid, ids, st_line, voucher_pool, move_pool, context):
- # Check if a voucher has already been created
- if st_line.voucher_id:
- # There's an existing voucher on the statement line which was probably created
- # manually. This may have been done because it was a single payment for multiple
- # invoices. Just get the voucher ID.
- voucher_id = st_line.voucher_id.id
- else:
- # Create a voucher and store the ID on the statement line
- voucher_id = self._create_voucher(cr, uid, ids, st_line, context=context)
- self.pool.get('account.bank.statement.line').write(cr,uid,st_line.id,{'voucher_id':voucher_id} , context=context)
-
- # If the voucher is in draft mode, then post it
- voucher = voucher_pool.browse(cr, uid, voucher_id, context=context)
- if voucher.state in ('draft','proforma'):
- voucher.action_move_line_create()
-
- # Update the statement line to indicate that it has been posted
- # ... no longer need to set the move_id on the voucher?
- self.write(cr, uid, st_line.id, {'state': 'confirmed'}, context)
-
- # The voucher journal isn't automatically posted, so post it (if needed)
- if not voucher.journal_id.entry_posted:
- voucher = voucher_pool.browse(cr, uid, voucher_id, context=context)
- move_pool.post(cr, uid, [voucher.move_id.id], context={})
-
-
- def _create_voucher(self, cr, uid, ids, st_line, context):
- """
- The line is matched against a move (invoice), so generate a payment voucher with the write-off settings that the
- user requested. The move lines will be generated by the voucher, handling rounding and currency conversion.
- """
- journal = st_line.statement_id.journal_id
- if st_line.amount < 0.0:
- voucher_type = 'payment'
- account_id = journal.default_debit_account_id and journal.default_debit_account_id.id or False
- else:
- voucher_type = 'receipt'
- account_id = journal.default_credit_account_id and journal.default_credit_account_id.id or False
-
- # Use the statement line's date determine the period
- ctxt = context.copy()
- ctxt['company_id'] = st_line.company_id.id
- if 'period_id' in ctxt:
- del ctxt['period_id']
- period_id = self.pool.get('account.period').find(cr, uid, st_line.date, context=ctxt)[0]
-
- # Convert the move line amount to the journal currency
- move_line_amount = st_line.import_transaction_id.move_line_id.amount_residual_currency
- 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
- 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
- if from_curr_id != to_curr_id:
- amount_currency = self._convert_currency(cr, uid, from_curr_id, to_curr_id, move_line_amount, round=True,
- date=time.strftime('%Y-%m-%d'), context=context)
- else:
- amount_currency = move_line_amount
-
- # Check whether this is a full or partial reconciliation
- if st_line.import_transaction_id.payment_option=='with_writeoff':
- writeoff = abs(st_line.amount)-abs(amount_currency)
- line_amount = abs(amount_currency)
- else:
- writeoff = 0.0
- line_amount = abs(st_line.amount)
-
- # Define the voucher
- voucher = {
- 'journal_id': st_line.statement_id.journal_id.id,
- 'partner_id': st_line.partner_id and st_line.partner_id.id or False,
- 'company_id': st_line.company_id.id,
- 'type':voucher_type,
- 'company_id': st_line.company_id.id,
- 'account_id': account_id,
- 'amount': abs(st_line.amount),
- 'writeoff_amount': writeoff,
- 'payment_option': st_line.import_transaction_id.payment_option,
- 'writeoff_acc_id': st_line.import_transaction_id.writeoff_account_id.id,
- 'analytic_id': st_line.import_transaction_id.writeoff_analytic_id.id,
- 'date': st_line.date,
- 'date_due': st_line.date,
- 'period_id': period_id,
- 'payment_rate_currency_id':to_curr_id,
- }
-
- # Define the voucher line
- vch_line = {
- #'voucher_id': v_id,
- 'move_line_id': st_line.import_transaction_id.move_line_id.id,
- 'reconcile': True,
- 'amount': line_amount,
- 'account_id': st_line.import_transaction_id.move_line_id.account_id.id,
- 'type': st_line.import_transaction_id.move_line_id.credit and 'dr' or 'cr',
- }
- voucher['line_ids'] = [(0,0,vch_line)]
- v_id = self.pool.get('account.voucher').create(cr, uid, voucher, context=context)
-
- return v_id
-
-
def cancel(self, cr, uid, ids, context=None):
if ids and isinstance(ids, (int, float)):
ids = [ids]
- account_move_obj = self.pool.get('account.move')
import_transaction_obj = self.pool.get('banking.import.transaction')
- voucher_pool = self.pool.get('account.voucher')
+ move_pool = self.pool.get('account.move')
transaction_cancel_ids = []
- voucher_cancel_ids = []
+ set_draft_ids = []
move_unlink_ids = []
- set_draft_ids = []
# harvest ids for various actions
for st_line in self.browse(cr, uid, ids, context):
if st_line.state != 'confirmed':
@@ -1895,32 +1800,23 @@
_("The bank statement that this transaction belongs to has "
"already been confirmed"))
- # Check if the transaction has a voucher
- if st_line.voucher_id:
- voucher_cancel_ids.append(st_line.voucher_id.id)
- else:
- if st_line.import_transaction_id:
- transaction_cancel_ids.append(st_line.import_transaction_id.id)
- if st_line.move_id:
- move_unlink_ids.append(st_line.move_id.id)
- else:
- raise osv.except_osv(
- _("Cannot cancel bank transaction"),
- _("Cannot cancel this bank transaction. The information "
- "needed to undo the accounting entries has not been "
- "recorded"))
+ if st_line.import_transaction_id:
+ # Cancel transaction immediately.
+ # If it has voucher, this will clean up
+ # the moves on the st_line.
+ import_transaction_obj.cancel(
+ cr, uid, [st_line.import_transaction_id.id], context=context)
+ st_line.refresh()
+ for line in st_line.move_ids:
+ # We allow for people canceling and removing
+ # the associated payments, which can lead to confirmed
+ # statement lines without an associated move
+ move_unlink_ids.append(line.id)
set_draft_ids.append(st_line.id)
- # Cancel and delete the vouchers
- voucher_pool.cancel_voucher(cr, uid, voucher_cancel_ids, context=context)
- voucher_pool.action_cancel_draft(cr, uid, voucher_cancel_ids, context=context)
- voucher_pool.unlink(cr, uid, voucher_cancel_ids, context=context)
-
- # Perform actions
- import_transaction_obj.cancel(
- cr, uid, transaction_cancel_ids, context=context)
- account_move_obj.button_cancel(cr, uid, move_unlink_ids, context)
- account_move_obj.unlink(cr, uid, move_unlink_ids, context)
+ move_pool.button_cancel(
+ cr, uid, move_unlink_ids, context=context)
+ move_pool.unlink(cr, uid, move_unlink_ids, context=context)
self.write(
cr, uid, set_draft_ids, {'state': 'draft'}, context=context)
return True
@@ -1934,8 +1830,12 @@
ids = [ids]
for line in self.browse(cr, uid, ids, context=context):
if line.state == 'confirmed':
- raise osv.except_osv(_('Confirmed Statement Line'), _("You cannot delete a confirmed Statement Line: '%s'" % line.name))
- return super(account_bank_statement_line,self).unlink(cr, uid, ids, context=context)
+ raise osv.except_osv(
+ _('Confirmed Statement Line'),
+ _("You cannot delete a confirmed Statement Line"
+ ": '%s'" % line.name))
+ return super(account_bank_statement_line, self).unlink(
+ cr, uid, ids, context=context)
account_bank_statement_line()
@@ -1980,7 +1880,7 @@
# protect against misguided manual changes
for line in st.move_line_ids:
- if line.state <> 'valid':
+ if line.state != 'valid':
raise osv.except_osv(_('Error !'),
_('The account entries lines are not in valid state.'))
=== 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-02 13:35:21 +0000
@@ -21,6 +21,7 @@
#
##############################################################################
from osv import osv, fields
+from openerp.tools.translate import _
"""
@@ -38,7 +39,7 @@
"""
Return a popup window for this model
"""
- if isinstance(ids, (int,long)):
+ if isinstance(ids, (int, long)):
ids = [ids]
return {
'name': self._description,
@@ -160,9 +161,7 @@
statement_line_obj = self.pool.get('account.bank.statement.line')
for wiz in self.browse(
cr, uid, ids, context=context):
- invoice_ids = False
move_line_id = False
- move_line_ids = False
invoice_id = manual_invoice_id
if invoice_id:
invoice = invoice_obj.browse(
=== 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-02 13:35:21 +0000
@@ -104,7 +104,6 @@
_("Cannot unreconcile"),
_("Cannot unreconcile debit order: "+
"Workflow will not allow it."))
-
return True
def test_undo_done(self, cr, uid, ids, context=None):
=== 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-02 13:35:21 +0000
@@ -13,9 +13,9 @@
Maybe apply trick in fields_view_get instead, for
better compatibility with other modules?
-->
- <button name="invoice_open" position="attributes">
+ <!-- button name="invoice_open" position="attributes">
<attribute name="states">draft,proforma2,debit_denied</attribute>
- </button>
+ </button -->
<button string='Re-Open' position="attributes">
<attribute name="states">paid,debit_denied</attribute>
<!--
=== 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-02 13:35:21 +0000
@@ -8,20 +8,44 @@
<field name="kind">function</field>
</record>
<record id="paid_to_debit_denied" model="workflow.transition">
+ <!--
+ Set an invoice to state debit denied, either manually
+ or by confirming a bank statement line that constitutes
+ a fatal storno
+ -->
<field name="act_from" ref="account.act_paid"/>
<field name="act_to" ref="act_debit_denied"/>
<field name="signal">invoice_debit_denied</field>
</record>
+ <record id="open_test_to_debit_denied" model="workflow.transition">
+ <!--
+ A storno leads to unreconciling the move line, which
+ reopens the invoice. We need to allow a transition from
+ this state to the debit denied state if the storno is fatal.
+ -->
+ <field name="act_from" ref="account.act_open_test"/>
+ <field name="act_to" ref="act_debit_denied"/>
+ <field name="signal">invoice_debit_denied</field>
+ </record>
<record id="debit_denied_to_paid" model="workflow.transition">
+ <!--
+ Cancel a bank statement line that constitutes a fatal
+ storno
+ -->
<field name="act_from" ref="act_debit_denied"/>
<field name="act_to" ref="account.act_paid"/>
<field name="condition">test_undo_debit_denied()</field>
<field name="signal">undo_debit_denied</field>
</record>
<record id="debit_denied_to_open" model="workflow.transition">
+ <!--
+ Allow the user to manually reset a debit denied status
+ on a paid invoice (but only after manually unreconciling
+ the invoice)
+ -->
<field name="act_from" ref="act_debit_denied"/>
- <field name="act_to" ref="account.act_open"/>
- <field name="signal">invoice_open</field>
+ <field name="act_to" ref="account.act_open_test"/>
+ <field name="signal">open_test</field>
</record>
</data>
</openerp>
Follow ups