mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
[FIX] cascading deletes for banking_import_transaction and
account_bank_statement_line didn't work [ADD] function to split off some amount from a statement line [ADD] unsplit transactions/statement lines when deleting split ones [ADD] allow to manually match multiple invoices/move lines causing the statement line to be split according to the amounts given
This commit is contained in:
@@ -1587,6 +1587,22 @@ class banking_import_transaction(osv.osv):
|
||||
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Unsplit if this if a split transaction
|
||||
"""
|
||||
for this in self.browse(cr, uid, ids, context):
|
||||
if this.parent_id:
|
||||
this.parent_id.write(
|
||||
{'transferred_amount':
|
||||
this.parent_id.transferred_amount + \
|
||||
this.transferred_amount,
|
||||
})
|
||||
this.parent_id.refresh()
|
||||
return super(banking_import_transaction, self).unlink(
|
||||
cr, uid, ids, context=context)
|
||||
|
||||
|
||||
column_map = {
|
||||
# used in bank_import.py, converting non-osv transactions
|
||||
'statement_id': 'statement',
|
||||
@@ -1638,7 +1654,7 @@ class banking_import_transaction(osv.osv):
|
||||
'duplicate': fields.boolean('duplicate'),
|
||||
'statement_line_id': fields.many2one(
|
||||
'account.bank.statement.line', 'Statement line',
|
||||
ondelete='CASCADE'),
|
||||
ondelete='cascade'),
|
||||
'statement_id': fields.many2one(
|
||||
'account.bank.statement', 'Statement'),
|
||||
'parent_id': fields.many2one(
|
||||
@@ -1709,7 +1725,7 @@ class account_bank_statement_line(osv.osv):
|
||||
_columns = {
|
||||
'import_transaction_id': fields.many2one(
|
||||
'banking.import.transaction',
|
||||
'Import transaction', readonly=True, delete='cascade'),
|
||||
'Import transaction', readonly=True, ondelete='cascade'),
|
||||
'match_multi': fields.related(
|
||||
'import_transaction_id', 'match_multi', type='boolean',
|
||||
string='Multi match', readonly=True),
|
||||
@@ -1730,6 +1746,8 @@ class account_bank_statement_line(osv.osv):
|
||||
'state': fields.selection(
|
||||
[('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State',
|
||||
readonly=True, required=True),
|
||||
'parent_id': fields.many2one('account.bank.statement.line',
|
||||
'Parent'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -1872,6 +1890,8 @@ class account_bank_statement_line(osv.osv):
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Don't allow deletion of a confirmed statement line
|
||||
If this statement line comes from a split transaction, give the
|
||||
amount back
|
||||
"""
|
||||
if type(ids) is int:
|
||||
ids = [ids]
|
||||
@@ -1881,6 +1901,12 @@ class account_bank_statement_line(osv.osv):
|
||||
_('Confirmed Statement Line'),
|
||||
_("You cannot delete a confirmed Statement Line"
|
||||
": '%s'" % line.name))
|
||||
if line.parent_id:
|
||||
line.parent_id.write(
|
||||
{
|
||||
'amount': line.parent_id.amount + line.amount,
|
||||
})
|
||||
line.parent_id.refresh()
|
||||
return super(account_bank_statement_line, self).unlink(
|
||||
cr, uid, ids, context=context)
|
||||
|
||||
@@ -1920,6 +1946,46 @@ class account_bank_statement_line(osv.osv):
|
||||
'import_transaction_id': res},
|
||||
context=context)
|
||||
|
||||
def split_off(self, cr, uid, ids, amount, context=None):
|
||||
"""
|
||||
Create a child statement line with amount, deduce that from this line,
|
||||
change transactions accordingly
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
transaction_pool = self.pool.get('banking.import.transaction')
|
||||
|
||||
child_statement_ids = []
|
||||
for this in self.browse(cr, uid, ids, context):
|
||||
transaction_data = transaction_pool.copy_data(
|
||||
cr, uid, this.import_transaction_id.id)
|
||||
transaction_data['transferred_amount'] = amount
|
||||
transaction_data['message'] = (
|
||||
(transaction_data['message'] or '') + _(' (split)'))
|
||||
transaction_data['parent_id'] = this.import_transaction_id.id
|
||||
transaction_id = transaction_pool.create(
|
||||
cr,
|
||||
uid,
|
||||
transaction_data,
|
||||
context=dict(
|
||||
context, transaction_no_duplicate_search=True))
|
||||
|
||||
statement_line_data = self.copy_data(
|
||||
cr, uid, this.id)
|
||||
statement_line_data['amount'] = amount
|
||||
statement_line_data['name'] = (
|
||||
(statement_line_data['name'] or '') + _(' (split)'))
|
||||
statement_line_data['import_transaction_id'] = transaction_id
|
||||
statement_line_data['parent_id'] = this.id
|
||||
|
||||
child_statement_ids.append(
|
||||
self.create(cr, uid, statement_line_data,
|
||||
context=context))
|
||||
this.write({'amount': this.amount - amount})
|
||||
|
||||
return child_statement_ids
|
||||
|
||||
account_bank_statement_line()
|
||||
|
||||
class account_bank_statement(osv.osv):
|
||||
|
||||
@@ -96,6 +96,8 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
# which populates regular fields on the transaction
|
||||
manual_invoice_id = vals.pop('manual_invoice_id', False)
|
||||
manual_move_line_id = vals.pop('manual_move_line_id', False)
|
||||
manual_invoice_ids = vals.pop('manual_invoice_ids', [])
|
||||
manual_move_line_ids = vals.pop('manual_move_line_ids', [])
|
||||
|
||||
# Support for writing fields.related is still flakey:
|
||||
# https://bugs.launchpad.net/openobject-server/+bug/915975
|
||||
@@ -167,55 +169,96 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
_("No entry found for the selected invoice. " +
|
||||
"Try manual reconciliation."))
|
||||
|
||||
if manual_move_line_id or manual_invoice_id:
|
||||
if manual_move_line_id or manual_invoice_id \
|
||||
or manual_move_line_ids or manual_invoice_ids:
|
||||
move_line_obj = self.pool.get('account.move.line')
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
for wiz in self.browse(
|
||||
cr, uid, ids, context=context):
|
||||
move_line_id = False
|
||||
invoice_id = manual_invoice_id
|
||||
if invoice_id:
|
||||
invoice = invoice_obj.browse(
|
||||
cr, uid, manual_invoice_id, context=context)
|
||||
manual_invoice_ids = (
|
||||
([manual_invoice_id] if manual_invoice_id else []) +
|
||||
[i[1] for i in manual_invoice_ids if i[0]==4] +
|
||||
[j for i in manual_invoice_ids if i[0]==6 for j in i[2]])
|
||||
manual_move_line_ids = (
|
||||
([manual_move_line_id] if manual_move_line_id else []) +
|
||||
[i[1] for i in manual_move_line_ids if i[0]==4] +
|
||||
[j for i in manual_move_line_ids if i[0]==6 for j in i[2]])
|
||||
for wiz in self.browse(cr, uid, ids, context=context):
|
||||
#write can be called multiple times for the same values
|
||||
#that doesn't hurt above, but it does here
|
||||
if wiz.match_type and (
|
||||
len(manual_move_line_ids) > 1 or
|
||||
len(manual_invoice_ids) > 1):
|
||||
continue
|
||||
|
||||
todo = []
|
||||
|
||||
for invoice in invoice_obj.browse(
|
||||
cr, uid, manual_invoice_ids, context=context):
|
||||
found_move_line = False
|
||||
if invoice.move_id:
|
||||
for line in invoice.move_id.line_id:
|
||||
if line.account_id.type in ('receivable', 'payable'):
|
||||
move_line_id = line.id
|
||||
todo.append((invoice.id, line.id))
|
||||
found_move_line = True
|
||||
break
|
||||
if not move_line_id:
|
||||
osv.except_osv(
|
||||
if not found_move_line:
|
||||
raise osv.except_osv(
|
||||
_("Cannot select for reconcilion"),
|
||||
_("No entry found for the selected invoice. "))
|
||||
else:
|
||||
move_line_id = manual_move_line_id
|
||||
move_line = move_line_obj.read(
|
||||
cr, uid, move_line_id, ['invoice'], context=context)
|
||||
invoice_id = (move_line['invoice'] and
|
||||
move_line['invoice'][0])
|
||||
vals = {
|
||||
'move_line_id': move_line_id,
|
||||
'move_line_ids': [(6, 0, [move_line_id])],
|
||||
'invoice_id': invoice_id,
|
||||
'invoice_ids': [(6, 0, invoice_id and
|
||||
[invoice_id] or [])],
|
||||
'match_type': 'manual',
|
||||
}
|
||||
transaction_obj.clear_and_write(
|
||||
cr, uid, wiz.import_transaction_id.id,
|
||||
vals, context=context)
|
||||
st_line_vals = {
|
||||
'account_id': move_line_obj.read(
|
||||
cr, uid, move_line_id,
|
||||
['account_id'], context=context)['account_id'][0],
|
||||
}
|
||||
if invoice_id:
|
||||
st_line_vals['partner_id'] = invoice_obj.read(
|
||||
cr, uid, invoice_id,
|
||||
['partner_id'], context=context)['partner_id'][0]
|
||||
statement_line_obj.write(
|
||||
cr, uid, wiz.import_transaction_id.statement_line_id.id,
|
||||
st_line_vals, context=context)
|
||||
for move_line_id in manual_move_line_ids:
|
||||
todo_entry = [False, move_line_id]
|
||||
move_line=move_line_obj.read(
|
||||
cr,
|
||||
uid,
|
||||
move_line_id,
|
||||
['invoice'],
|
||||
context=context)
|
||||
if move_line['invoice']:
|
||||
todo_entry[0] = move_line['invoice'][0]
|
||||
todo.append(todo_entry)
|
||||
|
||||
while todo:
|
||||
todo_entry = todo.pop()
|
||||
move_line = move_line_obj.browse(
|
||||
cr, uid, todo_entry[1], context)
|
||||
transaction_id = wiz.import_transaction_id.id
|
||||
statement_line_id = wiz.statement_line_id.id
|
||||
|
||||
if len(todo) > 0:
|
||||
statement_line_id = wiz.statement_line_id.split_off(
|
||||
move_line.credit or move_line.debit)[0]
|
||||
transaction_id = statement_line_obj.browse(
|
||||
cr,
|
||||
uid,
|
||||
statement_line_id,
|
||||
context=context).import_transaction_id.id
|
||||
|
||||
vals = {
|
||||
'move_line_id': todo_entry[1],
|
||||
'move_line_ids': [(6, 0, [todo_entry[1]])],
|
||||
'invoice_id': todo_entry[0],
|
||||
'invoice_ids': [(6, 0,
|
||||
[todo_entry[0]] if todo_entry[0] else [])],
|
||||
'match_type': 'manual',
|
||||
}
|
||||
|
||||
transaction_obj.clear_and_write(
|
||||
cr, uid, transaction_id, vals, context=context)
|
||||
|
||||
st_line_vals = {
|
||||
'account_id': move_line_obj.read(
|
||||
cr, uid, todo_entry[1],
|
||||
['account_id'], context=context)['account_id'][0],
|
||||
}
|
||||
|
||||
if todo_entry[0]:
|
||||
st_line_vals['partner_id'] = invoice_obj.read(
|
||||
cr, uid, todo_entry[0],
|
||||
['partner_id'], context=context)['partner_id'][0]
|
||||
|
||||
statement_line_obj.write(
|
||||
cr, uid, statement_line_id,
|
||||
st_line_vals, context=context)
|
||||
return res
|
||||
|
||||
def trigger_write(self, cr, uid, ids, context=None):
|
||||
@@ -247,14 +290,21 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
account_id = setting.default_debit_account_id and setting.default_debit_account_id.id
|
||||
statement_pool.write(cr, uid, wiz.statement_line_id.id, {'account_id':account_id})
|
||||
|
||||
self.write(cr, uid, wiz.id, {'partner_id': False}, context=context)
|
||||
wiz.write({'partner_id': False})
|
||||
|
||||
if wiz.statement_line_id:
|
||||
#delete splits causing an unsplit if this is a split
|
||||
#transaction
|
||||
statement_pool.unlink(cr, uid,
|
||||
statement_pool.search(cr, uid,
|
||||
[('parent_id', '=', wiz.statement_line_id.id)],
|
||||
context=context),
|
||||
context=context)
|
||||
|
||||
if wiz.import_transaction_id:
|
||||
wiz.import_transaction_id.clear_and_write()
|
||||
|
||||
|
||||
wizs = self.read(
|
||||
cr, uid, ids, ['import_transaction_id'], context=context)
|
||||
trans_ids = [x['import_transaction_id'][0] for x in wizs
|
||||
if x['import_transaction_id']]
|
||||
self.pool.get('banking.import.transaction').clear_and_write(
|
||||
cr, uid, trans_ids, context=context)
|
||||
return True
|
||||
|
||||
def reverse_duplicate(self, cr, uid, ids, context=None):
|
||||
@@ -281,7 +331,7 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
return res
|
||||
|
||||
def button_done(self, cr, uid, ids, context=None):
|
||||
return {'nodestroy': False, 'type': 'ir.actions.act_window_close'}
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
_defaults = {
|
||||
# 'match_type': _get_default_match_type,
|
||||
@@ -305,6 +355,9 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
'statement_line_id', 'partner_id',
|
||||
type='many2one', relation='res.partner',
|
||||
string="Partner", readonly=True),
|
||||
'statement_line_parent_id': fields.related(
|
||||
'statement_line_id', 'parent_id', type='many2one',
|
||||
relation='account.bank.statement.line', readonly=True),
|
||||
'import_transaction_id': fields.related(
|
||||
'statement_line_id', 'import_transaction_id',
|
||||
string="Import transaction",
|
||||
@@ -356,8 +409,18 @@ class banking_transaction_wizard(osv.osv_memory):
|
||||
'manual_move_line_id': fields.many2one(
|
||||
'account.move.line', 'Or match this entry',
|
||||
domain=[('account_id.reconcile', '=', True),
|
||||
('reconcile_id', '=', False)],
|
||||
),
|
||||
('reconcile_id', '=', False)]),
|
||||
'manual_invoice_ids': fields.many2many(
|
||||
'account.invoice',
|
||||
'banking_transaction_wizard_account_invoice_rel',
|
||||
'wizard_id', 'invoice_id', string='Match following invoices',
|
||||
domain=[('reconciled', '=', False)]),
|
||||
'manual_move_line_ids': fields.many2many(
|
||||
'account.move.line',
|
||||
'banking_transaction_wizard_account_move_line_rel',
|
||||
'wizard_id', 'move_line_id', string='Or match this entries',
|
||||
domain=[('account_id.reconcile', '=', True),
|
||||
('reconcile_id', '=', False)]),
|
||||
'payment_option': fields.related('import_transaction_id','payment_option', string='Payment Difference', type='selection', required=True,
|
||||
selection=[('without_writeoff', 'Keep Open'),('with_writeoff', 'Reconcile Payment Balance')]),
|
||||
'writeoff_analytic_id': fields.related(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<form string="Match transaction">
|
||||
<!-- fields used for form logic -->
|
||||
<field name="payment_order_ids" invisible="True"/>
|
||||
<field name="statement_line_parent_id" invisible="True"/>
|
||||
<field name="invoice_ids" invisible="True"/>
|
||||
<field name="move_line_ids" invisible="True"/>
|
||||
<field name="match_multi" invisible="True"/>
|
||||
@@ -114,6 +115,13 @@
|
||||
type="object"
|
||||
string="Match"/>
|
||||
</page>
|
||||
<page string="Multiple manual matches" attrs="{'invisible': ['|', ('match_type', '!=', False), ('statement_line_parent_id', '!=', False)]}">
|
||||
<field name="manual_invoice_ids" colspan="4"/>
|
||||
<field name="manual_move_line_ids" colspan="4"/>
|
||||
<button name="trigger_write"
|
||||
type="object"
|
||||
string="Match" />
|
||||
</page>
|
||||
<page string="Write-Off" attrs="{'invisible': [('match_type', '=', False)]}">
|
||||
<group colspan="2" col="2">
|
||||
<label string="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." colspan="2"/>
|
||||
|
||||
Reference in New Issue
Block a user