mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
166 lines
5.7 KiB
Python
166 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
##############################################################################
|
|
#
|
|
# Copyright (C) 2011 - 2013 Therp BV (<http://therp.nl>).
|
|
#
|
|
# All other contributions are (C) by their respective contributors
|
|
#
|
|
# All Rights Reserved
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
##############################################################################
|
|
"""
|
|
This module adds support for Direct debit orders as applicable
|
|
in the Netherlands. Debit orders are advanced in total by the bank.
|
|
Amounts that cannot be debited or are canceled by account owners are
|
|
credited afterwards. Such a creditation is called a storno.
|
|
|
|
Invoice workflow:
|
|
|
|
1 the sale leads to
|
|
1300 Debtors 100
|
|
8000 Sales 100
|
|
|
|
Balance:
|
|
Debtors 2000 |
|
|
Sales | 2000
|
|
|
|
2 an external booking takes place
|
|
1100 Bank 100
|
|
1300 Debtors 100
|
|
This booking is reconciled with [1]
|
|
The invoice gets set to state 'paid', and 'reconciled' = True
|
|
|
|
Balance:
|
|
Debtors 1900 |
|
|
Bank 100 |
|
|
Sales | 2000
|
|
|
|
This module implements the following diversion:
|
|
|
|
2a the invoice is included in a direct debit order. When the order is
|
|
confirmed, a move is created per invoice:
|
|
|
|
2000 Transfer account 100 |
|
|
1300 Debtors | 100
|
|
Reconciliation takes place between 1 and 2a.
|
|
The invoice gets set to state 'paid', and 'reconciled' = True
|
|
|
|
Balance:
|
|
Debtors 0 |
|
|
Transfer account 2000 |
|
|
Bank 0 |
|
|
Sales | 2000
|
|
|
|
3a the direct debit order is booked on the bank account
|
|
|
|
Balance:
|
|
1100 Bank 2000 |
|
|
2000 Transfer account | 2000
|
|
Reconciliation takes place between 3a and 2a
|
|
|
|
Balance:
|
|
Debtors 0 |
|
|
Transfer account 0 |
|
|
Bank 2000 |
|
|
Sales | 2000
|
|
|
|
4 a storno from invoice [1] triggers a new booking on the bank account
|
|
1300 Debtors 100 |
|
|
1100 Bank | 100
|
|
|
|
Balance:
|
|
Debtors 100 |
|
|
Transfer account 0 |
|
|
Bank 1900 |
|
|
Sales | 2000
|
|
|
|
The reconciliation of 2a is undone. The booking of 2a is reconciled
|
|
with the booking of 4 instead.
|
|
The payment line attribute 'storno' is set to True and the invoice
|
|
state is no longer 'paid'.
|
|
|
|
Two cases need to be distinguisted:
|
|
1) If the storno is a manual storno from the partner, the invoice is set to
|
|
state 'debit_denied', with 'reconciled' = False
|
|
This module implements this option by allowing the bank module to call
|
|
|
|
netsvc.LocalService("workflow").trg_validate(
|
|
uid, 'account.invoice', ids, 'debit_denied', cr)
|
|
|
|
2) If the storno is an error generated by the bank (assumingly non-fatal),
|
|
the invoice is reopened for the next debit run.
|
|
This is a call to existing
|
|
|
|
netsvc.LocalService("workflow").trg_validate(
|
|
uid, 'account.invoice', ids, 'open_test', cr)
|
|
|
|
Should also be adding a log entry on the invoice for tracing purposes
|
|
|
|
self._log_event(cr, uid, ids, -1.0, 'Debit denied')
|
|
|
|
If not for that funny comment
|
|
"#TODO: implement messages system" in account/invoice.py
|
|
|
|
Repeating non-fatal fatal errors need to be dealt with manually by checking
|
|
open invoices with a matured invoice- or due date.
|
|
"""
|
|
|
|
from openerp.osv import orm
|
|
from openerp.tools.translate import _
|
|
|
|
|
|
class account_invoice(orm.Model):
|
|
_inherit = "account.invoice"
|
|
|
|
def __init__(self, pool, cr):
|
|
"""
|
|
Adding a state to the hardcoded state list of the inherited
|
|
model. The alternative is duplicating the field definition
|
|
in columns but only one module can do that!
|
|
|
|
Maybe apply a similar trick when overriding the buttons' 'states'
|
|
attributes in the form view, manipulating the xml in fields_view_get().
|
|
"""
|
|
super(account_invoice, self).__init__(pool, cr)
|
|
invoice_obj = pool.get('account.invoice')
|
|
invoice_obj._columns['state'].selection.append(
|
|
('debit_denied', 'Debit denied'))
|
|
|
|
def action_debit_denied(self, cr, uid, ids, context=None):
|
|
for invoice_id in ids:
|
|
if self.test_paid(cr, uid, [invoice_id], context):
|
|
number = self.read(
|
|
cr, uid, invoice_id, ['number'], context=context)['number']
|
|
raise orm.except_orm(
|
|
_('Error !'),
|
|
_("You cannot set invoice '%s' to state 'debit denied', "
|
|
'as it is still reconciled.') % number)
|
|
self.write(cr, uid, ids, {'state': 'debit_denied'}, context=context)
|
|
for inv_id, name in self.name_get(cr, uid, ids, context=context):
|
|
message = _("Invoice '%s': direct debit is denied.") % name
|
|
self.log(cr, uid, inv_id, message)
|
|
return True
|
|
|
|
def test_undo_debit_denied(self, cr, uid, ids, context=None):
|
|
"""
|
|
Called from the workflow. Used to unset paid state on
|
|
invoices that were paid with bank transfers which are being cancelled
|
|
"""
|
|
for invoice in self.read(cr, uid, ids, ['reconciled'], context):
|
|
if not invoice['reconciled']:
|
|
return False
|
|
return True
|