mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
[RFR] Restore confirm and cancel logic for other match types
[RFR] Adapt direct debit workflow to 6.1
This commit is contained in:
@@ -457,22 +457,23 @@ class account_bank_statement(osv.osv):
|
||||
# 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
|
||||
|
||||
@@ -430,114 +430,12 @@ class banking_import_transaction(osv.osv):
|
||||
|
||||
return trans, False, False
|
||||
|
||||
def _do_move_reconcile(
|
||||
self, cr, uid, move_line_ids, currency, amount, context=None):
|
||||
def _confirm_move(self, cr, uid, transaction_id, 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 _create_voucher_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.
|
||||
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 = {}
|
||||
@@ -638,50 +536,46 @@ class banking_import_transaction(osv.osv):
|
||||
'type': transaction.move_line_id.credit and 'dr' or 'cr',
|
||||
}
|
||||
voucher['line_ids'] = [(0,0,vch_line)]
|
||||
v_id = self.pool.get('account.voucher').create(
|
||||
voucher_id = self.pool.get('account.voucher').create(
|
||||
cr, uid, voucher, context=context)
|
||||
|
||||
return v_id
|
||||
statement_line_pool.write(
|
||||
cr, uid, st_line.id,
|
||||
{'voucher_id': voucher_id}, context=context)
|
||||
transaction.refresh()
|
||||
|
||||
def _reconcile_move(
|
||||
self, cr, uid, transaction_id, context=None):
|
||||
transaction = self.browse(cr, uid, transaction_id, context=context)
|
||||
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(
|
||||
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(
|
||||
@@ -691,14 +585,17 @@ class banking_import_transaction(osv.osv):
|
||||
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
|
||||
@@ -712,7 +609,7 @@ class banking_import_transaction(osv.osv):
|
||||
'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):
|
||||
@@ -755,7 +652,6 @@ class banking_import_transaction(osv.osv):
|
||||
: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(
|
||||
@@ -867,7 +763,7 @@ class banking_import_transaction(osv.osv):
|
||||
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"))
|
||||
@@ -903,7 +799,7 @@ class banking_import_transaction(osv.osv):
|
||||
def cancel(self, cr, uid, ids, context=None):
|
||||
if ids and isinstance(ids, (int, float)):
|
||||
ids = [ids]
|
||||
move_obj = self.pool.get('account.move')
|
||||
move_pool = self.pool.get('account.move')
|
||||
for transaction in self.browse(cr, uid, ids, context):
|
||||
if not transaction.match_type:
|
||||
continue
|
||||
@@ -918,28 +814,28 @@ class banking_import_transaction(osv.osv):
|
||||
# We allow for people canceling and removing
|
||||
# the associated payments, which can lead to confirmed
|
||||
# statement lines without an associated move
|
||||
account_move_obj.button_cancel(
|
||||
cr, uid, [transaction.statement_line_id.move_id], context)
|
||||
account_move_obj.unlink(
|
||||
cr, uid, [transaction.statement_line_id.move_id], context)
|
||||
move_pool.button_cancel(
|
||||
cr, uid, [transaction.statement_line_id.move_id.id], context)
|
||||
move_pool.unlink(
|
||||
cr, uid, [transaction.statement_line_id.move_id.id], context)
|
||||
return True
|
||||
|
||||
create_voucher_map = {
|
||||
# 'storno': _create_voucher_storno,
|
||||
'invoice': _create_voucher_move,
|
||||
'manual': _create_voucher_move,
|
||||
# 'payment_order': _create_voucher_payment_order,
|
||||
# 'payment': _create_voucher_payment,
|
||||
'move': _create_voucher_move,
|
||||
confirm_map = {
|
||||
'storno': _confirm_storno,
|
||||
'invoice': _confirm_move,
|
||||
'manual': _confirm_move,
|
||||
'payment_order': _confirm_payment_order,
|
||||
'payment': _confirm_payment,
|
||||
'move': _confirm_move,
|
||||
}
|
||||
|
||||
def create_voucher(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.create_voucher_map:
|
||||
if transaction.match_type not in self.confirm_map:
|
||||
raise osv.except_osv(
|
||||
_("Cannot reconcile"),
|
||||
_("Cannot reconcile type %s. No method found to " +
|
||||
@@ -954,16 +850,11 @@ class banking_import_transaction(osv.osv):
|
||||
"this match type.") %
|
||||
transaction.statement_line_id.name
|
||||
)
|
||||
voucher_id = self.create_voucher_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,
|
||||
{'voucher_id': voucher_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
|
||||
@@ -1568,10 +1459,15 @@ class banking_import_transaction(osv.osv):
|
||||
"""
|
||||
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):
|
||||
@@ -1623,11 +1519,10 @@ class banking_import_transaction(osv.osv):
|
||||
"""
|
||||
if not ids:
|
||||
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:
|
||||
@@ -1874,9 +1769,9 @@ class account_bank_statement_line(osv.osv):
|
||||
statement_obj.write(cr, uid, [st.id], {'name': st_number}, context=context)
|
||||
|
||||
if st_line.import_transaction_id:
|
||||
import_transaction_obj.create_voucher(
|
||||
import_transaction_obj.confirm(
|
||||
cr, uid, st_line.import_transaction_id.id, context)
|
||||
st_line.refresh()
|
||||
st_line.refresh()
|
||||
if st_line.voucher_id:
|
||||
|
||||
# Check if this line has been matched against a journal item
|
||||
@@ -1896,16 +1791,20 @@ class account_bank_statement_line(osv.osv):
|
||||
|
||||
return True
|
||||
|
||||
def _create_move(self, cr, uid, st_line, statement_pool, st, st_number, context):
|
||||
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.
|
||||
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)
|
||||
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)
|
||||
|
||||
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_voucher(self, cr, uid, ids, st_line, move_pool, context):
|
||||
# If the voucher is in draft mode, then post it
|
||||
|
||||
@@ -104,7 +104,6 @@ class payment_order(osv.osv):
|
||||
_("Cannot unreconcile"),
|
||||
_("Cannot unreconcile debit order: "+
|
||||
"Workflow will not allow it."))
|
||||
|
||||
return True
|
||||
|
||||
def test_undo_done(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -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>
|
||||
<!--
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user