mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Start to port bank-payment to v9 (with a lot of improvements) during the Sorrento Code sprint 2016
Improvements include: - full re-organisation of modules and big re-organisation of the code - simplification of the code related to the fact that support for direct debit is now in t he base module, not added by an optional module account_direct_debit (module was removed) - new design of the wizard to select move lines to pay - support for non-SEPA file transfer- - support for German direct debit SEPA files (fixes bug #129) - remove workflow of payment.order This port to v9 is not finished... there is still a lot of work: - finish the code of account_payment_order/wizard/account_payment_line_create.py - port account_banking_payment_transfer and integrate it inside account_payment_order - fix bugs - clean-up code, remove dead code - test in several complex scenarios
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
'name': 'Account Banking Mandate',
|
||||
'summary': 'Banking mandates',
|
||||
'version': '8.0.0.2.0',
|
||||
'version': '9.0.0.2.0',
|
||||
'license': 'AGPL-3',
|
||||
'author': "Compassion CH, "
|
||||
"Serv. Tecnol. Avanzados - Pedro M. Baeza, "
|
||||
@@ -16,19 +16,20 @@
|
||||
'website': 'https://github.com/OCA/bank-payment',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_banking_payment_export',
|
||||
'account_payment_order',
|
||||
],
|
||||
'data': [
|
||||
'views/account_banking_mandate_view.xml',
|
||||
'views/account_invoice_view.xml',
|
||||
'views/account_payment_view.xml',
|
||||
'views/account_payment_line.xml',
|
||||
'views/res_partner_bank_view.xml',
|
||||
'views/bank_payment_line_view.xml',
|
||||
'views/account_move_line.xml',
|
||||
'data/mandate_reference_sequence.xml',
|
||||
'security/mandate_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [],
|
||||
'test': ['test/banking_mandate.yml'],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
<record id="dd_mandate_seq_type" model="ir.sequence.type">
|
||||
<field name="name">DD Mandate Reference</field>
|
||||
<field name="code">account.banking.mandate</field>
|
||||
</record>
|
||||
|
||||
<record id="dd_mandate_seq" model="ir.sequence">
|
||||
<field name="name">DD Mandate Reference</field>
|
||||
<field name="code">account.banking.mandate</field>
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
from . import account_banking_mandate
|
||||
from . import account_invoice
|
||||
from . import res_partner_bank
|
||||
from . import payment_line
|
||||
from . import account_payment_line
|
||||
from . import bank_payment_line
|
||||
from . import account_move_line
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, exceptions, api, _
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class AccountBankingMandate(models.Model):
|
||||
@@ -17,30 +18,10 @@ class AccountBankingMandate(models.Model):
|
||||
_rec_name = 'unique_mandate_reference'
|
||||
_inherit = ['mail.thread']
|
||||
_order = 'signature_date desc'
|
||||
_track = {
|
||||
'state': {
|
||||
'account_banking_mandate.mandate_valid': (
|
||||
lambda self, cr, uid, obj, ctx=None: obj['state'] == 'valid'),
|
||||
'account_banking_mandate.mandate_expired': (
|
||||
lambda self, cr, uid, obj, ctx=None:
|
||||
obj['state'] == 'expired'),
|
||||
'account_banking_mandate.mandate_cancel': (
|
||||
lambda self, cr, uid, obj, ctx=None: obj['state'] == 'cancel'),
|
||||
},
|
||||
}
|
||||
|
||||
def _get_states(self):
|
||||
return [('draft', 'Draft'),
|
||||
('valid', 'Valid'),
|
||||
('expired', 'Expired'),
|
||||
('cancel', 'Cancelled')]
|
||||
|
||||
format = fields.Selection(
|
||||
[('basic', _('Basic Mandate'))],
|
||||
default='basic',
|
||||
required=True,
|
||||
string='Mandate Format',
|
||||
)
|
||||
[('basic', 'Basic Mandate')], default='basic', required=True,
|
||||
string='Mandate Format', track_visibility='onchange')
|
||||
partner_bank_id = fields.Many2one(
|
||||
comodel_name='res.partner.bank', string='Bank Account',
|
||||
track_visibility='onchange')
|
||||
@@ -52,19 +33,22 @@ class AccountBankingMandate(models.Model):
|
||||
default=lambda self: self.env['res.company']._company_default_get(
|
||||
'account.banking.mandate'))
|
||||
unique_mandate_reference = fields.Char(
|
||||
string='Unique Mandate Reference', track_visibility='always',
|
||||
default='/')
|
||||
string='Unique Mandate Reference', track_visibility='onchange')
|
||||
signature_date = fields.Date(string='Date of Signature of the Mandate',
|
||||
track_visibility='onchange')
|
||||
scan = fields.Binary(string='Scan of the Mandate')
|
||||
last_debit_date = fields.Date(string='Date of the Last Debit',
|
||||
readonly=True)
|
||||
state = fields.Selection(
|
||||
_get_states, string='Status', default='draft',
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('valid', 'Valid'),
|
||||
('expired', 'Expired'),
|
||||
('cancel', 'Cancelled'),
|
||||
], string='Status', default='draft', track_visibility='onchange',
|
||||
help="Only valid mandates can be used in a payment line. A cancelled "
|
||||
"mandate is a mandate that has been cancelled by the customer.")
|
||||
"mandate is a mandate that has been cancelled by the customer.")
|
||||
payment_line_ids = fields.One2many(
|
||||
comodel_name='payment.line', inverse_name='mandate_id',
|
||||
comodel_name='account.payment.line', inverse_name='mandate_id',
|
||||
string="Related Payment Lines")
|
||||
|
||||
_sql_constraints = [(
|
||||
@@ -79,13 +63,13 @@ class AccountBankingMandate(models.Model):
|
||||
if (mandate.signature_date and
|
||||
mandate.signature_date > fields.Date.context_today(
|
||||
mandate)):
|
||||
raise exceptions.Warning(
|
||||
raise ValidationError(
|
||||
_("The date of signature of mandate '%s' "
|
||||
"is in the future !")
|
||||
% mandate.unique_mandate_reference)
|
||||
if (mandate.signature_date and mandate.last_debit_date and
|
||||
mandate.signature_date > mandate.last_debit_date):
|
||||
raise exceptions.Warning(
|
||||
raise ValidationError(
|
||||
_("The mandate '%s' can't have a date of last debit "
|
||||
"before the date of signature."
|
||||
) % mandate.unique_mandate_reference)
|
||||
@@ -96,20 +80,21 @@ class AccountBankingMandate(models.Model):
|
||||
for mandate in self:
|
||||
if mandate.state == 'valid':
|
||||
if not mandate.signature_date:
|
||||
raise exceptions.Warning(
|
||||
raise ValidationError(
|
||||
_("Cannot validate the mandate '%s' without a date of "
|
||||
"signature.") % mandate.unique_mandate_reference)
|
||||
if not mandate.partner_bank_id:
|
||||
raise exceptions.Warning(
|
||||
raise ValidationError(
|
||||
_("Cannot validate the mandate '%s' because it is not "
|
||||
"attached to a bank account.") %
|
||||
mandate.unique_mandate_reference)
|
||||
|
||||
@api.model
|
||||
def create(self, vals=None):
|
||||
if vals.get('unique_mandate_reference', '/') == '/':
|
||||
if vals.get('unique_mandate_reference', 'New') == 'New':
|
||||
vals['unique_mandate_reference'] = \
|
||||
self.env['ir.sequence'].next_by_code('account.banking.mandate')
|
||||
self.env['ir.sequence'].next_by_code('account.banking.mandate')\
|
||||
or 'New'
|
||||
return super(AccountBankingMandate, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
@@ -122,7 +107,7 @@ class AccountBankingMandate(models.Model):
|
||||
def validate(self):
|
||||
for mandate in self:
|
||||
if mandate.state != 'draft':
|
||||
raise exceptions.Warning(
|
||||
raise UserError(
|
||||
_('Mandate should be in draft state'))
|
||||
self.write({'state': 'valid'})
|
||||
return True
|
||||
@@ -131,7 +116,7 @@ class AccountBankingMandate(models.Model):
|
||||
def cancel(self):
|
||||
for mandate in self:
|
||||
if mandate.state not in ('draft', 'valid'):
|
||||
raise exceptions.Warning(
|
||||
raise UserError(
|
||||
_('Mandate should be in draft or valid state'))
|
||||
self.write({'state': 'cancel'})
|
||||
return True
|
||||
@@ -143,7 +128,7 @@ class AccountBankingMandate(models.Model):
|
||||
"""
|
||||
for mandate in self:
|
||||
if mandate.state != 'cancel':
|
||||
raise exceptions.Warning(
|
||||
raise UserError(
|
||||
_('Mandate should be in cancel state'))
|
||||
self.write({'state': 'draft'})
|
||||
return True
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
from openerp import models, fields
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
@@ -12,5 +13,15 @@ class AccountInvoice(models.Model):
|
||||
|
||||
mandate_id = fields.Many2one(
|
||||
'account.banking.mandate', string='Direct Debit Mandate',
|
||||
domain=[('state', '=', 'valid')], readonly=True,
|
||||
states={'draft': [('readonly', False)]})
|
||||
ondelete='restrict',
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
|
||||
@api.model
|
||||
def line_get_convert(self, line, part):
|
||||
"""Copy mandate from invoice to account move line"""
|
||||
res = super(AccountInvoice, self).line_get_convert(line, part)
|
||||
if line.get('type') == 'dest' and line.get('invoice_id'):
|
||||
invoice = self.browse(line['invoice_id'])
|
||||
if invoice.type in ('out_invoice', 'out_refund'):
|
||||
res['mandate_id'] = invoice.mandate_id.id or False
|
||||
return res
|
||||
|
||||
23
account_banking_mandate/models/account_move_line.py
Normal file
23
account_banking_mandate/models/account_move_line.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Akretion (http://www.akretion.com/)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
mandate_id = fields.Many2one(
|
||||
'account.banking.mandate', string='Direct Debit Mandate',
|
||||
ondelete='restrict')
|
||||
|
||||
@api.multi
|
||||
def _prepare_payment_line_vals(self, payment_order):
|
||||
vals = super(AccountMoveLine, self)._prepare_payment_line_vals(
|
||||
payment_order)
|
||||
# TODO : test on the view field "mandate required ?"
|
||||
if payment_order.payment_type == 'inbound' and self.mandate_id:
|
||||
vals['mandate_id'] = self.mandate_id.id or False
|
||||
vals['partner_bank_id'] = self.mandate_id.partner_bank_id.id or False
|
||||
return vals
|
||||
@@ -1,19 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, exceptions, _
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import ValidationError
|
||||
|
||||
|
||||
class PaymentLine(models.Model):
|
||||
_inherit = 'payment.line'
|
||||
class AccountPaymentLine(models.Model):
|
||||
_inherit = 'account.payment.line'
|
||||
|
||||
mandate_id = fields.Many2one(
|
||||
comodel_name='account.banking.mandate', string='Direct Debit Mandate',
|
||||
domain=[('state', '=', 'valid')])
|
||||
|
||||
# TODO : remove this
|
||||
@api.model
|
||||
def create(self, vals=None):
|
||||
"""If the customer invoice has a mandate, take it
|
||||
@@ -21,7 +23,7 @@ class PaymentLine(models.Model):
|
||||
"""
|
||||
if vals is None:
|
||||
vals = {}
|
||||
partner_bank_id = vals.get('bank_id')
|
||||
partner_bank_id = vals.get('partner_bank_id')
|
||||
move_line_id = vals.get('move_line_id')
|
||||
if (self.env.context.get('search_payment_order_type') == 'debit' and
|
||||
'mandate_id' not in vals):
|
||||
@@ -31,7 +33,7 @@ class PaymentLine(models.Model):
|
||||
line.invoice.mandate_id):
|
||||
vals.update({
|
||||
'mandate_id': line.invoice.mandate_id.id,
|
||||
'bank_id': line.invoice.mandate_id.partner_bank_id.id,
|
||||
'partner_bank_id': line.invoice.mandate_id.partner_bank_id.id,
|
||||
})
|
||||
if partner_bank_id and 'mandate_id' not in vals:
|
||||
mandates = self.env['account.banking.mandate'].search(
|
||||
@@ -39,21 +41,23 @@ class PaymentLine(models.Model):
|
||||
('state', '=', 'valid')])
|
||||
if mandates:
|
||||
vals['mandate_id'] = mandates[0].id
|
||||
return super(PaymentLine, self).create(vals)
|
||||
return super(AccountPaymentLine, self).create(vals)
|
||||
|
||||
@api.one
|
||||
@api.constrains('mandate_id', 'bank_id')
|
||||
@api.constrains('mandate_id', 'partner_bank_id')
|
||||
def _check_mandate_bank_link(self):
|
||||
if (self.mandate_id and self.bank_id and
|
||||
if (self.mandate_id and self.partner_bank_id and
|
||||
self.mandate_id.partner_bank_id.id !=
|
||||
self.bank_id.id):
|
||||
raise exceptions.Warning(
|
||||
self.partner_bank_id.id):
|
||||
raise ValidationError(
|
||||
_("The payment line with reference '%s' has the bank account "
|
||||
"'%s' which is not attached to the mandate '%s' (this "
|
||||
"mandate is attached to the bank account '%s').") %
|
||||
(self.name,
|
||||
self.env['res.partner.bank'].name_get(
|
||||
[self.bank_id.id])[0][1],
|
||||
self.partner_bank_id.name_get()[0][1],
|
||||
self.mandate_id.unique_mandate_reference,
|
||||
self.env['res.partner.bank'].name_get(
|
||||
[self.mandate_id.partner_bank_id.id])[0][1]))
|
||||
self.mandate_id.partner_bank_id.name_get()[0][1]))
|
||||
|
||||
# @api.multi
|
||||
# def check_payment_line(self):
|
||||
# TODO : i would like to block here is mandate is missing... but how do you know it's required ? => create option on payment order ?
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_account_banking_mandate","Full access on account.banking.mandate","model_account_banking_mandate","account_payment.group_account_payment",1,1,1,1
|
||||
"access_account_banking_mandate_read","Read access on account.banking.mandate","model_account_banking_mandate","base.group_user",1,0,0,0
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_account_banking_mandate,Full access on account.banking.mandate,model_account_banking_mandate,account_payment_order.group_account_payment,1,1,1,1
|
||||
access_account_banking_mandate_read,Read access on account.banking.mandate,model_account_banking_mandate,base.group_user,1,0,0,0
|
||||
|
||||
|
@@ -101,33 +101,11 @@
|
||||
</record>
|
||||
|
||||
<menuitem id="mandate_menu"
|
||||
parent="account_payment.menu_main_payment"
|
||||
parent="account_payment_order.payment_root"
|
||||
action="mandate_action"
|
||||
sequence="20"
|
||||
sequence="30"
|
||||
/>
|
||||
|
||||
<!-- notifications in the chatter -->
|
||||
<record id="mandate_valid" model="mail.message.subtype">
|
||||
<field name="name">Mandate Validated</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Banking Mandate Validated</field>
|
||||
</record>
|
||||
|
||||
<record id="mandate_expired" model="mail.message.subtype">
|
||||
<field name="name">Mandate Expired</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Banking Mandate has Expired</field>
|
||||
</record>
|
||||
|
||||
<record id="mandate_cancel" model="mail.message.subtype">
|
||||
<field name="name">Mandate Cancelled</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Banking Mandate Cancelled</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
@@ -10,10 +10,10 @@
|
||||
<record id="invoice_form" model="ir.ui.view">
|
||||
<field name="name">add.mandate.on.customer.invoice.form</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account.invoice_form"/>
|
||||
<field name="inherit_id" ref="account_payment_partner.invoice_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id" domain="[('partner_id', '=', partner_id), ('state', '=', 'valid')]" attrs="{'invisible': [('type', '=', 'out_refund')]}"/>
|
||||
<field name="mandate_id" domain="[('partner_id', '=', commercial_partner_id), ('state', '=', 'valid')]" attrs="{'invisible': [('type', '=', 'out_refund')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
26
account_banking_mandate/views/account_move_line.xml
Normal file
26
account_banking_mandate/views/account_move_line.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2016 Akretion (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="view_move_line_form" model="ir.ui.view">
|
||||
<field name="name">account_banking_mandate.move_line_form</field>
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="inherit_id" ref="account_payment_order.view_move_line_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id"
|
||||
domain="[('partner_id', '=', partner_id), ('state', '=', 'valid')]"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
37
account_banking_mandate/views/account_payment_line.xml
Normal file
37
account_banking_mandate/views/account_payment_line.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="account_payment_line_form" model="ir.ui.view">
|
||||
<field name="name">account_banking_mandate.account.payment.line.form</field>
|
||||
<field name="model">account.payment.line</field>
|
||||
<field name="inherit_id" ref="account_payment_order.account_payment_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id"
|
||||
domain="[('partner_bank_id', '=', partner_bank_id), ('state', '=', 'valid')]"
|
||||
invisible="context.get('default_payment_type') != 'inbound'"
|
||||
context="{'default_partner_bank_id': partner_bank_id}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment_line_tree" model="ir.ui.view">
|
||||
<field name="name">account_banking_mandate.account.payment.line.tree</field>
|
||||
<field name="model">account.payment.line</field>
|
||||
<field name="inherit_id" ref="account_payment_order.account_payment_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id"
|
||||
invisible="context.get('default_payment_type') != 'inbound'"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_mandate_payment_order_form" model="ir.ui.view">
|
||||
<field name="name">mandate.payment.order.form</field>
|
||||
<field name="model">payment.order</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.view_payment_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='bank_id']" position="after">
|
||||
<field name="mandate_id"
|
||||
domain="[('partner_bank_id', '=', bank_id), ('state', '=', 'valid')]"
|
||||
invisible="context.get('search_payment_order_type')!='debit'"
|
||||
context="{'default_partner_bank_id': bank_id}"/>
|
||||
<newline />
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='bank_id']" position="after">
|
||||
<field name="mandate_id" string="Mandate"
|
||||
invisible="context.get('search_payment_order_type')!='debit'"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2015-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
@@ -10,11 +10,11 @@
|
||||
<record id="bank_payment_line_form" model="ir.ui.view">
|
||||
<field name="name">banking.mandate.bank.payment.line.form</field>
|
||||
<field name="model">bank.payment.line</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.bank_payment_line_form"/>
|
||||
<field name="inherit_id" ref="account_payment_order.bank_payment_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bank_id" position="after">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id"
|
||||
invisible="context.get('search_payment_order_type')!='debit'"/>
|
||||
invisible="context.get('default_payment_type')!='inbound'"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -22,11 +22,11 @@
|
||||
<record id="bank_payment_line_tree" model="ir.ui.view">
|
||||
<field name="name">banking.mandate.bank.payment.line.tree</field>
|
||||
<field name="model">bank.payment.line</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.bank_payment_line_tree"/>
|
||||
<field name="inherit_id" ref="account_payment_order.bank_payment_line_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bank_id" position="after">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="mandate_id" string="Mandate"
|
||||
invisible="context.get('search_payment_order_type')!='debit'"/>
|
||||
invisible="context.get('default_payment_type')!='inbound'"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
@@ -12,8 +12,8 @@
|
||||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="base.view_partner_bank_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="bank" position="after">
|
||||
<group name="mandates" string="Direct Debit Mandates" colspan="4">
|
||||
<group col="4" position="after">
|
||||
<group name="mandates" string="Direct Debit Mandates">
|
||||
<field name="mandate_ids" context="{'default_partner_bank_id': active_id, 'mandate_bank_partner_view': True}" nolabel="1"/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -26,23 +26,10 @@
|
||||
<field name="inherit_id" ref="base.view_partner_bank_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="partner_id" position="after">
|
||||
<field name="mandate_ids" string="DD Mandates"/>
|
||||
<field name="mandate_ids" string="Mandates"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- add number of mandates in this list of bank accounts
|
||||
on the partner form -->
|
||||
<record id="mandate_partner_form" model="ir.ui.view">
|
||||
<field name="name">mandate.partner.form</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="account.view_partner_property_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='bank_ids']/tree/field[@name='owner_name']" position="after">
|
||||
<field name="mandate_ids" string="DD Mandates"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
'name': 'Account Banking PAIN Base Module',
|
||||
'summary': 'Base module for PAIN file generation',
|
||||
'version': '8.0.0.4.0',
|
||||
'version': '9.0.1.0.0',
|
||||
'license': 'AGPL-3',
|
||||
'author': "Akretion, "
|
||||
"Noviat, "
|
||||
@@ -17,16 +17,18 @@
|
||||
'website': 'https://github.com/OCA/bank-payment',
|
||||
'contributors': ['Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>'],
|
||||
'category': 'Hidden',
|
||||
'depends': ['account_banking_payment_export'],
|
||||
'depends': ['account_payment_order'],
|
||||
'external_dependencies': {
|
||||
'python': ['unidecode', 'lxml'],
|
||||
},
|
||||
'data': [
|
||||
'views/payment_line_view.xml',
|
||||
'views/account_payment_line.xml',
|
||||
'views/account_payment_order.xml',
|
||||
'views/bank_payment_line_view.xml',
|
||||
'views/payment_mode_view.xml',
|
||||
'views/account_payment_mode.xml',
|
||||
'views/res_company_view.xml',
|
||||
'views/account_payment_method.xml',
|
||||
],
|
||||
'post_init_hook': 'set_default_initiating_party',
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import payment_line
|
||||
from . import account_payment_line
|
||||
from . import account_payment_order
|
||||
from . import bank_payment_line
|
||||
from . import payment_mode
|
||||
from . import account_payment_mode
|
||||
from . import res_company
|
||||
from . import banking_export_pain
|
||||
from . import res_partner_bank
|
||||
from . import account_payment_method
|
||||
|
||||
23
account_banking_pain_base/models/account_payment_line.py
Normal file
23
account_banking_pain_base/models/account_payment_line.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields
|
||||
|
||||
|
||||
class AccountPaymentLine(models.Model):
|
||||
_inherit = 'account.payment.line'
|
||||
|
||||
priority = fields.Selection([
|
||||
('NORM', 'Normal'),
|
||||
('HIGH', 'High')],
|
||||
string='Priority', default='NORM',
|
||||
help="This field will be used as the 'Instruction Priority' in "
|
||||
"the generated PAIN file.")
|
||||
# PAIN allows 140 caracters
|
||||
communication = fields.Char(size=140)
|
||||
# The field struct_communication_type has been dropped in v9
|
||||
# We now use communication_type ; you should add an option
|
||||
# in communication_type with selection_add=[]
|
||||
communication_type = fields.Selection(selection_add=[('ISO', 'ISO')])
|
||||
19
account_banking_pain_base/models/account_payment_method.py
Normal file
19
account_banking_pain_base/models/account_payment_method.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class AccountPaymentMethod(models.Model):
|
||||
_inherit = 'account.payment.method'
|
||||
|
||||
pain_version = fields.Selection([], string='PAIN Version')
|
||||
|
||||
@api.multi
|
||||
def get_xsd_file_path(self):
|
||||
"""This method is designed to be inherited in the SEPA modules"""
|
||||
self.ensure_one()
|
||||
raise UserError(_(
|
||||
"No XSD file path found for payment method '%s'") % self.name)
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
@@ -7,8 +7,8 @@
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class PaymentMode(models.Model):
|
||||
_inherit = 'payment.mode'
|
||||
class AccountPaymentMode(models.Model):
|
||||
_inherit = 'account.payment.mode'
|
||||
|
||||
convert_to_ascii = fields.Boolean(
|
||||
string='Convert to ASCII', default=True,
|
||||
@@ -33,17 +33,18 @@ class PaymentMode(models.Model):
|
||||
"- Country code (2, optional)\n"
|
||||
"- Company idenfier (N, VAT)\n"
|
||||
"- Service suffix (N, issued by bank)")
|
||||
sepa_type = fields.Char(compute="_compute_sepa_type")
|
||||
# I plan to change this -- Alexis
|
||||
#sepa_type = fields.Char(compute="_compute_sepa_type")
|
||||
|
||||
def _sepa_type_get(self):
|
||||
"""Defined to be inherited by child addons, for instance:
|
||||
- account_banking_sepa_credit_transfer
|
||||
- account_banking_sepa_direct_debit
|
||||
"""
|
||||
return False
|
||||
#def _sepa_type_get(self):
|
||||
# """Defined to be inherited by child addons, for instance:
|
||||
# - account_banking_sepa_credit_transfer
|
||||
# - account_banking_sepa_direct_debit
|
||||
# """
|
||||
# return False
|
||||
|
||||
@api.multi
|
||||
@api.depends('type')
|
||||
def _compute_sepa_type(self):
|
||||
for mode in self:
|
||||
mode.sepa_type = mode._sepa_type_get()
|
||||
#@api.multi
|
||||
#@api.depends('type')
|
||||
#def _compute_sepa_type(self):
|
||||
# for mode in self:
|
||||
# mode.sepa_type = mode._sepa_type_get()
|
||||
55
account_banking_pain_base/models/account_payment_order.py
Normal file
55
account_banking_pain_base/models/account_payment_order.py
Normal file
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountPaymentOrder(models.Model):
|
||||
_inherit = 'account.payment.order'
|
||||
|
||||
sepa = fields.Boolean(
|
||||
compute='compute_sepa', readonly=True,
|
||||
string="SEPA Payment")
|
||||
charge_bearer = fields.Selection([
|
||||
('SLEV', 'Following Service Level'),
|
||||
('SHAR', 'Shared'),
|
||||
('CRED', 'Borne by Creditor'),
|
||||
('DEBT', 'Borne by Debtor')], string='Charge Bearer',
|
||||
default='SLEV',
|
||||
help="Following service level : transaction charges are to be "
|
||||
"applied following the rules agreed in the service level "
|
||||
"and/or scheme (SEPA Core messages must use this). Shared : "
|
||||
"transaction charges on the debtor side are to be borne by "
|
||||
"the debtor, transaction charges on the creditor side are to "
|
||||
"be borne by the creditor. Borne by creditor : all "
|
||||
"transaction charges are to be borne by the creditor. Borne "
|
||||
"by debtor : all transaction charges are to be borne by the "
|
||||
"debtor.")
|
||||
batch_booking = fields.Boolean(
|
||||
string='Batch Booking',
|
||||
help="If true, the bank statement will display only one debit "
|
||||
"line for all the wire transfers of the SEPA XML file ; if "
|
||||
"false, the bank statement will display one debit line per wire "
|
||||
"transfer of the SEPA XML file.")
|
||||
|
||||
@api.multi
|
||||
@api.depends(
|
||||
'company_partner_bank_id.acc_type',
|
||||
'payment_line_ids.currency_id',
|
||||
'payment_line_ids.partner_bank_id.acc_type')
|
||||
def compute_sepa(self):
|
||||
eur = self.env.ref('base.EUR')
|
||||
for order in self:
|
||||
sepa = True
|
||||
if order.company_partner_bank_id.acc_type != 'iban':
|
||||
sepa = False
|
||||
for pline in order.payment_line_ids:
|
||||
if pline.currency_id != eur:
|
||||
sepa = False
|
||||
break
|
||||
if pline.partner_bank_id.acc_type != 'iban':
|
||||
sepa = False
|
||||
break
|
||||
self.sepa = sepa
|
||||
@@ -10,13 +10,10 @@ class BankPaymentLine(models.Model):
|
||||
|
||||
priority = fields.Selection(
|
||||
related='payment_line_ids.priority', string='Priority')
|
||||
struct_communication_type = fields.Selection(
|
||||
related='payment_line_ids.struct_communication_type',
|
||||
string='Structured Communication Type')
|
||||
|
||||
@api.model
|
||||
def same_fields_payment_line_and_bank_payment_line(self):
|
||||
res = super(BankPaymentLine, self).\
|
||||
same_fields_payment_line_and_bank_payment_line()
|
||||
res += ['priority', 'struct_communication_type']
|
||||
res += ['priority']
|
||||
return res
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, api, _
|
||||
from openerp.exceptions import Warning
|
||||
from openerp.exceptions import UserError
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
from datetime import datetime
|
||||
from lxml import etree
|
||||
from openerp import tools
|
||||
import logging
|
||||
import base64
|
||||
|
||||
|
||||
try:
|
||||
@@ -22,17 +21,8 @@ except ImportError:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BankingExportPain(models.AbstractModel):
|
||||
_name = 'banking.export.pain'
|
||||
|
||||
@api.model
|
||||
def _validate_iban(self, iban):
|
||||
"""if IBAN is valid, returns IBAN
|
||||
if IBAN is NOT valid, raises an error message"""
|
||||
if self.env['res.partner.bank'].is_iban_valid(iban):
|
||||
return iban.replace(' ', '')
|
||||
else:
|
||||
raise Warning(_("This IBAN is not valid : %s") % iban)
|
||||
class AccountPaymentOrder(models.Model):
|
||||
_inherit = 'account.payment.order'
|
||||
|
||||
@api.model
|
||||
def _prepare_field(self, field_name, field_value, eval_ctx,
|
||||
@@ -58,20 +48,20 @@ class BankingExportPain(models.AbstractModel):
|
||||
except:
|
||||
line = eval_ctx.get('line')
|
||||
if line:
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("Cannot compute the '%s' of the Payment Line with "
|
||||
"reference '%s'.")
|
||||
% (field_name, line.name))
|
||||
else:
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("Cannot compute the '%s'.") % field_name)
|
||||
if not isinstance(value, (str, unicode)):
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("The type of the field '%s' is %s. It should be a string "
|
||||
"or unicode.")
|
||||
% (field_name, type(value)))
|
||||
if not value:
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("The '%s' is empty or 0. It should have a non-null value.")
|
||||
% field_name)
|
||||
if max_size and len(value) > max_size:
|
||||
@@ -92,7 +82,7 @@ class BankingExportPain(models.AbstractModel):
|
||||
"The XML file is invalid against the XML Schema Definition")
|
||||
logger.warning(xml_string)
|
||||
logger.warning(e)
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("The generated XML file is not valid against the official "
|
||||
"XML Schema Definition. The generated XML file and the "
|
||||
"full error have been written in the server logs. Here "
|
||||
@@ -102,8 +92,7 @@ class BankingExportPain(models.AbstractModel):
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def finalize_sepa_file_creation(
|
||||
self, xml_root, total_amount, transactions_count, gen_args):
|
||||
def finalize_sepa_file_creation(self, xml_root, gen_args):
|
||||
xml_string = etree.tostring(
|
||||
xml_root, pretty_print=True, encoding='UTF-8',
|
||||
xml_declaration=True)
|
||||
@@ -113,30 +102,8 @@ class BankingExportPain(models.AbstractModel):
|
||||
logger.debug(xml_string)
|
||||
self._validate_xml(xml_string, gen_args)
|
||||
|
||||
order_ref = []
|
||||
for order in self.payment_order_ids:
|
||||
if order.reference:
|
||||
order_ref.append(order.reference.replace('/', '-'))
|
||||
filename = '%s%s.xml' % (gen_args['file_prefix'], '-'.join(order_ref))
|
||||
|
||||
self.write({
|
||||
'nb_transactions': transactions_count,
|
||||
'total_amount': total_amount,
|
||||
'filename': filename,
|
||||
'file': base64.encodestring(xml_string),
|
||||
'state': 'finish',
|
||||
})
|
||||
|
||||
action = {
|
||||
'name': _('SEPA File'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': self._name,
|
||||
'res_id': self.ids[0],
|
||||
'target': 'new',
|
||||
}
|
||||
return action
|
||||
filename = '%s%s.xml' % (gen_args['file_prefix'], self.name)
|
||||
return (xml_string, filename)
|
||||
|
||||
@api.model
|
||||
def generate_group_header_block(self, parent_node, gen_args):
|
||||
@@ -145,7 +112,7 @@ class BankingExportPain(models.AbstractModel):
|
||||
group_header_1_0, 'MsgId')
|
||||
message_identification_1_1.text = self._prepare_field(
|
||||
'Message Identification',
|
||||
'self.payment_order_ids[0].reference',
|
||||
'self.name',
|
||||
{'self': self}, 35, gen_args=gen_args)
|
||||
creation_date_time_1_2 = etree.SubElement(group_header_1_0, 'CreDtTm')
|
||||
creation_date_time_1_2.text = datetime.strftime(
|
||||
@@ -196,10 +163,11 @@ class BankingExportPain(models.AbstractModel):
|
||||
instruction_priority_2_7 = etree.SubElement(
|
||||
payment_type_info_2_6, 'InstrPrty')
|
||||
instruction_priority_2_7.text = priority
|
||||
service_level_2_8 = etree.SubElement(
|
||||
payment_type_info_2_6, 'SvcLvl')
|
||||
service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd')
|
||||
service_level_code_2_9.text = 'SEPA'
|
||||
if self.sepa:
|
||||
service_level_2_8 = etree.SubElement(
|
||||
payment_type_info_2_6, 'SvcLvl')
|
||||
service_level_code_2_9 = etree.SubElement(service_level_2_8, 'Cd')
|
||||
service_level_code_2_9.text = 'SEPA'
|
||||
if local_instrument:
|
||||
local_instrument_2_11 = etree.SubElement(
|
||||
payment_type_info_2_6, 'LclInstrm')
|
||||
@@ -230,18 +198,17 @@ class BankingExportPain(models.AbstractModel):
|
||||
def generate_initiating_party_block(self, parent_node, gen_args):
|
||||
my_company_name = self._prepare_field(
|
||||
'Company Name',
|
||||
'self.payment_order_ids[0].mode.bank_id.partner_id.name',
|
||||
'self.company_partner_bank_id.partner_id.name',
|
||||
{'self': self}, gen_args.get('name_maxsize'), gen_args=gen_args)
|
||||
initiating_party_1_8 = etree.SubElement(parent_node, 'InitgPty')
|
||||
initiating_party_name = etree.SubElement(initiating_party_1_8, 'Nm')
|
||||
initiating_party_name.text = my_company_name
|
||||
payment = self.payment_order_ids[0]
|
||||
initiating_party_identifier = (
|
||||
payment.mode.initiating_party_identifier or
|
||||
payment.company_id.initiating_party_identifier)
|
||||
self.payment_mode_id.initiating_party_identifier or
|
||||
self.payment_mode_id.company_id.initiating_party_identifier)
|
||||
initiating_party_issuer = (
|
||||
payment.mode.initiating_party_issuer or
|
||||
payment.company_id.initiating_party_issuer)
|
||||
self.payment_mode_id.initiating_party_issuer or
|
||||
self.payment_mode_id.company_id.initiating_party_issuer)
|
||||
if initiating_party_identifier and initiating_party_issuer:
|
||||
iniparty_id = etree.SubElement(initiating_party_1_8, 'Id')
|
||||
iniparty_org_id = etree.SubElement(iniparty_id, 'OrgId')
|
||||
@@ -252,11 +219,11 @@ class BankingExportPain(models.AbstractModel):
|
||||
iniparty_org_other, 'Issr')
|
||||
iniparty_org_other_issuer.text = initiating_party_issuer
|
||||
elif self._must_have_initiating_party(gen_args):
|
||||
raise Warning(
|
||||
raise UserError(
|
||||
_("Missing 'Initiating Party Issuer' and/or "
|
||||
"'Initiating Party Identifier' for the company '%s'. "
|
||||
"Both fields must have a value.")
|
||||
% payment.company_id.name)
|
||||
% self.company_id.name)
|
||||
return True
|
||||
|
||||
@api.model
|
||||
@@ -275,11 +242,10 @@ class BankingExportPain(models.AbstractModel):
|
||||
party_agent_bic = etree.SubElement(
|
||||
party_agent_institution, gen_args.get('bic_xml_tag'))
|
||||
party_agent_bic.text = bic
|
||||
except Warning:
|
||||
except UserError:
|
||||
if order == 'C':
|
||||
if iban[0:2] != gen_args['initiating_party_country_code']:
|
||||
raise Warning(
|
||||
_('Error:'),
|
||||
raise UserError(
|
||||
_("The bank account with IBAN '%s' of partner '%s' "
|
||||
"must have an associated BIC because it is a "
|
||||
"cross-border SEPA operation.")
|
||||
@@ -314,9 +280,10 @@ class BankingExportPain(models.AbstractModel):
|
||||
party_name = self._prepare_field(
|
||||
'%s Name' % party_type_label, name, eval_ctx,
|
||||
gen_args.get('name_maxsize'), gen_args=gen_args)
|
||||
piban = self._prepare_field(
|
||||
viban = self._prepare_field(
|
||||
'%s IBAN' % party_type_label, iban, eval_ctx, gen_args=gen_args)
|
||||
viban = self._validate_iban(piban)
|
||||
# TODO : add support for bank accounts other than IBAN
|
||||
#viban = self._validate_iban(piban)
|
||||
# At C level, the order is : BIC, Name, IBAN
|
||||
# At B level, the order is : Name, IBAN, BIC
|
||||
if order == 'B':
|
||||
@@ -353,11 +320,6 @@ class BankingExportPain(models.AbstractModel):
|
||||
'line.communication', {'line': line}, 140,
|
||||
gen_args=gen_args)
|
||||
else:
|
||||
if not line.struct_communication_type:
|
||||
raise Warning(
|
||||
_("Missing 'Structured Communication Type' on payment "
|
||||
"line with reference '%s'.")
|
||||
% line.name)
|
||||
remittance_info_structured_2_100 = etree.SubElement(
|
||||
remittance_info_2_91, 'Strd')
|
||||
creditor_ref_information_2_120 = etree.SubElement(
|
||||
@@ -385,7 +347,7 @@ class BankingExportPain(models.AbstractModel):
|
||||
|
||||
creditor_ref_info_type_code_2_123.text = 'SCOR'
|
||||
creditor_ref_info_type_issuer_2_125.text = \
|
||||
line.struct_communication_type
|
||||
line.communication_type
|
||||
creditor_reference_2_126.text = \
|
||||
self._prepare_field(
|
||||
'Creditor Structured Reference',
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class PaymentLine(models.Model):
|
||||
_inherit = 'payment.line'
|
||||
|
||||
@api.model
|
||||
def _get_struct_communication_types(self):
|
||||
return [('ISO', 'ISO')]
|
||||
|
||||
priority = fields.Selection([
|
||||
('NORM', 'Normal'),
|
||||
('HIGH', 'High')],
|
||||
string='Priority', default='NORM',
|
||||
help="This field will be used as the 'Instruction Priority' in "
|
||||
"the generated PAIN file.")
|
||||
# Update size from 64 to 140, because PAIN allows 140 caracters
|
||||
communication = fields.Char(size=140)
|
||||
struct_communication_type = fields.Selection(
|
||||
'_get_struct_communication_types',
|
||||
string='Structured Communication Type', default='ISO')
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
|
||||
|
||||
22
account_banking_pain_base/views/account_payment_line.xml
Normal file
22
account_banking_pain_base/views/account_payment_line.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="account_payment_line_form" model="ir.ui.view">
|
||||
<field name="name">pain.base.account.payment.line</field>
|
||||
<field name="model">account.payment.line</field>
|
||||
<field name="inherit_id" ref="account_payment_order.account_payment_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="communication_type" position="before">
|
||||
<field name="priority"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
30
account_banking_pain_base/views/account_payment_method.xml
Normal file
30
account_banking_pain_base/views/account_payment_method.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="account_payment_method_form" model="ir.ui.view">
|
||||
<field name="name">pain_base.account_payment_method.form</field>
|
||||
<field name="model">account.payment.method</field>
|
||||
<field name="inherit_id" ref="account_payment_mode.account_payment_method_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="payment_type" position="after">
|
||||
<field name="pain_version"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment_method_tree" model="ir.ui.view">
|
||||
<field name="name">pain_base.account_payment_method.tree</field>
|
||||
<field name="model">account.payment.method</field>
|
||||
<field name="inherit_id" ref="account_payment_mode.account_payment_method_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="payment_type" position="after">
|
||||
<field name="pain_version"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
30
account_banking_pain_base/views/account_payment_mode.xml
Normal file
30
account_banking_pain_base/views/account_payment_mode.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
© 2015 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<record id="account_payment_mode_form" model="ir.ui.view">
|
||||
<field name="name">pain_base.account.payment.mode.form</field>
|
||||
<field name="model">account.payment.mode</field>
|
||||
<field name="inherit_id" ref="account_payment_order.account_payment_mode_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="payment_order_options" position="after">
|
||||
<group name="pain_options" string="Options for PAIN">
|
||||
<field name="convert_to_ascii"/>
|
||||
<!-- To be set visible in the localisation modules that need it -->
|
||||
<field name="initiating_party_identifier" invisible="1"/>
|
||||
<field name="initiating_party_issuer" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
24
account_banking_pain_base/views/account_payment_order.xml
Normal file
24
account_banking_pain_base/views/account_payment_order.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="account_payment_order_form" model="ir.ui.view">
|
||||
<field name="name">pain.base.account.payment.order.form</field>
|
||||
<field name="model">account.payment.order</field>
|
||||
<field name="inherit_id" ref="account_payment_order.account_payment_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_partner_bank_id" position="after">
|
||||
<field name="sepa"/>
|
||||
<field name="batch_booking"/>
|
||||
<field name="charge_bearer" attrs="{'invisible': [('sepa', '=', True)]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2015-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
@@ -10,14 +10,11 @@
|
||||
<record id="bank_payment_line_form" model="ir.ui.view">
|
||||
<field name="name">pain.base.bank.payment.line.form</field>
|
||||
<field name="model">bank.payment.line</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.bank_payment_line_form"/>
|
||||
<field name="inherit_id" ref="account_payment_order.bank_payment_line_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bank_id" position="after">
|
||||
<field name="partner_bank_id" position="after">
|
||||
<field name="priority"/>
|
||||
</field>
|
||||
<field name="state" position="after">
|
||||
<field name="struct_communication_type" attrs="{'invisible': [('state', '!=', 'structured')]}"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_payment_order_form" model="ir.ui.view">
|
||||
<field name="name">pain.base.payment.line.inside.order.form</field>
|
||||
<field name="model">payment.order</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.view_payment_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='bank_id']" position="after">
|
||||
<field name="priority"/>
|
||||
<newline />
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/form//field[@name='state']" position="after">
|
||||
<field name="struct_communication_type" attrs="{'invisible': [('state', '!=', 'structured')], 'required': [('state', '=', 'structured')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
© 2015 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_payment_mode_form_inherit" model="ir.ui.view">
|
||||
<field name="name">add.convert_to_ascii.in.payment.mode.form</field>
|
||||
<field name="model">payment.mode</field>
|
||||
<field name="inherit_id" ref="account_banking_payment_export.view_payment_mode_form_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="type" position="after">
|
||||
<field name="convert_to_ascii"/>
|
||||
</field>
|
||||
<xpath expr="//form/group" position="after">
|
||||
<group name="sepa_identifiers" string="SEPA identifiers"
|
||||
attrs="{'invisible': [('sepa_type', '=', False)]}">
|
||||
<field name="sepa_type" invisible="1"/>
|
||||
<group>
|
||||
<field name="initiating_party_identifier" />
|
||||
<field name="initiating_party_issuer"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Akretion (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="bank_payment_line_seq_type" model="ir.sequence.type">
|
||||
<field name="name">Bank Payment Line</field>
|
||||
<field name="code">bank.payment.line</field>
|
||||
</record>
|
||||
|
||||
<record id="bank_payment_line_seq" model="ir.sequence">
|
||||
<field name="name">Bank Payment Line</field>
|
||||
<field name="code">bank.payment.line</field>
|
||||
<field name="prefix">L</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="number_next">1</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,11 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import account_payment
|
||||
# important: import payment_mode_type before payment_mode
|
||||
# to let the _auto_init work properly
|
||||
from . import payment_mode_type
|
||||
from . import payment_mode
|
||||
from . import account_move_line
|
||||
from . import account_invoice
|
||||
from . import bank_payment_line
|
||||
from . import payment_line
|
||||
from . import res_partner_bank
|
||||
@@ -1,37 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2004-2014 OpenERP S.A. (http://www.openerp.com/)
|
||||
# © 2014 Akretion (http://www.akretion.com/)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
@api.one
|
||||
def _get_journal_entry_ref(self):
|
||||
if self.move_id.state == 'draft':
|
||||
if self.invoice.id:
|
||||
self.journal_entry_ref = self.invoice.number
|
||||
else:
|
||||
self.journal_entry_ref = '*' + str(self.move_id.id)
|
||||
else:
|
||||
self.journal_entry_ref = self.move_id.name
|
||||
|
||||
journal_entry_ref = fields.Char(compute=_get_journal_entry_ref,
|
||||
string='Journal Entry Ref')
|
||||
|
||||
@api.multi
|
||||
def get_balance(self):
|
||||
"""
|
||||
Return the balance of any set of move lines.
|
||||
|
||||
Not to be confused with the 'balance' field on this model, which
|
||||
returns the account balance that the move line applies to.
|
||||
"""
|
||||
total = 0.0
|
||||
for line in self:
|
||||
total += (line.debit or 0.0) - (line.credit or 0.0)
|
||||
return total
|
||||
@@ -1,159 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2009 EduSense BV (<http://www.edusense.nl>)
|
||||
# © 2011-2013 Therp BV (<http://therp.nl>)
|
||||
# © 2016 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, exceptions, workflow, _
|
||||
try:
|
||||
# This is to avoid the drop of the column total each time you update
|
||||
# the module account_payment, because the store attribute is set later
|
||||
# and Odoo doesn't defer this removal
|
||||
from openerp.addons.account_payment.account_payment import payment_order
|
||||
payment_order._columns['total'].nodrop = True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class PaymentOrder(models.Model):
|
||||
_inherit = 'payment.order'
|
||||
|
||||
payment_order_type = fields.Selection(
|
||||
[('payment', 'Payment'), ('debit', 'Direct debit')],
|
||||
'Payment order type', required=True, default='payment',
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
mode_type = fields.Many2one('payment.mode.type', related='mode.type',
|
||||
string='Payment Type')
|
||||
bank_line_ids = fields.One2many(
|
||||
'bank.payment.line', 'order_id', string="Bank Payment Lines",
|
||||
readonly=True)
|
||||
total = fields.Float(compute='_compute_total', store=True)
|
||||
bank_line_count = fields.Integer(
|
||||
compute='_bank_line_count', string='Number of Bank Lines')
|
||||
|
||||
@api.depends('line_ids', 'line_ids.amount')
|
||||
@api.one
|
||||
def _compute_total(self):
|
||||
self.total = sum(self.mapped('line_ids.amount') or [0.0])
|
||||
|
||||
@api.multi
|
||||
@api.depends('bank_line_ids')
|
||||
def _bank_line_count(self):
|
||||
for order in self:
|
||||
order.bank_line_count = len(order.bank_line_ids)
|
||||
|
||||
@api.multi
|
||||
def launch_wizard(self):
|
||||
"""Search for a wizard to launch according to the type.
|
||||
If type is manual. just confirm the order.
|
||||
Previously (pre-v6) in account_payment/wizard/wizard_pay.py
|
||||
"""
|
||||
context = self.env.context.copy()
|
||||
order = self[0]
|
||||
# check if a wizard is defined for the first order
|
||||
if order.mode.type and order.mode.type.ir_model_id:
|
||||
context['active_ids'] = self.ids
|
||||
wizard_model = order.mode.type.ir_model_id.model
|
||||
wizard_obj = self.env[wizard_model]
|
||||
return {
|
||||
'name': wizard_obj._description or _('Payment Order Export'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': wizard_model,
|
||||
'domain': [],
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'nodestroy': True,
|
||||
}
|
||||
else:
|
||||
# should all be manual orders without type or wizard model
|
||||
for order in self[1:]:
|
||||
if order.mode.type and order.mode.type.ir_model_id:
|
||||
raise exceptions.Warning(
|
||||
_('Error'),
|
||||
_('You can only combine payment orders of the same '
|
||||
'type'))
|
||||
# process manual payments
|
||||
for order_id in self.ids:
|
||||
workflow.trg_validate(self.env.uid, 'payment.order',
|
||||
order_id, 'done', self.env.cr)
|
||||
return {}
|
||||
|
||||
@api.multi
|
||||
def action_done(self):
|
||||
self.write({
|
||||
'date_done': fields.Date.context_today(self),
|
||||
'state': 'done',
|
||||
})
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def action_cancel(self):
|
||||
for order in self:
|
||||
order.write({'state': 'cancel'})
|
||||
order.bank_line_ids.unlink()
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def _prepare_bank_payment_line(self, paylines):
|
||||
return {
|
||||
'order_id': paylines[0].order_id.id,
|
||||
'payment_line_ids': [(6, 0, paylines.ids)],
|
||||
'communication': '-'.join(
|
||||
[line.communication for line in paylines]),
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def action_open(self):
|
||||
"""
|
||||
Called when you click on the 'Confirm' button
|
||||
Set the 'date' on payment line depending on the 'date_prefered'
|
||||
setting of the payment.order
|
||||
Re-generate the bank payment lines
|
||||
"""
|
||||
res = super(PaymentOrder, self).action_open()
|
||||
bplo = self.env['bank.payment.line']
|
||||
today = fields.Date.context_today(self)
|
||||
for order in self:
|
||||
# Delete existing bank payment lines
|
||||
order.bank_line_ids.unlink()
|
||||
# Create the bank payment lines from the payment lines
|
||||
group_paylines = {} # key = hashcode
|
||||
for payline in order.line_ids:
|
||||
# Compute requested payment date
|
||||
if order.date_prefered == 'due':
|
||||
requested_date = payline.ml_maturity_date or today
|
||||
elif order.date_prefered == 'fixed':
|
||||
requested_date = order.date_scheduled or today
|
||||
else:
|
||||
requested_date = today
|
||||
# Write requested_date on 'date' field of payment line
|
||||
payline.date = requested_date
|
||||
# Group options
|
||||
if order.mode.group_lines:
|
||||
hashcode = payline.payment_line_hashcode()
|
||||
else:
|
||||
# Use line ID as hascode, which actually means no grouping
|
||||
hashcode = payline.id
|
||||
if hashcode in group_paylines:
|
||||
group_paylines[hashcode]['paylines'] += payline
|
||||
group_paylines[hashcode]['total'] +=\
|
||||
payline.amount_currency
|
||||
else:
|
||||
group_paylines[hashcode] = {
|
||||
'paylines': payline,
|
||||
'total': payline.amount_currency,
|
||||
}
|
||||
# Create bank payment lines
|
||||
for paydict in group_paylines.values():
|
||||
# Block if a bank payment line is <= 0
|
||||
if paydict['total'] <= 0:
|
||||
raise exceptions.Warning(_(
|
||||
"The amount for Partner '%s' is negative "
|
||||
"or null (%.2f) !")
|
||||
% (paydict['paylines'][0].partner_id.name,
|
||||
paydict['total']))
|
||||
vals = self._prepare_bank_payment_line(paydict['paylines'])
|
||||
bplo.create(vals)
|
||||
return res
|
||||
@@ -1,68 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
import openerp.addons.decimal_precision as dp
|
||||
|
||||
|
||||
class BankPaymentLine(models.Model):
|
||||
_name = 'bank.payment.line'
|
||||
_description = 'Bank Payment Lines'
|
||||
|
||||
name = fields.Char(string='Bank Payment Line Ref', required=True)
|
||||
order_id = fields.Many2one(
|
||||
'payment.order', string='Order', ondelete='cascade', select=True)
|
||||
payment_line_ids = fields.One2many(
|
||||
'payment.line', 'bank_line_id', string='Payment Lines')
|
||||
partner_id = fields.Many2one(
|
||||
'res.partner', string='Partner', related='payment_line_ids.partner_id')
|
||||
# Function Float fields are sometimes badly displayed in tree view,
|
||||
# see bug report https://github.com/odoo/odoo/issues/8632
|
||||
amount_currency = fields.Float(
|
||||
string='Amount', digits=dp.get_precision('Account'),
|
||||
compute='_compute_amount', store=True)
|
||||
# I would have preferred currency_id, but I need to keep the field names
|
||||
# similar to the field names of payment.line
|
||||
currency = fields.Many2one(
|
||||
'res.currency', string='Currency', required=True,
|
||||
related='payment_line_ids.currency')
|
||||
bank_id = fields.Many2one(
|
||||
'res.partner.bank', string='Bank Account',
|
||||
related='payment_line_ids.bank_id')
|
||||
date = fields.Date(
|
||||
string='Payment Date', related='payment_line_ids.date')
|
||||
state = fields.Selection(
|
||||
related='payment_line_ids.state', string='Communication Type')
|
||||
communication = fields.Char(string='Communication', required=True)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company', readonly=True,
|
||||
related='order_id.company_id', store=True)
|
||||
|
||||
@api.model
|
||||
def same_fields_payment_line_and_bank_payment_line(self):
|
||||
"""
|
||||
This list of fields is used both to compute the grouping
|
||||
hashcode and to copy the values from payment line
|
||||
to bank payment line
|
||||
The fields must have the same name on the 2 objects
|
||||
"""
|
||||
same_fields = [
|
||||
'currency', 'partner_id',
|
||||
'bank_id', 'date', 'state']
|
||||
return same_fields
|
||||
|
||||
@api.multi
|
||||
@api.depends('payment_line_ids', 'payment_line_ids.amount_currency')
|
||||
def _compute_amount(self):
|
||||
for line in self:
|
||||
line.amount_currency = sum(
|
||||
line.mapped('payment_line_ids.amount_currency'))
|
||||
|
||||
@api.model
|
||||
@api.returns('self')
|
||||
def create(self, vals):
|
||||
if vals.get('name', '/') == '/':
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'bank.payment.line')
|
||||
return super(BankPaymentLine, self).create(vals)
|
||||
@@ -1,22 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class PaymentLine(models.Model):
|
||||
_inherit = 'payment.line'
|
||||
|
||||
bank_line_id = fields.Many2one(
|
||||
'bank.payment.line', string='Bank Payment Line')
|
||||
|
||||
@api.multi
|
||||
def payment_line_hashcode(self):
|
||||
self.ensure_one()
|
||||
bplo = self.env['bank.payment.line']
|
||||
values = []
|
||||
for field in bplo.same_fields_payment_line_and_bank_payment_line():
|
||||
values.append(unicode(self[field]))
|
||||
hashcode = '-'.join(values)
|
||||
return hashcode
|
||||
@@ -1,119 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2009 EduSense BV (<http://www.edusense.nl>)
|
||||
# © 2011-2013 Therp BV (<http://therp.nl>)
|
||||
# © 2014-2016 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, SUPERUSER_ID
|
||||
|
||||
|
||||
class PaymentMode(models.Model):
|
||||
"""Restoring the payment type from version 5,
|
||||
used to select the export wizard (if any)
|
||||
"""
|
||||
_inherit = "payment.mode"
|
||||
|
||||
def _get_manual_bank_transfer(self, cr, uid, context=None):
|
||||
""" hack: pre-create the manual bank transfer that is also
|
||||
defined in the data directory, so we have an id in to use
|
||||
in _auto_init """
|
||||
model_data = self.pool['ir.model.data']
|
||||
try:
|
||||
_, res = model_data.get_object_reference(
|
||||
cr, uid,
|
||||
'account_banking_payment_export',
|
||||
'manual_bank_tranfer')
|
||||
except ValueError:
|
||||
payment_mode_type = self.pool['payment.mode.type']
|
||||
res = payment_mode_type.create(
|
||||
cr, uid,
|
||||
{'name': 'Manual Bank Transfer',
|
||||
'code': 'BANKMAN'})
|
||||
model_data.create(
|
||||
cr, uid,
|
||||
{'module': 'account_banking_payment_export',
|
||||
'model': 'payment.mode.type',
|
||||
'name': 'manual_bank_tranfer',
|
||||
'res_id': res,
|
||||
'noupdate': False})
|
||||
return res
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
""" hack: pre-create and initialize the type column so that the
|
||||
constraint setting will not fail, this is a hack, made necessary
|
||||
because Odoo tries to set the not-null constraint before
|
||||
applying default values """
|
||||
self._field_create(cr, context=context)
|
||||
column_data = self._select_column_data(cr)
|
||||
if 'type' not in column_data:
|
||||
default_type = self._get_manual_bank_transfer(
|
||||
cr, SUPERUSER_ID, context=context)
|
||||
if default_type:
|
||||
cr.execute('ALTER TABLE "{table}" ADD COLUMN "type" INTEGER'.
|
||||
format(table=self._table))
|
||||
cr.execute('UPDATE "{table}" SET type=%s'.
|
||||
format(table=self._table),
|
||||
(default_type,))
|
||||
return super(PaymentMode, self)._auto_init(cr, context=context)
|
||||
|
||||
def suitable_bank_types(self, cr, uid, payment_mode_id=None, context=None):
|
||||
""" Reinstates functional code for suitable bank type filtering.
|
||||
Current code in account_payment is disfunctional.
|
||||
"""
|
||||
res = []
|
||||
payment_mode = self.browse(cr, uid, payment_mode_id, context=context)
|
||||
if (payment_mode and payment_mode.type and
|
||||
payment_mode.type.suitable_bank_types):
|
||||
res = [t.code for t in payment_mode.type.suitable_bank_types]
|
||||
return res
|
||||
|
||||
type = fields.Many2one(
|
||||
'payment.mode.type', string='Export type', required=True,
|
||||
help='Select the Export Payment Type for the Payment Mode.')
|
||||
payment_order_type = fields.Selection(
|
||||
related='type.payment_order_type', readonly=True, string="Order Type",
|
||||
help="This field, that comes from export type, determines if this "
|
||||
"mode can be selected for customers or suppliers.")
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
sale_ok = fields.Boolean(string='Selectable on sale operations',
|
||||
default=True)
|
||||
purchase_ok = fields.Boolean(string='Selectable on purchase operations',
|
||||
default=True)
|
||||
note = fields.Text(string="Note", translate=True)
|
||||
# Default options for the "payment.order.create" wizard
|
||||
default_journal_ids = fields.Many2many(
|
||||
'account.journal', string="Journals Filter")
|
||||
default_invoice = fields.Boolean(
|
||||
string='Linked to an Invoice or Refund', default=False)
|
||||
default_date_type = fields.Selection([
|
||||
('due', 'Due'),
|
||||
('move', 'Move'),
|
||||
], default='due', string="Type of Date Filter")
|
||||
default_populate_results = fields.Boolean(
|
||||
string='Populate Results Directly')
|
||||
group_lines = fields.Boolean(
|
||||
string="Group lines in payment orders", default=True,
|
||||
help="If this mark is checked, the payment order lines will be "
|
||||
"grouped when validating the payment order before exporting the "
|
||||
"bank file. The grouping will be done only if the following "
|
||||
"fields matches:\n"
|
||||
"* Partner\n"
|
||||
"* Currency\n"
|
||||
"* Destination Bank Account\n"
|
||||
"* Communication Type (structured, free)\n"
|
||||
"* Payment Date\n"
|
||||
"(other modules can set additional fields to restrict the "
|
||||
"grouping.)")
|
||||
|
||||
@api.onchange('type')
|
||||
def type_on_change(self):
|
||||
if self.type:
|
||||
ajo = self.env['account.journal']
|
||||
aj_ids = []
|
||||
if self.type.payment_order_type == 'payment':
|
||||
aj_ids = ajo.search([
|
||||
('type', 'in', ('purchase_refund', 'purchase'))]).ids
|
||||
elif self.type.payment_order_type == 'debit':
|
||||
aj_ids = ajo.search([
|
||||
('type', 'in', ('sale_refund', 'sale'))]).ids
|
||||
self.default_journal_ids = [(6, 0, aj_ids)]
|
||||
@@ -1,44 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2009 EduSense BV (<http://www.edusense.nl>)
|
||||
# © 2011-2013 Therp BV (<http://therp.nl>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields
|
||||
|
||||
|
||||
class PaymentModeType(models.Model):
|
||||
_name = 'payment.mode.type'
|
||||
_description = 'Payment Mode Type'
|
||||
|
||||
name = fields.Char('Name', size=64, required=True, help='Payment Type')
|
||||
code = fields.Char('Code', size=64, required=True,
|
||||
help='Specify the Code for Payment Type')
|
||||
suitable_bank_types = fields.Many2many(
|
||||
comodel_name='res.partner.bank.type',
|
||||
relation='bank_type_payment_type_rel', column1='pay_type_id',
|
||||
column2='bank_type_id', string='Suitable bank types', required=True)
|
||||
ir_model_id = fields.Many2one(
|
||||
'ir.model', string='Payment wizard',
|
||||
help='Select the Payment Wizard for payments of this type. Leave '
|
||||
'empty for manual processing',
|
||||
domain=[('osv_memory', '=', True)])
|
||||
payment_order_type = fields.Selection(
|
||||
[('payment', 'Payment'),
|
||||
('debit', 'Debit')],
|
||||
string='Order type', required=True, default='payment',
|
||||
help="This field determines if this type applies to customers "
|
||||
"(Debit) or suppliers (Payment)")
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
|
||||
def _auto_init(self, cr, context=None):
|
||||
res = super(PaymentModeType, self)._auto_init(cr, context=context)
|
||||
# migrate xmlid from manual_bank_transfer to avoid dependency on
|
||||
# account_banking
|
||||
cr.execute(
|
||||
"""UPDATE ir_model_data
|
||||
SET module='account_banking_payment_export'
|
||||
WHERE module='account_banking' AND
|
||||
name='manual_bank_tranfer' AND
|
||||
model='payment.mode.type'""")
|
||||
return res
|
||||
@@ -1,3 +0,0 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1
|
||||
"access_bank_payment_line","Full access on bank.payment.line to Payment Manager","model_bank_payment_line","account_payment.group_account_payment",1,1,1,1
|
||||
|
@@ -1,107 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
|
||||
<!-- restore wizard functionality when making payments -->
|
||||
<record id="view_payment_order_form" model="ir.ui.view">
|
||||
<field name="name">account.payment.order.form.banking-1</field>
|
||||
<field name="inherit_id" ref="account_payment.view_payment_order_form" />
|
||||
<field name="model">payment.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//button[@string='Make Payments']" position="attributes">
|
||||
<attribute name="name">launch_wizard</attribute>
|
||||
</xpath>
|
||||
<field name="mode" position="after">
|
||||
<field name="mode_type" invisible="1"/>
|
||||
<field name="payment_order_type" invisible="1"/>
|
||||
<field name="bank_line_count" attrs="{'invisible': [('state', 'in', ('draft', 'cancel'))]}"/>
|
||||
</field>
|
||||
<xpath expr="//button[@string='Invoices']" position="attributes">
|
||||
<attribute name="attrs">{
|
||||
'invisible': [('state', '!=', 'draft')]}</attribute>
|
||||
</xpath>
|
||||
<!-- sorry, I have no choice but to replace the line_ids field
|
||||
in order to introduce a 'notebook' in this view -->
|
||||
<field name="line_ids" position="replace">
|
||||
<notebook>
|
||||
<page string="Payment Lines" name="payment-lines">
|
||||
<!-- copy/paste from the view that we inherit -->
|
||||
<field name="line_ids" context="{'order_id': active_id or False}" >
|
||||
<form string="Payment Line">
|
||||
<notebook>
|
||||
<page string="Payment">
|
||||
<group col="4">
|
||||
<field name="move_line_id" on_change="onchange_move_line(move_line_id,parent.mode,parent.date_prefered,parent.date_scheduled,currency,company_currency)" domain="[('reconcile_id','=', False), ('account_id.reconcile', '=', True)] "/> <!-- we removed the filter on amount_to_pay, because we want to be able to select refunds -->
|
||||
<separator colspan="4" string="Transaction Information"/>
|
||||
<field name="date"/>
|
||||
<label for="amount_currency" string="Amount"/>
|
||||
<div>
|
||||
<field name="amount_currency" on_change="onchange_amount(amount_currency,currency,company_currency)" class="oe_inline"/>
|
||||
<field name="currency" nolabel="1" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="partner_id" on_change="onchange_partner(partner_id,parent.mode)"/>
|
||||
<field domain="[('partner_id','=',partner_id)]" name="bank_id"/>
|
||||
<separator colspan="2" string="Owner Account"/>
|
||||
<separator colspan="2" string="Partner Bank Account"/>
|
||||
<field colspan="2" name="info_owner" nolabel="1"/>
|
||||
<field colspan="2" name="info_partner" nolabel="1"/>
|
||||
<field colspan="4" name="communication"/>
|
||||
<field colspan="4" name="communication2"/>
|
||||
<field name="name"/>
|
||||
<field name="state"/>
|
||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Information">
|
||||
<group col="4" string="General Information">
|
||||
<label for="amount" groups="base.group_multi_currency"/>
|
||||
<div groups="base.group_multi_currency">
|
||||
<field name="amount" class="oe_inline"/>
|
||||
<field name="company_currency" class="oe_inline"/>
|
||||
</div>
|
||||
<separator colspan="4" string="Entry Information"/>
|
||||
<field name="create_date" readonly="1"/>
|
||||
<field name="ml_maturity_date"/>
|
||||
<field name="ml_inv_ref"/>
|
||||
<field name="bank_line_id" readonly="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
<tree string="Payment Line">
|
||||
<field name="ml_inv_ref" />
|
||||
<field name="partner_id"/>
|
||||
<field name="communication"/>
|
||||
<field name="bank_id" domain="[('partner_id', '=', partner_id)]"/>
|
||||
<field name="ml_maturity_date"/>
|
||||
<field name="date"/>
|
||||
<field name="amount_currency" string="Amount"/>
|
||||
<field name="currency"/>
|
||||
<field name="name"/>
|
||||
<field name="amount" sum="Total in Company Currency" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
<!-- end of the copy/paste -->
|
||||
</page>
|
||||
<page string="Bank Payment Lines" name="bank-payment-lines">
|
||||
<field name="bank_line_ids" context="{'search_payment_order_type': context.get('search_payment_order_type')}"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_payment_order_tree" model="ir.ui.view">
|
||||
<field name="name">account_banking_payment_export.payment.order.tree</field>
|
||||
<field name="inherit_id" ref="account_payment.view_payment_order_tree" />
|
||||
<field name="model">payment.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="date_done" position="after">
|
||||
<field name="bank_line_count"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_payment_manual_form" model="ir.ui.view">
|
||||
<field name="name">Form for manual payment wizard</field>
|
||||
<field name="model">payment.manual</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Manual payment" version="7.0">
|
||||
<label string="Please execute payment order manually, and click OK when succesfully sent."/>
|
||||
<footer>
|
||||
<button name="button_ok" type="object" string="OK" class="oe_highlight"/>
|
||||
<button special="cancel" string="Cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,37 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!--
|
||||
Add the payment mode type settings
|
||||
-->
|
||||
<record id="view_payment_mode_form_inherit" model="ir.ui.view">
|
||||
<field name="name">payment.mode.form.inherit</field>
|
||||
<field name="model">payment.mode</field>
|
||||
<field name="inherit_id" ref="account_payment.view_payment_mode_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="after">
|
||||
<field name="active"/>
|
||||
<field name="type"/>
|
||||
<field name="purchase_ok"/>
|
||||
<field name="sale_ok"/>
|
||||
</field>
|
||||
<form position="inside">
|
||||
<group name="payment_order_create_defaults" string="Select Move Lines to Pay - Default Values">
|
||||
<field name="default_populate_results"/>
|
||||
<field name="default_journal_ids" widget="many2many_tags"/>
|
||||
<field name="default_invoice"/>
|
||||
<field name="default_date_type"/>
|
||||
</group>
|
||||
<group name="group_grouping" string="Line grouping">
|
||||
<field name="group_lines"/>
|
||||
</group>
|
||||
<group string="Note" col="4">
|
||||
<field name="note" nolabel="1"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_payment_mode_tree_inherit" model="ir.ui.view">
|
||||
<field name="name">payment.mode.tree.inherit</field>
|
||||
<field name="model">payment.mode</field>
|
||||
<field name="inherit_id" ref="account_payment.view_payment_mode_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="company_id" position="after">
|
||||
<field name="type"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- basic view for payment mode type -->
|
||||
<record model="ir.ui.view" id="view_payment_mode_type_form">
|
||||
<field name="name">view.payment.mode.type.form</field>
|
||||
<field name="model">payment.mode.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Payment Type" version="7.0">
|
||||
<group name="main">
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="ir_model_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Suitable bank types">
|
||||
<field name="suitable_bank_types"
|
||||
nolabel="1"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_payment_mode_type_tree" model="ir.ui.view">
|
||||
<field name="name">view.payment.mode.type.tree</field>
|
||||
<field name="model">payment.mode.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Payment Types">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="active"/>
|
||||
<field name="ir_model_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_payment_mode_type" model="ir.actions.act_window">
|
||||
<field name="name">Payment Export Types</field>
|
||||
<field name="res_model">payment.mode.type</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{'active_test': False}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_payment_mode_type"
|
||||
action="action_payment_mode_type"
|
||||
parent="account.menu_configuration_misc" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,3 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import payment_order_create
|
||||
from . import bank_payment_manual
|
||||
@@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (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 contains a single "wizard" for confirming manual
|
||||
bank transfers.
|
||||
"""
|
||||
|
||||
from openerp import models, api, workflow
|
||||
|
||||
|
||||
class PaymentManual(models.TransientModel):
|
||||
_name = 'payment.manual'
|
||||
_description = 'Send payment order(s) manually'
|
||||
|
||||
@api.multi
|
||||
def button_ok(self):
|
||||
for order_id in self.env.context.get('active_ids', []):
|
||||
workflow.trg_validate(self.env.uid, 'payment.order', order_id,
|
||||
'done', self.env.cr)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_payment_manual_form" model="ir.ui.view">
|
||||
<field name="name">Form for manual payment wizard</field>
|
||||
<field name="model">payment.manual</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Manual payment" version="7.0">
|
||||
<label string="Please execute payment order manually, and click OK when succesfully sent."/>
|
||||
<footer>
|
||||
<button name="button_ok" type="object" string="OK" class="oe_highlight"/>
|
||||
<button special="cancel" string="Cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_create_payment_order" model="ir.ui.view">
|
||||
<field name="name">payment.order.create.form.export</field>
|
||||
<field name="model">payment.order.create</field>
|
||||
<field name="inherit_id" ref="account_payment.view_create_payment_order"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="duedate" position="after">
|
||||
<field name="journal_ids"
|
||||
widget="many2many_tags"
|
||||
placeholder="Keep empty for using all journals"
|
||||
/>
|
||||
<field name="invoice"/>
|
||||
<field name="populate_results"/>
|
||||
</field>
|
||||
<field name="duedate" position="before">
|
||||
<field name="date_type"/>
|
||||
<field name="move_date" attrs="{'required': [('date_type', '=', 'move')], 'invisible': [('date_type', '!=', 'move')]}"/>
|
||||
</field>
|
||||
<field name="duedate" position="attributes">
|
||||
<attribute name="attrs">{'required': [('date_type', '=', 'due')], 'invisible': [('date_type', '!=', 'due')]}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_create_payment_order_lines" model="ir.ui.view">
|
||||
<field name="name">add.context.to.display.maturity.date</field>
|
||||
<field name="model">payment.order.create</field>
|
||||
<field name="inherit_id" ref="account_payment.view_create_payment_order_lines"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="entries" position="attributes">
|
||||
<attribute name="context">{'display_credit': context.get('display_credit', False),'display_debit': context.get('display_debit', False),'journal_type': 'sale', 'tree_view_ref' : 'account_banking_payment_export.payment_order_populate_view_move_line_tree'}</attribute>
|
||||
<attribute name="nolabel">1</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="payment_order_populate_view_move_line_tree" model="ir.ui.view">
|
||||
<field name="name">payment.order.populate.account.move.line.tree</field>
|
||||
<field name="model">account.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Journal Items">
|
||||
<field name="journal_id" />
|
||||
<field name="date"/>
|
||||
<field name="name"/>
|
||||
<field name="ref"/>
|
||||
<field name="partner_id" />
|
||||
<field name="account_id" />
|
||||
<field name="journal_entry_ref" string="Journal Entry" />
|
||||
<field name="debit" sum="Total Debit" invisible="not context.get('display_debit', False)"/>
|
||||
<field name="credit" sum="Total Credit" invisible="not context.get('display_credit', False)"/>
|
||||
<field name="amount_residual" />
|
||||
<field name="date_maturity" invisible="context.get('journal_type', False) not in ['sale','sale_refund','purchase','purchase_refund']" />
|
||||
<field name="reconcile_ref"/>
|
||||
<field name="amount_currency" invisible="not context.get('currency',False)"/>
|
||||
<field name="currency_id" invisible="not context.get('currency',False)" />
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Akretion (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="account_payment.act_done" model="workflow.activity">
|
||||
<field name="action">action_done()</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment.act_cancel" model="workflow.activity">
|
||||
<field name="action">action_cancel()</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -2,4 +2,3 @@
|
||||
# © 2010-2013 Akretion (www.akretion.com)
|
||||
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2010-2015 Akretion (www.akretion.com)
|
||||
# © 2010-2016 Akretion (www.akretion.com)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
'name': 'Account Banking SEPA Credit Transfer',
|
||||
'summary': 'Create SEPA XML files for Credit Transfers',
|
||||
'version': '8.0.0.5.0',
|
||||
'version': '9.0.1.0.0',
|
||||
'license': 'AGPL-3',
|
||||
'author': "Akretion, "
|
||||
"Serv. Tecnol. Avanzados - Pedro M. Baeza, "
|
||||
@@ -15,13 +15,13 @@
|
||||
"Odoo Community Association (OCA)",
|
||||
'website': 'https://github.com/OCA/bank-payment',
|
||||
'category': 'Banking addons',
|
||||
'conflicts': ['account_sepa'],
|
||||
'depends': ['account_banking_pain_base'],
|
||||
'data': [
|
||||
'wizard/export_sepa_view.xml',
|
||||
'data/payment_type_sepa_sct.xml',
|
||||
'data/account_payment_method.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/sepa_credit_transfer_demo.xml'
|
||||
],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
|
||||
|
||||
<record id="sepa_credit_transfer" model="account.payment.method">
|
||||
<field name="name">SEPA Credit Transfer to suppliers</field>
|
||||
<field name="code">sepa_credit_transfer</field>
|
||||
<field name="payment_type">outbound</field>
|
||||
<field name="pain_version">pain.001.001.03</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
|
||||
|
||||
<!-- TODO In the suitable_bank_types field, we should restrict to IBAN type and Rib+IBAN of l10n_fr_rib ? -->
|
||||
<record id="export_sepa_sct_001_001_05" model="payment.mode.type">
|
||||
<field name="name">SEPA Credit Transfer v05</field>
|
||||
<field name="code">pain.001.001.05</field>
|
||||
<field name="payment_order_type">payment</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
|
||||
</record>
|
||||
|
||||
<record id="export_sepa_sct_001_001_04" model="payment.mode.type">
|
||||
<field name="name">SEPA Credit Transfer v04</field>
|
||||
<field name="code">pain.001.001.04</field>
|
||||
<field name="payment_order_type">payment</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
|
||||
</record>
|
||||
|
||||
<record id="export_sepa_sct_001_001_03" model="payment.mode.type">
|
||||
<field name="name">SEPA Credit Transfer v03 (recommended)</field>
|
||||
<field name="code">pain.001.001.03</field>
|
||||
<field name="payment_order_type">payment</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
|
||||
</record>
|
||||
|
||||
<record id="export_sepa_sct_001_001_02" model="payment.mode.type">
|
||||
<field name="name">SEPA Credit Transfer v02</field>
|
||||
<field name="code">pain.001.001.02</field>
|
||||
<field name="payment_order_type">payment</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
|
||||
</record>
|
||||
|
||||
<record id="export_sepa_sct_001_003_03" model="payment.mode.type">
|
||||
<field name="name">SEPA Credit Transfer pain 001.003.03 (used in Germany)</field>
|
||||
<field name="code">pain.001.003.03</field>
|
||||
<field name="payment_order_type">payment</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sepa_wizard"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -3,13 +3,12 @@
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="sepa_credit_transfer_mode" model="payment.mode">
|
||||
<field name="name">SEPA Credit Transfer La Banque Postale</field>
|
||||
<field name="journal" ref="account.bank_journal"/>
|
||||
<field name="bank_id" ref="account_banking_payment_export.main_company_iban"/>
|
||||
<record id="payment_mode_outbound_sepa_ct1" model="account.payment.mode">
|
||||
<field name="name">SEPA Credit Transfer to suppliers</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="type" ref="export_sepa_sct_001_001_03"/>
|
||||
<field name="sale_ok" eval="False"/>
|
||||
<field name="bank_account_link">variable</field>
|
||||
<field name="payment_method_id" ref="sepa_credit_transfer"/>
|
||||
<field name="default_journal_ids" search="[('type', 'in', ('purchase', 'purchase_refund'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import payment_mode
|
||||
from . import account_payment_method
|
||||
from . import account_payment_order
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountPaymentMethod(models.Model):
|
||||
_inherit = 'account.payment.method'
|
||||
|
||||
pain_version = fields.Selection(selection_add=[
|
||||
('pain.001.001.02', 'pain.001.001.02'),
|
||||
('pain.001.001.03', 'pain.001.001.03 (recommended)'),
|
||||
('pain.001.001.04', 'pain.001.001.04'),
|
||||
('pain.001.001.05', 'pain.001.001.05'),
|
||||
('pain.001.003.03', 'pain.001.003.03 (used in Germany)'),
|
||||
])
|
||||
|
||||
@api.multi
|
||||
def get_xsd_file_path(self):
|
||||
self.ensure_one()
|
||||
if self.pain_version in [
|
||||
'pain.001.001.02', 'pain.001.001.03', 'pain.001.001.04',
|
||||
'pain.001.001.05', 'pain.001.003.03']:
|
||||
path = 'account_banking_sepa_credit_transfer/data/%s.xsd'\
|
||||
% self.pain_version
|
||||
return path
|
||||
return super(AccountPaymentMethod, self).get_xsd_file_path()
|
||||
@@ -1,67 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2010-2015 Akretion (www.akretion.com)
|
||||
# © 2010-2016 Akretion (www.akretion.com)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import Warning
|
||||
from openerp import workflow
|
||||
from openerp import models, api, _
|
||||
from openerp.exceptions import UserError
|
||||
from lxml import etree
|
||||
|
||||
|
||||
class BankingExportSepaWizard(models.TransientModel):
|
||||
_name = 'banking.export.sepa.wizard'
|
||||
_inherit = ['banking.export.pain']
|
||||
_description = 'Export SEPA Credit Transfer File'
|
||||
|
||||
state = fields.Selection([
|
||||
('create', 'Create'),
|
||||
('finish', 'Finish')],
|
||||
string='State', readonly=True, default='create')
|
||||
batch_booking = fields.Boolean(
|
||||
string='Batch Booking',
|
||||
help="If true, the bank statement will display only one debit "
|
||||
"line for all the wire transfers of the SEPA XML file ; if "
|
||||
"false, the bank statement will display one debit line per wire "
|
||||
"transfer of the SEPA XML file.")
|
||||
charge_bearer = fields.Selection([
|
||||
('SLEV', 'Following Service Level'),
|
||||
('SHAR', 'Shared'),
|
||||
('CRED', 'Borne by Creditor'),
|
||||
('DEBT', 'Borne by Debtor')], string='Charge Bearer',
|
||||
default='SLEV', required=True,
|
||||
help="Following service level : transaction charges are to be "
|
||||
"applied following the rules agreed in the service level "
|
||||
"and/or scheme (SEPA Core messages must use this). Shared : "
|
||||
"transaction charges on the debtor side are to be borne by "
|
||||
"the debtor, transaction charges on the creditor side are to "
|
||||
"be borne by the creditor. Borne by creditor : all "
|
||||
"transaction charges are to be borne by the creditor. Borne "
|
||||
"by debtor : all transaction charges are to be borne by the "
|
||||
"debtor.")
|
||||
nb_transactions = fields.Integer(
|
||||
string='Number of Transactions', readonly=True)
|
||||
total_amount = fields.Float(string='Total Amount', readonly=True)
|
||||
file = fields.Binary(string="File", readonly=True)
|
||||
filename = fields.Char(string="Filename", readonly=True)
|
||||
payment_order_ids = fields.Many2many(
|
||||
'payment.order', 'wiz_sepa_payorders_rel', 'wizard_id',
|
||||
'payment_order_id', string='Payment Orders', readonly=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
payment_order_ids = self._context.get('active_ids', [])
|
||||
vals.update({
|
||||
'payment_order_ids': [[6, 0, payment_order_ids]],
|
||||
})
|
||||
return super(BankingExportSepaWizard, self).create(vals)
|
||||
class AccountPaymentOrder(models.Model):
|
||||
_inherit = 'account.payment.order'
|
||||
|
||||
@api.multi
|
||||
def create_sepa(self):
|
||||
def generate_payment_file(self):
|
||||
"""Creates the SEPA Credit Transfer file. That's the important code!"""
|
||||
pain_flavor = self.payment_order_ids[0].mode.type.code
|
||||
convert_to_ascii = \
|
||||
self.payment_order_ids[0].mode.convert_to_ascii
|
||||
self.ensure_one()
|
||||
if (
|
||||
self.payment_mode_id.payment_method_id.code !=
|
||||
'sepa_credit_transfer'):
|
||||
return super(AccountPaymentOrder, self).generate_payment_file()
|
||||
|
||||
pain_flavor = self.payment_mode_id.payment_method_id.pain_version
|
||||
if not pain_flavor:
|
||||
pain_flavor = 'pain.001.001.03'
|
||||
if pain_flavor == 'pain.001.001.02':
|
||||
bic_xml_tag = 'BIC'
|
||||
name_maxsize = 70
|
||||
@@ -94,24 +55,19 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
name_maxsize = 70
|
||||
root_xml_tag = 'CstmrCdtTrfInitn'
|
||||
else:
|
||||
raise Warning(
|
||||
_("Payment Type Code '%s' is not supported. The only "
|
||||
"Payment Type Codes supported for SEPA Credit Transfers "
|
||||
"are 'pain.001.001.02', 'pain.001.001.03', "
|
||||
"'pain.001.001.04', 'pain.001.001.05'"
|
||||
" and 'pain.001.003.03'.") %
|
||||
pain_flavor)
|
||||
raise UserError(
|
||||
_("PAIN version '%s' is not supported.") % pain_flavor)
|
||||
xsd_file = self.payment_mode_id.payment_method_id.get_xsd_file_path()
|
||||
gen_args = {
|
||||
'bic_xml_tag': bic_xml_tag,
|
||||
'name_maxsize': name_maxsize,
|
||||
'convert_to_ascii': convert_to_ascii,
|
||||
'convert_to_ascii': self.payment_mode_id.convert_to_ascii,
|
||||
'payment_method': 'TRF',
|
||||
'file_prefix': 'sct_',
|
||||
'pain_flavor': pain_flavor,
|
||||
'pain_xsd_file':
|
||||
'account_banking_sepa_credit_transfer/data/%s.xsd'
|
||||
% pain_flavor,
|
||||
'pain_xsd_file': xsd_file,
|
||||
}
|
||||
# TODO: make it inheritable
|
||||
pain_ns = {
|
||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,
|
||||
@@ -128,30 +84,27 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 = \
|
||||
self.generate_group_header_block(pain_root, gen_args)
|
||||
transactions_count_1_6 = 0
|
||||
total_amount = 0.0
|
||||
amount_control_sum_1_7 = 0.0
|
||||
lines_per_group = {}
|
||||
# key = (requested_date, priority)
|
||||
# values = list of lines as object
|
||||
for payment_order in self.payment_order_ids:
|
||||
total_amount = total_amount + payment_order.total
|
||||
for line in payment_order.bank_line_ids:
|
||||
priority = line.priority
|
||||
# The field line.date is the requested payment date
|
||||
# taking into account the 'date_prefered' setting
|
||||
# cf account_banking_payment_export/models/account_payment.py
|
||||
# in the inherit of action_open()
|
||||
key = (line.date, priority)
|
||||
if key in lines_per_group:
|
||||
lines_per_group[key].append(line)
|
||||
else:
|
||||
lines_per_group[key] = [line]
|
||||
for line in self.bank_line_ids:
|
||||
priority = line.priority
|
||||
# The field line.date is the requested payment date
|
||||
# taking into account the 'date_prefered' setting
|
||||
# cf account_banking_payment_export/models/account_payment.py
|
||||
# in the inherit of action_open()
|
||||
key = (line.date, priority)
|
||||
if key in lines_per_group:
|
||||
lines_per_group[key].append(line)
|
||||
else:
|
||||
lines_per_group[key] = [line]
|
||||
for (requested_date, priority), lines in lines_per_group.items():
|
||||
# B. Payment info
|
||||
payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \
|
||||
self.generate_start_payment_info_block(
|
||||
pain_root,
|
||||
"self.payment_order_ids[0].reference + '-' "
|
||||
"self.name + '-' "
|
||||
"+ requested_date.replace('-', '') + '-' + priority",
|
||||
priority, False, False, requested_date, {
|
||||
'self': self,
|
||||
@@ -160,15 +113,17 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
}, gen_args)
|
||||
self.generate_party_block(
|
||||
payment_info_2_0, 'Dbtr', 'B',
|
||||
'self.payment_order_ids[0].mode.bank_id.partner_id.'
|
||||
'name',
|
||||
'self.payment_order_ids[0].mode.bank_id.acc_number',
|
||||
'self.payment_order_ids[0].mode.bank_id.bank.bic or '
|
||||
'self.payment_order_ids[0].mode.bank_id.bank_bic',
|
||||
'self.company_partner_bank_id.partner_id.name',
|
||||
'self.company_partner_bank_id.sanitized_acc_number',
|
||||
'self.company_partner_bank_id.bank_bic',
|
||||
{'self': self},
|
||||
gen_args)
|
||||
charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
|
||||
charge_bearer_2_24.text = self.charge_bearer
|
||||
if self.sepa:
|
||||
charge_bearer = 'SLEV'
|
||||
else:
|
||||
charge_bearer = self.charge_bearer
|
||||
charge_bearer_2_24.text = charge_bearer
|
||||
transactions_count_2_4 = 0
|
||||
amount_control_sum_2_5 = 0.0
|
||||
for line in lines:
|
||||
@@ -185,7 +140,7 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
'End to End Identification', 'line.name',
|
||||
{'line': line}, 35, gen_args=gen_args)
|
||||
currency_name = self._prepare_field(
|
||||
'Currency Code', 'line.currency.name',
|
||||
'Currency Code', 'line.currency_id.name',
|
||||
{'line': line}, 3, gen_args=gen_args)
|
||||
amount_2_42 = etree.SubElement(
|
||||
credit_transfer_transaction_info_2_27, 'Amt')
|
||||
@@ -194,16 +149,16 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
instructed_amount_2_43.text = '%.2f' % line.amount_currency
|
||||
amount_control_sum_1_7 += line.amount_currency
|
||||
amount_control_sum_2_5 += line.amount_currency
|
||||
if not line.bank_id:
|
||||
raise Warning(
|
||||
if not line.partner_bank_id:
|
||||
raise UserError(
|
||||
_("Bank account is missing on the bank payment line "
|
||||
"of partner '%s' (reference '%s').")
|
||||
% (line.partner_id.name, line.name))
|
||||
self.generate_party_block(
|
||||
credit_transfer_transaction_info_2_27, 'Cdtr',
|
||||
'C', 'line.partner_id.name', 'line.bank_id.acc_number',
|
||||
'line.bank_id.bank.bic or '
|
||||
'line.bank_id.bank_bic', {'line': line}, gen_args)
|
||||
'C', 'line.partner_id.name',
|
||||
'line.partner_bank_id.sanitized_acc_number',
|
||||
'line.partner_bank_id.bank_bic', {'line': line}, gen_args)
|
||||
self.generate_remittance_info_block(
|
||||
credit_transfer_transaction_info_2_27, line, gen_args)
|
||||
if pain_flavor in pain_03_to_05:
|
||||
@@ -215,24 +170,4 @@ class BankingExportSepaWizard(models.TransientModel):
|
||||
else:
|
||||
nb_of_transactions_1_6.text = unicode(transactions_count_1_6)
|
||||
control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
|
||||
return self.finalize_sepa_file_creation(
|
||||
xml_root, total_amount, transactions_count_1_6, gen_args)
|
||||
|
||||
@api.multi
|
||||
def save_sepa(self):
|
||||
"""Save the SEPA file: send the done signal to all payment
|
||||
orders in the file. With the default workflow, they will
|
||||
transition to 'done', while with the advanced workflow in
|
||||
account_banking_payment they will transition to 'sent' waiting
|
||||
reconciliation.
|
||||
"""
|
||||
for order in self.payment_order_ids:
|
||||
workflow.trg_validate(
|
||||
self._uid, 'payment.order', order.id, 'done', self._cr)
|
||||
self.env['ir.attachment'].create({
|
||||
'res_model': 'payment.order',
|
||||
'res_id': order.id,
|
||||
'name': self.filename,
|
||||
'datas': self.file,
|
||||
})
|
||||
return True
|
||||
return self.finalize_sepa_file_creation(xml_root, gen_args)
|
||||
@@ -1,16 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models
|
||||
|
||||
|
||||
class PaymentMode(models.Model):
|
||||
_inherit = 'payment.mode'
|
||||
|
||||
def _sepa_type_get(self):
|
||||
res = super(PaymentMode, self)._sepa_type_get()
|
||||
if not res:
|
||||
if self.type.code and self.type.code.startswith('pain.001'):
|
||||
res = 'sepa_credit_transfer'
|
||||
return res
|
||||
@@ -1,5 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2010-2013 Akretion (www.akretion.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import export_sepa
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010-2015 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="banking_export_sepa_wizard_view" model="ir.ui.view">
|
||||
<field name="name">banking.export.sepa.wizard.view</field>
|
||||
<field name="model">banking.export.sepa.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="SEPA File Generation">
|
||||
<field name="state" invisible="True"/>
|
||||
<group states="create">
|
||||
<field name="batch_booking" />
|
||||
<field name="charge_bearer" />
|
||||
</group>
|
||||
<group states="finish">
|
||||
<field name="total_amount" />
|
||||
<field name="nb_transactions" />
|
||||
<field name="file" filename="filename" />
|
||||
<field name="filename" invisible="True"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Generate" name="create_sepa" type="object" class="oe_highlight" states="create"/>
|
||||
<button string="Validate" name="save_sepa" type="object" class="oe_highlight" states="finish"/>
|
||||
<button string="Cancel" special="cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013 Akretion (www.akretion.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013-2015 Akretion (www.akretion.com)
|
||||
# © 2013-2016 Akretion (www.akretion.com)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
'name': 'Account Banking SEPA Direct Debit',
|
||||
'summary': 'Create SEPA files for Direct Debit',
|
||||
'version': '8.0.0.5.0',
|
||||
'version': '9.0.1.0.0',
|
||||
'license': 'AGPL-3',
|
||||
'author': "Akretion, "
|
||||
"Serv. Tecnol. Avanzados - Pedro M. Baeza, "
|
||||
@@ -16,22 +16,19 @@
|
||||
'website': 'https://github.com/OCA/bank-payment',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_direct_debit',
|
||||
'account_banking_pain_base',
|
||||
'account_banking_mandate',
|
||||
],
|
||||
'data': [
|
||||
'views/account_banking_mandate_view.xml',
|
||||
'views/res_company_view.xml',
|
||||
'views/payment_mode_view.xml',
|
||||
'wizard/export_sdd_view.xml',
|
||||
'views/account_payment_mode.xml',
|
||||
'data/mandate_expire_cron.xml',
|
||||
'data/payment_type_sdd.xml',
|
||||
'data/account_payment_method.xml',
|
||||
'data/report_paperformat.xml',
|
||||
'reports/sepa_direct_debit_mandate.xml',
|
||||
'views/report_sepa_direct_debit_mandate.xml',
|
||||
'security/original_mandate_required_security.xml',
|
||||
],
|
||||
'demo': ['demo/sepa_direct_debit_demo.xml'],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="0">
|
||||
|
||||
|
||||
<record id="sepa_direct_debit" model="account.payment.method">
|
||||
<field name="name">SEPA Direct Debit for customers</field>
|
||||
<field name="code">sepa_direct_debit</field>
|
||||
<field name="payment_type">inbound</field>
|
||||
<field name="pain_version">pain.008.001.02</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com/)
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
614
account_banking_sepa_direct_debit/data/pain.008.003.02.xsd
Normal file
614
account_banking_sepa_direct_debit/data/pain.008.003.02.xsd
Normal file
@@ -0,0 +1,614 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Mit XMLSpy v2008 rel. 2 (http://www.altova.com) von Wenzel (SIZ Bonn) bearbeitet -->
|
||||
<!-- Version gemäß DFÜ-Abkommen Anlage 3, Version 2.7, gültig ab November 2013 mit Umsetzung von IBAN Only gemäß EPC SDD Core IG 7.0 bzw. SDD B2B IG 5.0 , zudem Einbau der COR1-Option durch Erweiterung Local Instrument und Erweiterung Service Level auf Externe Codeliste-->
|
||||
<!-- Mit XMLSpy v2008 rel. 2 sp2 (http://www.altova.com) am 29.11.2012 von der SIZ GmbH bearbeitet -->
|
||||
<xs:schema xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:iso:std:iso:20022:tech:xsd:pain.008.003.02" elementFormDefault="qualified">
|
||||
<xs:element name="Document" type="Document"/>
|
||||
<xs:complexType name="AccountIdentificationSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="IBAN" type="IBAN2007Identifier"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:minInclusive value="0.01"/>
|
||||
<xs:maxInclusive value="999999999.99"/>
|
||||
<xs:fractionDigits value="2"/>
|
||||
<xs:totalDigits value="11"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="ActiveOrHistoricCurrencyAndAmountSEPA">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="ActiveOrHistoricCurrencyAndAmount_SimpleTypeSEPA">
|
||||
<xs:attribute name="Ccy" type="ActiveOrHistoricCurrencyCodeEUR" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="ActiveOrHistoricCurrencyCodeEUR">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="EUR"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ActiveOrHistoricCurrencyCode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[A-Z]{3,3}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="AmendmentInformationDetailsSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="OrgnlMndtId" type="RestrictedIdentificationSEPA2" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Mandatory if changes occur in ‘Mandate Identification’, otherwise not to be used.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="OrgnlCdtrSchmeId" type="PartyIdentificationSEPA4" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Mandatory if changes occur in 'Creditor Scheme Identification', otherwise not to be used.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="OrgnlDbtrAcct" type="CashAccountSEPA2" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>To be used only for changes of accounts within the same bank.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="OrgnlDbtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA2" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>To use 'Identification’ under 'Other' under 'Financial Institution Identifier with code ‘SMNDA’ to indicate same mandate with new Debtor Agent. To be used with the ‘FRST’ indicator in the ‘Sequence Type’.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="AnyBICIdentifier">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="BICIdentifier">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="BatchBookingIndicator">
|
||||
<xs:restriction base="xs:boolean"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA3">
|
||||
<xs:sequence>
|
||||
<xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA3"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="BranchAndFinancialInstitutionIdentificationSEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="FinInstnId" type="FinancialInstitutionIdentificationSEPA2"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CashAccountSEPA1">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="AccountIdentificationSEPA"/>
|
||||
<xs:element name="Ccy" type="ActiveOrHistoricCurrencyCode" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CashAccountSEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="AccountIdentificationSEPA"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CategoryPurposeSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Cd" type="ExternalCategoryPurpose1Code"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="ChargeBearerTypeSEPACode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SLEV"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="CountryCode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[A-Z]{2,2}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="CreditorReferenceInformationSEPA1">
|
||||
<xs:sequence>
|
||||
<xs:element name="Tp" type="CreditorReferenceTypeSEPA"/>
|
||||
<xs:element name="Ref" type="Max35Text">
|
||||
<xs:annotation>
|
||||
<xs:documentation>If a Creditor Reference contains a check digit, the receiving bank is not required to validate this.
|
||||
If the receiving bank validates the check digit and if this validation fails, the bank may continue its processing and send the transaction to the next party in the chain.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CreditorReferenceTypeSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="CdOrPrtry" type="CreditorReferenceTypeCodeSEPA"/>
|
||||
<xs:element name="Issr" type="Max35Text" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CreditorReferenceTypeCodeSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Cd" type="DocumentType3CodeSEPA"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CustomerDirectDebitInitiationV02">
|
||||
<xs:sequence>
|
||||
<xs:element name="GrpHdr" type="GroupHeaderSDD"/>
|
||||
<xs:element name="PmtInf" type="PaymentInstructionInformationSDD" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DateAndPlaceOfBirth">
|
||||
<xs:sequence>
|
||||
<xs:element name="BirthDt" type="ISODate"/>
|
||||
<xs:element name="PrvcOfBirth" type="Max35Text" minOccurs="0"/>
|
||||
<xs:element name="CityOfBirth" type="Max35Text"/>
|
||||
<xs:element name="CtryOfBirth" type="CountryCode"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="DecimalNumber">
|
||||
<xs:restriction base="xs:decimal">
|
||||
<xs:fractionDigits value="17"/>
|
||||
<xs:totalDigits value="18"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="DirectDebitTransactionSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="MndtRltdInf" type="MandateRelatedInformationSDD"/>
|
||||
<xs:element name="CdtrSchmeId" type="PartyIdentificationSEPA3" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>It is recommended that all transactions within the same ‘Payment Information’ block have the same ‘Creditor Scheme Identification’.
|
||||
This data element must be present at either ‘Payment Information’ or ‘Direct Debit
|
||||
Transaction’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DirectDebitTransactionInformationSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="PmtId" type="PaymentIdentificationSEPA"/>
|
||||
<xs:element name="InstdAmt" type="ActiveOrHistoricCurrencyAndAmountSEPA"/>
|
||||
<xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="DrctDbtTx" type="DirectDebitTransactionSDD"/>
|
||||
<xs:element name="UltmtCdtr" type="PartyIdentificationSEPA1" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="DbtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA3"/>
|
||||
<xs:element name="Dbtr" type="PartyIdentificationSEPA2"/>
|
||||
<xs:element name="DbtrAcct" type="CashAccountSEPA2"/>
|
||||
<xs:element name="UltmtDbtr" type="PartyIdentificationSEPA1" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Mandatory if provided by the debtor in the mandate.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Purp" type="PurposeSEPA" minOccurs="0"/>
|
||||
<xs:element name="RmtInf" type="RemittanceInformationSEPA1Choice" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="Document">
|
||||
<xs:sequence>
|
||||
<xs:element name="CstmrDrctDbtInitn" type="CustomerDirectDebitInitiationV02"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="DocumentType3CodeSEPA">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SCOR"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalCategoryPurpose1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalLocalInstrument1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="35"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalOrganisationIdentification1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalPersonIdentification1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalPurpose1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ExternalServiceLevel1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="FinancialInstitutionIdentificationSEPA3">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="BIC" type="BICIdentifier"/>
|
||||
<xs:element name="Othr" type="OthrIdentification"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="OthrIdentification">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="OthrIdentificationCode"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="OthrIdentificationCode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="NOTPROVIDED"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="FinancialInstitutionIdentificationSEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="Othr" type="RestrictedFinancialIdentificationSEPA"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="RestrictedFinancialIdentificationSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="RestrictedSMNDACode"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="RestrictedSMNDACode">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SMNDA"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="GenericOrganisationIdentification1">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="Max35Text"/>
|
||||
<xs:element name="SchmeNm" type="OrganisationIdentificationSchemeName1Choice" minOccurs="0"/>
|
||||
<xs:element name="Issr" type="Max35Text" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="GenericPersonIdentification1">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="Max35Text"/>
|
||||
<xs:element name="SchmeNm" type="PersonIdentificationSchemeName1Choice" minOccurs="0"/>
|
||||
<xs:element name="Issr" type="Max35Text" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="RestrictedPersonIdentificationSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="RestrictedPersonIdentifierSEPA"/>
|
||||
<xs:element name="SchmeNm" type="RestrictedPersonIdentificationSchemeNameSEPA"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="RestrictedPersonIdentifierSEPA">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[a-zA-Z]{2,2}[0-9]{2,2}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){3,3}([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,28}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="GroupHeaderSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="MsgId" type="RestrictedIdentificationSEPA1"/>
|
||||
<xs:element name="CreDtTm" type="ISODateTime"/>
|
||||
<xs:element name="NbOfTxs" type="Max15NumericText"/>
|
||||
<xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
|
||||
<xs:element name="InitgPty" type="PartyIdentificationSEPA1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="IBAN2007Identifier">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ISODate">
|
||||
<xs:restriction base="xs:date"/>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="ISODateTime">
|
||||
<xs:restriction base="xs:dateTime"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="LocalInstrumentSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Cd" type="ExternalLocalInstrument1Code"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="MandateRelatedInformationSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="MndtId" type="RestrictedIdentificationSEPA2"/>
|
||||
<xs:element name="DtOfSgntr" type="ISODate"/>
|
||||
<xs:element name="AmdmntInd" type="TrueFalseIndicator" minOccurs="0"/>
|
||||
<xs:element name="AmdmntInfDtls" type="AmendmentInformationDetailsSDD" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Mandatory if 'Amendment Indicator' is 'TRUE'
|
||||
The reason code from the Rulebook is indicated using one of the following message subelements.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="ElctrncSgntr" type="Max1025Text" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="Max1025Text">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="1025"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Max140Text">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="140"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Max15NumericText">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="[0-9]{1,15}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Max35Text">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="35"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="Max70Text">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="70"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="OrganisationIdentificationSEPAChoice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="BICOrBEI" type="AnyBICIdentifier"/>
|
||||
<xs:element name="Othr" type="GenericOrganisationIdentification1"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="OrganisationIdentificationSchemeName1Choice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="Cd" type="ExternalOrganisationIdentification1Code"/>
|
||||
<xs:element name="Prtry" type="Max35Text"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartySEPAChoice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="OrgId" type="OrganisationIdentificationSEPAChoice">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Either ‘BIC or BEI’ or one
|
||||
occurrence of ‘Other’ is allowed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="PrvtId" type="PersonIdentificationSEPA1Choice">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Either ‘Date and Place of Birth’ or one occurrence of ‘Other’ is allowed</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartySEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="PrvtId" type="PersonIdentificationSEPA2">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Private Identification is used to identify either an organisation or a private
|
||||
person.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartyIdentificationSEPA1">
|
||||
<xs:sequence>
|
||||
<xs:element name="Nm" type="Max70Text" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartyIdentificationSEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="Nm" type="Max70Text">
|
||||
<xs:annotation>
|
||||
<xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="PstlAdr" type="PostalAddressSEPA" minOccurs="0"/>
|
||||
<xs:element name="Id" type="PartySEPAChoice" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartyIdentificationSEPA3">
|
||||
<xs:sequence>
|
||||
<xs:element name="Id" type="PartySEPA2"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartyIdentificationSEPA4">
|
||||
<xs:sequence>
|
||||
<xs:element name="Nm" type="Max70Text" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>If present the new’ Name’ must be specified under ‘Creditor’. ‘Name’ is limited to 70 characters in length.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="Id" type="PartySEPA2" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PartyIdentificationSEPA5">
|
||||
<xs:sequence>
|
||||
<xs:element name="Nm" type="Max70Text">
|
||||
<xs:annotation>
|
||||
<xs:documentation>‘Name’ is limited to 70 characters in length.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="PstlAdr" type="PostalAddressSEPA" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PaymentIdentificationSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="InstrId" type="RestrictedIdentificationSEPA1" minOccurs="0"/>
|
||||
<xs:element name="EndToEndId" type="RestrictedIdentificationSEPA1"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PaymentInstructionInformationSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="PmtInfId" type="RestrictedIdentificationSEPA1"/>
|
||||
<xs:element name="PmtMtd" type="PaymentMethod2Code"/>
|
||||
<xs:element name="BtchBookg" type="BatchBookingIndicator" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>If present and contains ‘true’, batch booking is requested. If present and contains ‘false’, booking per transaction is requested. If element is not present, pre-agreed customer-to-bank conditions apply.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="NbOfTxs" type="Max15NumericText" minOccurs="0"/>
|
||||
<xs:element name="CtrlSum" type="DecimalNumber" minOccurs="0"/>
|
||||
<xs:element name="PmtTpInf" type="PaymentTypeInformationSDD"/>
|
||||
<xs:element name="ReqdColltnDt" type="ISODate"/>
|
||||
<xs:element name="Cdtr" type="PartyIdentificationSEPA5"/>
|
||||
<xs:element name="CdtrAcct" type="CashAccountSEPA1"/>
|
||||
<xs:element name="CdtrAgt" type="BranchAndFinancialInstitutionIdentificationSEPA3"/>
|
||||
<xs:element name="UltmtCdtr" type="PartyIdentificationSEPA1" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="ChrgBr" type="ChargeBearerTypeSEPACode" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>It is recommended that this element be specified at ‘Payment Information’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="CdtrSchmeId" type="PartyIdentificationSEPA3" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>It is recommended that all transactions within the same ‘Payment Information’ block have the same ‘Creditor Scheme Identification’.
|
||||
This data element must be present at either ‘Payment Information’ or ‘Direct Debit
|
||||
Transaction’ level.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="DrctDbtTxInf" type="DirectDebitTransactionInformationSDD" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="PaymentMethod2Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="DD"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="PaymentTypeInformationSDD">
|
||||
<xs:sequence>
|
||||
<xs:element name="SvcLvl" type="ServiceLevelSEPA"/>
|
||||
<xs:element name="LclInstrm" type="LocalInstrumentSEPA">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Only ‘B2B’, 'CORE' or 'COR1' is allowed. The mixing of different Local Instrument values is not allowed in the same message.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="SeqTp" type="SequenceType1Code">
|
||||
<xs:annotation>
|
||||
<xs:documentation>If 'Amendment Indicator' is 'true' and 'Original Debtor Agent' is set to 'SMNDA' this message element must indicate 'FRST'</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
<xs:element name="CtgyPurp" type="CategoryPurposeSEPA" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Depending on the agreement between the Creditor and the Creditor Bank, ‘Category Purpose’ may be forwarded to the Debtor Bank.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PersonIdentificationSEPA1Choice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="DtAndPlcOfBirth" type="DateAndPlaceOfBirth"/>
|
||||
<xs:element name="Othr" type="GenericPersonIdentification1"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PersonIdentificationSEPA2">
|
||||
<xs:sequence>
|
||||
<xs:element name="Othr" type="RestrictedPersonIdentificationSEPA">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Only one occurrence of ‘Other’ is allowed, and no other sub-elements are allowed.
|
||||
Identification must be used with an identifier described in General Message Element Specifications, Chapter 1.5.2 of the Implementation Guide.
|
||||
Scheme Name’ under ‘Other’ must specify ‘SEPA’ under ‘Proprietary</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PersonIdentificationSchemeName1Choice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="Cd" type="ExternalPersonIdentification1Code"/>
|
||||
<xs:element name="Prtry" type="Max35Text"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="RestrictedPersonIdentificationSchemeNameSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Prtry" type="IdentificationSchemeNameSEPA"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="IdentificationSchemeNameSEPA">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="SEPA"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="PostalAddressSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Ctry" type="CountryCode" minOccurs="0"/>
|
||||
<xs:element name="AdrLine" type="Max70Text" minOccurs="0" maxOccurs="2"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PurposeSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Cd" type="ExternalPurpose1Code">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Only codes from the ISO 20022 ExternalPurposeCode list are allowed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="RemittanceInformationSEPA1Choice">
|
||||
<xs:sequence>
|
||||
<xs:choice>
|
||||
<xs:element name="Ustrd" type="Max140Text"/>
|
||||
<xs:element name="Strd" type="StructuredRemittanceInformationSEPA1"/>
|
||||
</xs:choice>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="SequenceType1Code">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="FRST"/>
|
||||
<xs:enumeration value="RCUR"/>
|
||||
<xs:enumeration value="FNAL"/>
|
||||
<xs:enumeration value="OOFF"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="ServiceLevelSEPA">
|
||||
<xs:sequence>
|
||||
<xs:element name="Cd" type="ExternalServiceLevel1Code"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="StructuredRemittanceInformationSEPA1">
|
||||
<xs:sequence>
|
||||
<xs:element name="CdtrRefInf" type="CreditorReferenceInformationSEPA1" minOccurs="0">
|
||||
<xs:annotation>
|
||||
<xs:documentation>When present, the receiving bank is not obliged to validate the reference information.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="TrueFalseIndicator">
|
||||
<xs:restriction base="xs:boolean"/>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="RestrictedIdentificationSEPA1">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|'| ]){1,35}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="RestrictedIdentificationSEPA2">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:pattern value="([A-Za-z0-9]|[\+|\?|/|\-|:|\(|\)|\.|,|']){1,35}"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:schema>
|
||||
@@ -1,35 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
<record id="export_sdd_008_001_02" model="payment.mode.type">
|
||||
<field name="name">SEPA Direct Debit v02 (recommended)</field>
|
||||
<field name="code">pain.008.001.02</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sdd_wizard"/>
|
||||
<field name="payment_order_type">debit</field>
|
||||
</record>
|
||||
|
||||
<record id="export_sdd_008_001_03" model="payment.mode.type">
|
||||
<field name="name">SEPA Direct Debit v03</field>
|
||||
<field name="code">pain.008.001.03</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sdd_wizard"/>
|
||||
<field name="payment_order_type">debit</field>
|
||||
</record>
|
||||
|
||||
<record id="export_sdd_008_001_04" model="payment.mode.type">
|
||||
<field name="name">SEPA Direct Debit v04</field>
|
||||
<field name="code">pain.008.001.04</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base_iban.bank_iban')])]" />
|
||||
<field name="ir_model_id" ref="model_banking_export_sdd_wizard"/>
|
||||
<field name="payment_order_type">debit</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -3,13 +3,11 @@
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="sepa_direct_debit_mode" model="payment.mode">
|
||||
<field name="name">SEPA Direct Debit La Banque Postale</field>
|
||||
<field name="journal" ref="account.bank_journal"/>
|
||||
<field name="bank_id" ref="account_banking_payment_export.main_company_iban"/>
|
||||
<record id="payment_mode_inbound_sepa_dd1" model="account.payment.mode">
|
||||
<field name="name">SEPA Direct Debit of customers</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="type" ref="export_sdd_008_001_02"/>
|
||||
<field name="purchase_ok" eval="False"/>
|
||||
<field name="bank_account_link">variable</field>
|
||||
<field name="payment_method_id" ref="sepa_direct_debit"/>
|
||||
<field name="default_journal_ids" search="[('type', 'in', ('sale', 'sale_refund'))]"/>
|
||||
</record>
|
||||
|
||||
@@ -18,7 +16,7 @@
|
||||
</record>
|
||||
|
||||
<record id="res_partner_12_mandate" model="account.banking.mandate">
|
||||
<field name="partner_bank_id" ref="account_banking_payment_export.res_partner_12_iban"/>
|
||||
<field name="partner_bank_id" ref="account_payment_mode.res_partner_12_iban"/>
|
||||
<field name="format">sepa</field>
|
||||
<field name="type">recurrent</field>
|
||||
<field name="recurrent_sequence_type">first</field>
|
||||
@@ -27,7 +25,7 @@
|
||||
</record>
|
||||
|
||||
<record id="res_partner_2_mandate" model="account.banking.mandate">
|
||||
<field name="partner_bank_id" ref="account_banking_payment_export.res_partner_2_iban"/>
|
||||
<field name="partner_bank_id" ref="account_payment_mode.res_partner_2_iban"/>
|
||||
<field name="format">sepa</field>
|
||||
<field name="type">recurrent</field>
|
||||
<field name="recurrent_sequence_type">first</field>
|
||||
|
||||
@@ -3,4 +3,6 @@
|
||||
from . import res_company
|
||||
from . import account_banking_mandate
|
||||
from . import bank_payment_line
|
||||
from . import payment_mode
|
||||
from . import account_payment_mode
|
||||
from . import account_payment_method
|
||||
from . import account_payment_order
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2013-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
@@ -16,29 +16,13 @@ logger = logging.getLogger(__name__)
|
||||
class AccountBankingMandate(models.Model):
|
||||
"""SEPA Direct Debit Mandate"""
|
||||
_inherit = 'account.banking.mandate'
|
||||
_track = {
|
||||
'recurrent_sequence_type': {
|
||||
'account_banking_sepa_direct_debit.recurrent_sequence_type_first':
|
||||
lambda self, cr, uid, obj, ctx=None:
|
||||
obj['recurrent_sequence_type'] == 'first',
|
||||
'account_banking_sepa_direct_debit.'
|
||||
'recurrent_sequence_type_recurring':
|
||||
lambda self, cr, uid, obj, ctx=None:
|
||||
obj['recurrent_sequence_type'] == 'recurring',
|
||||
'account_banking_sepa_direct_debit.recurrent_sequence_type_final':
|
||||
lambda self, cr, uid, obj, ctx=None:
|
||||
obj['recurrent_sequence_type'] == 'final',
|
||||
}
|
||||
}
|
||||
|
||||
format = fields.Selection(
|
||||
selection_add=[('sepa', _('Sepa Mandate'))],
|
||||
default='sepa',
|
||||
)
|
||||
selection_add=[('sepa', 'Sepa Mandate')], default='sepa')
|
||||
type = fields.Selection([('recurrent', 'Recurrent'),
|
||||
('oneoff', 'One-Off')],
|
||||
string='Type of Mandate',
|
||||
track_visibility='always')
|
||||
track_visibility='onchange')
|
||||
recurrent_sequence_type = fields.Selection(
|
||||
[('first', 'First'),
|
||||
('recurring', 'Recurring'),
|
||||
@@ -46,24 +30,10 @@ class AccountBankingMandate(models.Model):
|
||||
string='Sequence Type for Next Debit', track_visibility='onchange',
|
||||
help="This field is only used for Recurrent mandates, not for "
|
||||
"One-Off mandates.", default="first")
|
||||
sepa_migrated = fields.Boolean(
|
||||
string='Migrated to SEPA', track_visibility='onchange',
|
||||
help="If this field is not active, the mandate section of the next "
|
||||
"direct debit file that include this mandate will contain the "
|
||||
"'Original Mandate Identification' and the 'Original Creditor "
|
||||
"Scheme Identification'. This is required in a few countries "
|
||||
"(Belgium for instance), but not in all countries. If this is "
|
||||
"not required in your country, you should keep this field always "
|
||||
"active.", default=True)
|
||||
original_mandate_identification = fields.Char(
|
||||
string='Original Mandate Identification', track_visibility='onchange',
|
||||
size=35,
|
||||
help="When the field 'Migrated to SEPA' is not active, this field "
|
||||
"will be used as the Original Mandate Identification in the "
|
||||
"Direct Debit file.")
|
||||
scheme = fields.Selection([('CORE', 'Basic (CORE)'),
|
||||
('B2B', 'Enterprise (B2B)')],
|
||||
string='Scheme', default="CORE")
|
||||
scheme = fields.Selection([
|
||||
('CORE', 'Basic (CORE)'),
|
||||
('B2B', 'Enterprise (B2B)')],
|
||||
string='Scheme', default="CORE", track_visibility='onchange')
|
||||
unique_mandate_reference = fields.Char(size=35) # cf ISO 20022
|
||||
|
||||
@api.multi
|
||||
@@ -76,30 +46,6 @@ class AccountBankingMandate(models.Model):
|
||||
_("The recurrent mandate '%s' must have a sequence type.")
|
||||
% mandate.unique_mandate_reference)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('type', 'recurrent_sequence_type', 'sepa_migrated')
|
||||
def _check_migrated_to_sepa(self):
|
||||
for mandate in self:
|
||||
if (mandate.type == 'recurrent' and not mandate.sepa_migrated and
|
||||
mandate.recurrent_sequence_type != 'first'):
|
||||
raise exceptions.Warning(
|
||||
_("The recurrent mandate '%s' which is not marked as "
|
||||
"'Migrated to SEPA' must have its recurrent sequence "
|
||||
"type set to 'First'.")
|
||||
% mandate.unique_mandate_reference)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('type', 'original_mandate_identification', 'sepa_migrated')
|
||||
def _check_original_mandate_identification(self):
|
||||
for mandate in self:
|
||||
if (mandate.type == 'recurrent' and not mandate.sepa_migrated and
|
||||
not mandate.original_mandate_identification):
|
||||
raise exceptions.Warning(
|
||||
_("You must set the 'Original Mandate Identification' on "
|
||||
"the recurrent mandate '%s' which is not marked as "
|
||||
"'Migrated to SEPA'.")
|
||||
% mandate.unique_mandate_reference)
|
||||
|
||||
@api.multi
|
||||
@api.onchange('partner_bank_id')
|
||||
def mandate_partner_bank_change(self):
|
||||
@@ -137,5 +83,5 @@ class AccountBankingMandate(models.Model):
|
||||
'The following SDD Mandate IDs has been set to expired: %s'
|
||||
% expired_mandates.ids)
|
||||
else:
|
||||
logger.info('0 SDD Mandates must be set to Expired')
|
||||
logger.info('0 SDD Mandates had to be set to Expired')
|
||||
return True
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class AccountPaymentMethod(models.Model):
|
||||
_inherit = 'account.payment.method'
|
||||
|
||||
pain_version = fields.Selection(selection_add=[
|
||||
('pain.008.001.02', 'pain.008.001.02 (recommended)'),
|
||||
('pain.008.001.03', 'pain.008.001.03'),
|
||||
('pain.008.001.04', 'pain.008.001.04'),
|
||||
('pain.008.003.02', 'pain.008.003.02 (used in Germany)'),
|
||||
])
|
||||
|
||||
@api.multi
|
||||
def get_xsd_file_path(self):
|
||||
self.ensure_one()
|
||||
if self.pain_version in [
|
||||
'pain.008.001.02', 'pain.008.001.03', 'pain.008.001.04',
|
||||
'pain.008.003.02']:
|
||||
path = 'account_banking_sepa_direct_debit/data/%s.xsd'\
|
||||
% self.pain_version
|
||||
return path
|
||||
return super(AccountPaymentMethod, self).get_xsd_file_path()
|
||||
@@ -2,12 +2,13 @@
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, exceptions, _
|
||||
from openerp import models, fields, api, _
|
||||
from .common import is_sepa_creditor_identifier_valid
|
||||
from openerp.exceptions import ValidationError
|
||||
|
||||
|
||||
class PaymentMode(models.Model):
|
||||
_inherit = 'payment.mode'
|
||||
class AccountPaymentMode(models.Model):
|
||||
_inherit = 'account.payment.mode'
|
||||
|
||||
sepa_creditor_identifier = fields.Char(
|
||||
string='SEPA Creditor Identifier', size=35,
|
||||
@@ -19,13 +20,9 @@ class PaymentMode(models.Model):
|
||||
"- a 2-digits checkum\n"
|
||||
"- a 3-letters business code\n"
|
||||
"- a country-specific identifier")
|
||||
original_creditor_identifier = fields.Char(
|
||||
string='Original Creditor Identifier', size=70,
|
||||
help="If not defined, Original Creditor Identifier from company "
|
||||
"will be used.")
|
||||
|
||||
def _sepa_type_get(self):
|
||||
res = super(PaymentMode, self)._sepa_type_get()
|
||||
res = super(AccountPaymentMode, self)._sepa_type_get()
|
||||
if not res:
|
||||
if self.type.code and self.type.code.startswith('pain.008'):
|
||||
res = 'sepa_direct_debit'
|
||||
@@ -38,6 +35,6 @@ class PaymentMode(models.Model):
|
||||
if payment_mode.sepa_creditor_identifier:
|
||||
if not is_sepa_creditor_identifier_valid(
|
||||
payment_mode.sepa_creditor_identifier):
|
||||
raise exceptions.Warning(
|
||||
_('Error'),
|
||||
_("Invalid SEPA Creditor Identifier."))
|
||||
raise ValidationError(
|
||||
_("The SEPA Creditor Identifier '%s' is invalid.")
|
||||
% payment_mode.sepa_creditor_identifier)
|
||||
@@ -0,0 +1,298 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import UserError
|
||||
from lxml import etree
|
||||
|
||||
|
||||
class AccountPaymentOrder(models.Model):
|
||||
_inherit = 'account.payment.order'
|
||||
|
||||
def _get_previous_bank(self, payline):
|
||||
previous_bank = False
|
||||
older_lines = self.env['account.payment.line'].search([
|
||||
('mandate_id', '=', payline.mandate_id.id),
|
||||
('partner_bank_id', '!=', payline.partner_bank_id.id)])
|
||||
if older_lines:
|
||||
previous_date = False
|
||||
previous_payline = False
|
||||
for older_line in older_lines:
|
||||
if hasattr(older_line.order_id, 'date_sent'):
|
||||
older_line_date = older_line.order_id.date_sent
|
||||
else:
|
||||
older_line_date = older_line.order_id.date_done
|
||||
if (older_line_date and
|
||||
older_line_date > previous_date):
|
||||
previous_date = older_line_date
|
||||
previous_payline = older_line
|
||||
if previous_payline:
|
||||
previous_bank = previous_payline.partner_bank_id
|
||||
return previous_bank
|
||||
|
||||
@api.multi
|
||||
def generate_payment_file(self):
|
||||
"""Creates the SEPA Direct Debit file. That's the important code !"""
|
||||
self.ensure_one()
|
||||
if (
|
||||
self.payment_mode_id.payment_method_id.code !=
|
||||
'sepa_direct_debit'):
|
||||
return super(AccountPaymentOrder, self).generate_payment_file()
|
||||
pain_flavor = self.payment_mode_id.payment_method_id.pain_version
|
||||
if pain_flavor == 'pain.008.001.02':
|
||||
bic_xml_tag = 'BIC'
|
||||
name_maxsize = 70
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
elif pain_flavor == 'pain.008.003.02':
|
||||
bic_xml_tag = 'BIC'
|
||||
name_maxsize = 70
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
elif pain_flavor == 'pain.008.001.03':
|
||||
bic_xml_tag = 'BICFI'
|
||||
name_maxsize = 140
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
elif pain_flavor == 'pain.008.001.04':
|
||||
bic_xml_tag = 'BICFI'
|
||||
name_maxsize = 140
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
else:
|
||||
raise UserError(
|
||||
_("Payment Type Code '%s' is not supported. The only "
|
||||
"Payment Type Code supported for SEPA Direct Debit are "
|
||||
"'pain.008.001.02', 'pain.008.001.03' and "
|
||||
"'pain.008.001.04'.") % pain_flavor)
|
||||
xsd_file = self.payment_mode_id.payment_method_id.get_xsd_file_path()
|
||||
gen_args = {
|
||||
'bic_xml_tag': bic_xml_tag,
|
||||
'name_maxsize': name_maxsize,
|
||||
'convert_to_ascii': self.payment_mode_id.convert_to_ascii,
|
||||
'payment_method': 'DD',
|
||||
'file_prefix': 'sdd_',
|
||||
'pain_flavor': pain_flavor,
|
||||
'pain_xsd_file': xsd_file,
|
||||
}
|
||||
pain_ns = {
|
||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,
|
||||
}
|
||||
xml_root = etree.Element('Document', nsmap=pain_ns)
|
||||
pain_root = etree.SubElement(xml_root, root_xml_tag)
|
||||
# A. Group header
|
||||
group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 = \
|
||||
self.generate_group_header_block(pain_root, gen_args)
|
||||
transactions_count_1_6 = 0
|
||||
amount_control_sum_1_7 = 0.0
|
||||
lines_per_group = {}
|
||||
# key = (requested_date, priority, sequence type)
|
||||
# value = list of lines as objects
|
||||
for line in self.bank_line_ids:
|
||||
transactions_count_1_6 += 1
|
||||
priority = line.priority
|
||||
# The field line.date is the requested payment date
|
||||
# taking into account the 'date_prefered' setting
|
||||
# cf account_banking_payment_export/models/account_payment.py
|
||||
# in the inherit of action_open()
|
||||
if not line.mandate_id:
|
||||
raise UserError(
|
||||
_("Missing SEPA Direct Debit mandate on the "
|
||||
"bank payment line with partner '%s' "
|
||||
"(reference '%s').")
|
||||
% (line.partner_id.name, line.name))
|
||||
scheme = line.mandate_id.scheme
|
||||
if line.mandate_id.state != 'valid':
|
||||
raise Warning(
|
||||
_("The SEPA Direct Debit mandate with reference '%s' "
|
||||
"for partner '%s' has expired.")
|
||||
% (line.mandate_id.unique_mandate_reference,
|
||||
line.mandate_id.partner_id.name))
|
||||
if line.mandate_id.type == 'oneoff':
|
||||
seq_type = 'OOFF'
|
||||
if line.mandate_id.last_debit_date:
|
||||
raise Warning(
|
||||
_("The mandate with reference '%s' for partner "
|
||||
"'%s' has type set to 'One-Off' and it has a "
|
||||
"last debit date set to '%s', so we can't use "
|
||||
"it.")
|
||||
% (line.mandate_id.unique_mandate_reference,
|
||||
line.mandate_id.partner_id.name,
|
||||
line.mandate_id.last_debit_date))
|
||||
elif line.mandate_id.type == 'recurrent':
|
||||
seq_type_map = {
|
||||
'recurring': 'RCUR',
|
||||
'first': 'FRST',
|
||||
'final': 'FNAL',
|
||||
}
|
||||
seq_type_label = \
|
||||
line.mandate_id.recurrent_sequence_type
|
||||
assert seq_type_label is not False
|
||||
seq_type = seq_type_map[seq_type_label]
|
||||
key = (line.date, priority, seq_type, scheme)
|
||||
if key in lines_per_group:
|
||||
lines_per_group[key].append(line)
|
||||
else:
|
||||
lines_per_group[key] = [line]
|
||||
|
||||
for (requested_date, priority, sequence_type, scheme), lines in \
|
||||
lines_per_group.items():
|
||||
# B. Payment info
|
||||
payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \
|
||||
self.generate_start_payment_info_block(
|
||||
pain_root,
|
||||
"self.name + '-' + "
|
||||
"sequence_type + '-' + requested_date.replace('-', '') "
|
||||
"+ '-' + priority",
|
||||
priority, scheme, sequence_type, requested_date, {
|
||||
'self': self,
|
||||
'sequence_type': sequence_type,
|
||||
'priority': priority,
|
||||
'requested_date': requested_date,
|
||||
}, gen_args)
|
||||
|
||||
self.generate_party_block(
|
||||
payment_info_2_0, 'Cdtr', 'B',
|
||||
'self.company_partner_bank_id.partner_id.name',
|
||||
'self.company_partner_bank_id.sanitized_acc_number',
|
||||
'self.company_partner_bank_id.bank_bic',
|
||||
{'self': self}, gen_args)
|
||||
charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
|
||||
if self.sepa:
|
||||
charge_bearer = 'SLEV'
|
||||
else:
|
||||
charge_bearer = self.charge_bearer
|
||||
charge_bearer_2_24.text = charge_bearer
|
||||
creditor_scheme_identification_2_27 = etree.SubElement(
|
||||
payment_info_2_0, 'CdtrSchmeId')
|
||||
self.generate_creditor_scheme_identification(
|
||||
creditor_scheme_identification_2_27,
|
||||
'self.payment_mode_id.sepa_creditor_identifier or '
|
||||
'self.company_id.sepa_creditor_identifier',
|
||||
'SEPA Creditor Identifier', {'self': self}, 'SEPA', gen_args)
|
||||
transactions_count_2_4 = 0
|
||||
amount_control_sum_2_5 = 0.0
|
||||
for line in lines:
|
||||
transactions_count_2_4 += 1
|
||||
# C. Direct Debit Transaction Info
|
||||
dd_transaction_info_2_28 = etree.SubElement(
|
||||
payment_info_2_0, 'DrctDbtTxInf')
|
||||
payment_identification_2_29 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'PmtId')
|
||||
end2end_identification_2_31 = etree.SubElement(
|
||||
payment_identification_2_29, 'EndToEndId')
|
||||
end2end_identification_2_31.text = self._prepare_field(
|
||||
'End to End Identification', 'line.name',
|
||||
{'line': line}, 35, gen_args=gen_args)
|
||||
currency_name = self._prepare_field(
|
||||
'Currency Code', 'line.currency_id.name',
|
||||
{'line': line}, 3, gen_args=gen_args)
|
||||
instructed_amount_2_44 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'InstdAmt', Ccy=currency_name)
|
||||
instructed_amount_2_44.text = '%.2f' % line.amount_currency
|
||||
amount_control_sum_1_7 += line.amount_currency
|
||||
amount_control_sum_2_5 += line.amount_currency
|
||||
dd_transaction_2_46 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'DrctDbtTx')
|
||||
mandate_related_info_2_47 = etree.SubElement(
|
||||
dd_transaction_2_46, 'MndtRltdInf')
|
||||
mandate_identification_2_48 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'MndtId')
|
||||
mandate_identification_2_48.text = self._prepare_field(
|
||||
'Unique Mandate Reference',
|
||||
'line.mandate_id.unique_mandate_reference',
|
||||
{'line': line}, 35, gen_args=gen_args)
|
||||
mandate_signature_date_2_49 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'DtOfSgntr')
|
||||
mandate_signature_date_2_49.text = self._prepare_field(
|
||||
'Mandate Signature Date',
|
||||
'line.mandate_id.signature_date',
|
||||
{'line': line}, 10, gen_args=gen_args)
|
||||
if sequence_type == 'FRST' and line.mandate_id.last_debit_date:
|
||||
previous_bank = self._get_previous_bank(line)
|
||||
if previous_bank:
|
||||
amendment_indicator_2_50 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'AmdmntInd')
|
||||
amendment_indicator_2_50.text = 'true'
|
||||
amendment_info_details_2_51 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'AmdmntInfDtls')
|
||||
if (
|
||||
previous_bank.bank_bic ==
|
||||
line.partner_bank_id.bank_bic):
|
||||
ori_debtor_account_2_57 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlDbtrAcct')
|
||||
ori_debtor_account_id = etree.SubElement(
|
||||
ori_debtor_account_2_57, 'Id')
|
||||
ori_debtor_account_iban = etree.SubElement(
|
||||
ori_debtor_account_id, 'IBAN')
|
||||
ori_debtor_account_iban.text = self._validate_iban(
|
||||
self._prepare_field(
|
||||
'Original Debtor Account',
|
||||
'previous_bank.sanitized_acc_number',
|
||||
{'previous_bank': previous_bank},
|
||||
gen_args=gen_args))
|
||||
else:
|
||||
ori_debtor_agent_2_58 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlDbtrAgt')
|
||||
ori_debtor_agent_institution = etree.SubElement(
|
||||
ori_debtor_agent_2_58, 'FinInstnId')
|
||||
ori_debtor_agent_bic = etree.SubElement(
|
||||
ori_debtor_agent_institution, bic_xml_tag)
|
||||
ori_debtor_agent_bic.text = self._prepare_field(
|
||||
'Original Debtor Agent',
|
||||
'previous_bank.bank_bic',
|
||||
{'previous_bank': previous_bank},
|
||||
gen_args=gen_args)
|
||||
ori_debtor_agent_other = etree.SubElement(
|
||||
ori_debtor_agent_institution, 'Othr')
|
||||
ori_debtor_agent_other_id = etree.SubElement(
|
||||
ori_debtor_agent_other, 'Id')
|
||||
ori_debtor_agent_other_id.text = 'SMNDA'
|
||||
# SMNDA = Same Mandate New Debtor Agent
|
||||
|
||||
self.generate_party_block(
|
||||
dd_transaction_info_2_28, 'Dbtr', 'C',
|
||||
'line.partner_id.name',
|
||||
'line.partner_bank_id.sanitized_acc_number',
|
||||
'line.partner_bank_id.bank_bic',
|
||||
{'line': line}, gen_args)
|
||||
|
||||
self.generate_remittance_info_block(
|
||||
dd_transaction_info_2_28, line, gen_args)
|
||||
|
||||
nb_of_transactions_2_4.text = unicode(transactions_count_2_4)
|
||||
control_sum_2_5.text = '%.2f' % amount_control_sum_2_5
|
||||
nb_of_transactions_1_6.text = unicode(transactions_count_1_6)
|
||||
control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
|
||||
|
||||
return self.finalize_sepa_file_creation(
|
||||
xml_root, gen_args)
|
||||
|
||||
@api.multi
|
||||
def finalize_sepa_file_creation(self, xml_root, gen_args):
|
||||
"""Save the SEPA Direct Debit file: mark all payments in the file
|
||||
as 'sent'. Write 'last debit date' on mandate and set oneoff
|
||||
mandate to expired.
|
||||
"""
|
||||
abmo = self.env['account.banking.mandate']
|
||||
to_expire_mandates = abmo.browse([])
|
||||
first_mandates = abmo.browse([])
|
||||
all_mandates = abmo.browse([])
|
||||
for bline in self.bank_line_ids:
|
||||
if bline.mandate_id in all_mandates:
|
||||
continue
|
||||
all_mandates += bline.mandate_id
|
||||
if bline.mandate_id.type == 'oneoff':
|
||||
to_expire_mandates += bline.mandate_id
|
||||
elif bline.mandate_id.type == 'recurrent':
|
||||
seq_type = bline.mandate_id.recurrent_sequence_type
|
||||
if seq_type == 'final':
|
||||
to_expire_mandates += bline.mandate_id
|
||||
elif seq_type == 'first':
|
||||
first_mandates += bline.mandate_id
|
||||
all_mandates.write(
|
||||
{'last_debit_date': fields.Date.context_today(self)})
|
||||
to_expire_mandates.write({'state': 'expired'})
|
||||
first_mandates.write({
|
||||
'recurrent_sequence_type': 'recurring',
|
||||
})
|
||||
return super(AccountPaymentOrder, self).finalize_sepa_file_creation(
|
||||
xml_root, gen_args)
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2015 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, api
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013 Akretion (www.akretion.com)
|
||||
# © 2013-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2013 Akretion (www.akretion.com)
|
||||
# © 2013-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# © 2016 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api, exceptions, _
|
||||
from openerp import models, fields, api, _
|
||||
from .common import is_sepa_creditor_identifier_valid
|
||||
from openerp.exceptions import ValidationError
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
@@ -28,6 +29,6 @@ class ResCompany(models.Model):
|
||||
if company.sepa_creditor_identifier:
|
||||
if not is_sepa_creditor_identifier_valid(
|
||||
company.sepa_creditor_identifier):
|
||||
raise exceptions.Warning(
|
||||
_('Error'),
|
||||
_("Invalid SEPA Creditor Identifier."))
|
||||
raise ValidationError(
|
||||
_("The SEPA Creditor Identifier '%s' is invalid.")
|
||||
% company.sepa_creditor_identifier)
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="group_original_mandate_required" model="res.groups">
|
||||
<field name="name">Original Mandate Required (SEPA)</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
@@ -11,7 +11,7 @@
|
||||
<data>
|
||||
|
||||
|
||||
<record id="sdd_mandate_form" model="ir.ui.view">
|
||||
<record id="view_mandate_form" model="ir.ui.view">
|
||||
<field name="name">sdd.mandate.form</field>
|
||||
<field name="model">account.banking.mandate</field>
|
||||
<field name="inherit_id" ref="account_banking_mandate.view_mandate_form"/>
|
||||
@@ -25,14 +25,10 @@
|
||||
<field name="scheme" attrs="{'invisible': [('format', '!=', 'sepa')],
|
||||
'required': [('format', '=', 'sepa')]}"/>
|
||||
</field>
|
||||
<field name="last_debit_date" position="after">
|
||||
<field name="sepa_migrated" groups="account_banking_sepa_direct_debit.group_original_mandate_required"/>
|
||||
<field name="original_mandate_identification" attrs="{'invisible': [('sepa_migrated', '=', True)], 'required': [('sepa_migrated', '=', False)]}" groups="account_banking_sepa_direct_debit.group_original_mandate_required"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sdd_mandate_tree" model="ir.ui.view">
|
||||
<record id="view_mandate_tree" model="ir.ui.view">
|
||||
<field name="name">sdd.mandate.tree</field>
|
||||
<field name="model">account.banking.mandate</field>
|
||||
<field name="inherit_id" ref="account_banking_mandate.view_mandate_tree"/>
|
||||
@@ -45,7 +41,7 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sdd_mandate_search" model="ir.ui.view">
|
||||
<record id="view_mandate_search" model="ir.ui.view">
|
||||
<field name="name">sdd.mandate.search</field>
|
||||
<field name="model">account.banking.mandate</field>
|
||||
<field name="inherit_id" ref="account_banking_mandate.view_mandate_search"/>
|
||||
@@ -66,67 +62,5 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mandate_action" model="ir.actions.act_window">
|
||||
<field name="name">SEPA Direct Debit Mandates</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new SEPA Direct Debit Mandate.
|
||||
</p><p>
|
||||
A SEPA Direct Debit Mandate is a document signed by your customer that gives you the autorization to do one or several direct debits on his bank account.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="account_banking_mandate.mandate_menu"
|
||||
parent="account_payment.menu_main_payment"
|
||||
action="mandate_action"
|
||||
sequence="20"
|
||||
/>
|
||||
|
||||
<record id="sdd_mandate_partner_bank_tree" model="ir.ui.view">
|
||||
<field name="name">sdd.mandate.res.partner.bank.tree</field>
|
||||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="account_banking_mandate.mandate_partner_bank_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="mandate_ids" position="attributes">
|
||||
<attribute name="string">SDD Mandates</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sdd_mandate_partner_form" model="ir.ui.view">
|
||||
<field name="name">sdd.mandate.partner.form</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="account_banking_mandate.mandate_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='bank_ids']/tree/field[@name='mandate_ids']" position="attributes">
|
||||
<attribute name="string">SDD Mandates</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="recurrent_sequence_type_first" model="mail.message.subtype">
|
||||
<field name="name">Sequence Type set to First</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Sequence Type set to First</field>
|
||||
</record>
|
||||
|
||||
<record id="recurrent_sequence_type_recurring" model="mail.message.subtype">
|
||||
<field name="name">Sequence Type set to Recurring</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Sequence Type set to Recurring</field>
|
||||
</record>
|
||||
|
||||
<record id="recurrent_sequence_type_final" model="mail.message.subtype">
|
||||
<field name="name">Sequence Type set to Final</field>
|
||||
<field name="res_model">account.banking.mandate</field>
|
||||
<field name="default" eval="False"/>
|
||||
<field name="description">Sequence Type set to Final</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- © 2015 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="account_payment_mode_form" model="ir.ui.view">
|
||||
<field name="name">Add SEPA identifiers on payment mode form</field>
|
||||
<field name="model">account.payment.mode</field>
|
||||
<field name="inherit_id" ref="account_banking_pain_base.account_payment_mode_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="pain_options" position="inside">
|
||||
<field name="sepa_creditor_identifier" invisible="1"/>
|
||||
<!-- This field should be set visible by localization modules
|
||||
for countries that may have several sepa_creditor_identifier for
|
||||
the same company (I guess only Spain) -->
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- © 2015 Antiun Ingenieria S.L. - Antonio Espinosa
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_payment_mode_form_inherit" model="ir.ui.view">
|
||||
<field name="name">Add SEPA identifiers</field>
|
||||
<field name="model">payment.mode</field>
|
||||
<field name="inherit_id" ref="account_banking_pain_base.view_payment_mode_form_inherit"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="sepa_identifiers" position="inside">
|
||||
<group>
|
||||
<field name="sepa_creditor_identifier"
|
||||
attrs="{'invisible': [('sepa_type', '!=', 'sepa_direct_debit')]}"/>
|
||||
<field name="original_creditor_identifier"
|
||||
attrs="{'invisible': [('sepa_type', '!=', 'sepa_direct_debit')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,20 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
Copyright (C) 2013-2016 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="sdd_res_company_form" model="ir.ui.view">
|
||||
<record id="view_company_form" model="ir.ui.view">
|
||||
<field name="name">sepa_direct_debit.res.company.form</field>
|
||||
<field name="model">res.company</field>
|
||||
<field name="inherit_id" ref="account_banking_pain_base.view_company_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="pain" position="inside">
|
||||
<field name="sepa_creditor_identifier"/>
|
||||
<field name="original_creditor_identifier" groups="account_banking_sepa_direct_debit.group_original_mandate_required"/>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# SEPA Direct Debit module for OpenERP
|
||||
# Copyright (C) 2013 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from . import export_sdd
|
||||
@@ -1,394 +0,0 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# SEPA Direct Debit module for Odoo
|
||||
# Copyright (C) 2013-2015 Akretion (http://www.akretion.com)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
#
|
||||
# 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import Warning
|
||||
from openerp import workflow
|
||||
from lxml import etree
|
||||
|
||||
|
||||
class BankingExportSddWizard(models.TransientModel):
|
||||
_name = 'banking.export.sdd.wizard'
|
||||
_inherit = ['banking.export.pain']
|
||||
_description = 'Export SEPA Direct Debit File'
|
||||
|
||||
state = fields.Selection([
|
||||
('create', 'Create'),
|
||||
('finish', 'Finish'),
|
||||
], string='State', readonly=True, default='create')
|
||||
batch_booking = fields.Boolean(
|
||||
string='Batch Booking',
|
||||
help="If true, the bank statement will display only one credit "
|
||||
"line for all the direct debits of the SEPA file ; if false, "
|
||||
"the bank statement will display one credit line per direct "
|
||||
"debit of the SEPA file.")
|
||||
charge_bearer = fields.Selection([
|
||||
('SLEV', 'Following Service Level'),
|
||||
('SHAR', 'Shared'),
|
||||
('CRED', 'Borne by Creditor'),
|
||||
('DEBT', 'Borne by Debtor'),
|
||||
], string='Charge Bearer', required=True, default='SLEV',
|
||||
help="Following service level : transaction charges are to be "
|
||||
"applied following the rules agreed in the service level "
|
||||
"and/or scheme (SEPA Core messages must use this). Shared : "
|
||||
"transaction charges on the creditor side are to be borne "
|
||||
"by the creditor, transaction charges on the debtor side are "
|
||||
"to be borne by the debtor. Borne by creditor : all "
|
||||
"transaction charges are to be borne by the creditor. Borne "
|
||||
"by debtor : all transaction charges are to be borne by the debtor.")
|
||||
nb_transactions = fields.Integer(
|
||||
string='Number of Transactions', readonly=True)
|
||||
total_amount = fields.Float(string='Total Amount', readonly=True)
|
||||
file = fields.Binary(string="File", readonly=True)
|
||||
filename = fields.Char(string="Filename", readonly=True)
|
||||
payment_order_ids = fields.Many2many(
|
||||
'payment.order', 'wiz_sdd_payorders_rel', 'wizard_id',
|
||||
'payment_order_id', string='Payment Orders', readonly=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
payment_order_ids = self._context.get('active_ids', [])
|
||||
vals.update({
|
||||
'payment_order_ids': [[6, 0, payment_order_ids]],
|
||||
})
|
||||
return super(BankingExportSddWizard, self).create(vals)
|
||||
|
||||
def _get_previous_bank(self, payline):
|
||||
previous_bank = False
|
||||
older_lines = self.env['payment.line'].search([
|
||||
('mandate_id', '=', payline.mandate_id.id),
|
||||
('bank_id', '!=', payline.bank_id.id)])
|
||||
if older_lines:
|
||||
previous_date = False
|
||||
previous_payline = False
|
||||
for older_line in older_lines:
|
||||
if hasattr(older_line.order_id, 'date_sent'):
|
||||
older_line_date = older_line.order_id.date_sent
|
||||
else:
|
||||
older_line_date = older_line.order_id.date_done
|
||||
if (older_line_date and
|
||||
older_line_date > previous_date):
|
||||
previous_date = older_line_date
|
||||
previous_payline = older_line
|
||||
if previous_payline:
|
||||
previous_bank = previous_payline.bank_id
|
||||
return previous_bank
|
||||
|
||||
@api.multi
|
||||
def create_sepa(self):
|
||||
"""Creates the SEPA Direct Debit file. That's the important code !"""
|
||||
pain_flavor = self.payment_order_ids[0].mode.type.code
|
||||
convert_to_ascii = \
|
||||
self.payment_order_ids[0].mode.convert_to_ascii
|
||||
if pain_flavor == 'pain.008.001.02':
|
||||
bic_xml_tag = 'BIC'
|
||||
name_maxsize = 70
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
elif pain_flavor == 'pain.008.001.03':
|
||||
bic_xml_tag = 'BICFI'
|
||||
name_maxsize = 140
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
elif pain_flavor == 'pain.008.001.04':
|
||||
bic_xml_tag = 'BICFI'
|
||||
name_maxsize = 140
|
||||
root_xml_tag = 'CstmrDrctDbtInitn'
|
||||
else:
|
||||
raise Warning(
|
||||
_("Payment Type Code '%s' is not supported. The only "
|
||||
"Payment Type Code supported for SEPA Direct Debit are "
|
||||
"'pain.008.001.02', 'pain.008.001.03' and "
|
||||
"'pain.008.001.04'.") % pain_flavor)
|
||||
gen_args = {
|
||||
'bic_xml_tag': bic_xml_tag,
|
||||
'name_maxsize': name_maxsize,
|
||||
'convert_to_ascii': convert_to_ascii,
|
||||
'payment_method': 'DD',
|
||||
'file_prefix': 'sdd_',
|
||||
'pain_flavor': pain_flavor,
|
||||
'pain_xsd_file':
|
||||
'account_banking_sepa_direct_debit/data/%s.xsd' % pain_flavor,
|
||||
}
|
||||
pain_ns = {
|
||||
'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
None: 'urn:iso:std:iso:20022:tech:xsd:%s' % pain_flavor,
|
||||
}
|
||||
xml_root = etree.Element('Document', nsmap=pain_ns)
|
||||
pain_root = etree.SubElement(xml_root, root_xml_tag)
|
||||
# A. Group header
|
||||
group_header_1_0, nb_of_transactions_1_6, control_sum_1_7 = \
|
||||
self.generate_group_header_block(pain_root, gen_args)
|
||||
transactions_count_1_6 = 0
|
||||
total_amount = 0.0
|
||||
amount_control_sum_1_7 = 0.0
|
||||
lines_per_group = {}
|
||||
# key = (requested_date, priority, sequence type)
|
||||
# value = list of lines as objects
|
||||
# Iterate on payment orders
|
||||
for payment_order in self.payment_order_ids:
|
||||
total_amount = total_amount + payment_order.total
|
||||
# Iterate each payment lines
|
||||
for line in payment_order.bank_line_ids:
|
||||
transactions_count_1_6 += 1
|
||||
priority = line.priority
|
||||
# The field line.date is the requested payment date
|
||||
# taking into account the 'date_prefered' setting
|
||||
# cf account_banking_payment_export/models/account_payment.py
|
||||
# in the inherit of action_open()
|
||||
if not line.mandate_id:
|
||||
raise Warning(
|
||||
_("Missing SEPA Direct Debit mandate on the "
|
||||
"bank payment line with partner '%s' "
|
||||
"(reference '%s').")
|
||||
% (line.partner_id.name, line.name))
|
||||
scheme = line.mandate_id.scheme
|
||||
if line.mandate_id.state != 'valid':
|
||||
raise Warning(
|
||||
_("The SEPA Direct Debit mandate with reference '%s' "
|
||||
"for partner '%s' has expired.")
|
||||
% (line.mandate_id.unique_mandate_reference,
|
||||
line.mandate_id.partner_id.name))
|
||||
if line.mandate_id.type == 'oneoff':
|
||||
seq_type = 'OOFF'
|
||||
if line.mandate_id.last_debit_date:
|
||||
raise Warning(
|
||||
_("The mandate with reference '%s' for partner "
|
||||
"'%s' has type set to 'One-Off' and it has a "
|
||||
"last debit date set to '%s', so we can't use "
|
||||
"it.")
|
||||
% (line.mandate_id.unique_mandate_reference,
|
||||
line.mandate_id.partner_id.name,
|
||||
line.mandate_id.last_debit_date))
|
||||
elif line.mandate_id.type == 'recurrent':
|
||||
seq_type_map = {
|
||||
'recurring': 'RCUR',
|
||||
'first': 'FRST',
|
||||
'final': 'FNAL',
|
||||
}
|
||||
seq_type_label = \
|
||||
line.mandate_id.recurrent_sequence_type
|
||||
assert seq_type_label is not False
|
||||
seq_type = seq_type_map[seq_type_label]
|
||||
key = (line.date, priority, seq_type, scheme)
|
||||
if key in lines_per_group:
|
||||
lines_per_group[key].append(line)
|
||||
else:
|
||||
lines_per_group[key] = [line]
|
||||
|
||||
for (requested_date, priority, sequence_type, scheme), lines in \
|
||||
lines_per_group.items():
|
||||
# B. Payment info
|
||||
payment_info_2_0, nb_of_transactions_2_4, control_sum_2_5 = \
|
||||
self.generate_start_payment_info_block(
|
||||
pain_root,
|
||||
"self.payment_order_ids[0].reference + '-' + "
|
||||
"sequence_type + '-' + requested_date.replace('-', '') "
|
||||
"+ '-' + priority",
|
||||
priority, scheme, sequence_type, requested_date, {
|
||||
'self': self,
|
||||
'sequence_type': sequence_type,
|
||||
'priority': priority,
|
||||
'requested_date': requested_date,
|
||||
}, gen_args)
|
||||
|
||||
self.generate_party_block(
|
||||
payment_info_2_0, 'Cdtr', 'B',
|
||||
'self.payment_order_ids[0].mode.bank_id.partner_id.'
|
||||
'name',
|
||||
'self.payment_order_ids[0].mode.bank_id.acc_number',
|
||||
'self.payment_order_ids[0].mode.bank_id.bank.bic or '
|
||||
'self.payment_order_ids[0].mode.bank_id.bank_bic',
|
||||
{'self': self}, gen_args)
|
||||
charge_bearer_2_24 = etree.SubElement(payment_info_2_0, 'ChrgBr')
|
||||
charge_bearer_2_24.text = self.charge_bearer
|
||||
creditor_scheme_identification_2_27 = etree.SubElement(
|
||||
payment_info_2_0, 'CdtrSchmeId')
|
||||
self.generate_creditor_scheme_identification(
|
||||
creditor_scheme_identification_2_27,
|
||||
'self.payment_order_ids[0].mode.'
|
||||
'sepa_creditor_identifier or '
|
||||
'self.payment_order_ids[0].company_id.'
|
||||
'sepa_creditor_identifier',
|
||||
'SEPA Creditor Identifier', {'self': self}, 'SEPA', gen_args)
|
||||
transactions_count_2_4 = 0
|
||||
amount_control_sum_2_5 = 0.0
|
||||
for line in lines:
|
||||
transactions_count_2_4 += 1
|
||||
# C. Direct Debit Transaction Info
|
||||
dd_transaction_info_2_28 = etree.SubElement(
|
||||
payment_info_2_0, 'DrctDbtTxInf')
|
||||
payment_identification_2_29 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'PmtId')
|
||||
end2end_identification_2_31 = etree.SubElement(
|
||||
payment_identification_2_29, 'EndToEndId')
|
||||
end2end_identification_2_31.text = self._prepare_field(
|
||||
'End to End Identification', 'line.name',
|
||||
{'line': line}, 35, gen_args=gen_args)
|
||||
currency_name = self._prepare_field(
|
||||
'Currency Code', 'line.currency.name',
|
||||
{'line': line}, 3, gen_args=gen_args)
|
||||
instructed_amount_2_44 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'InstdAmt', Ccy=currency_name)
|
||||
instructed_amount_2_44.text = '%.2f' % line.amount_currency
|
||||
amount_control_sum_1_7 += line.amount_currency
|
||||
amount_control_sum_2_5 += line.amount_currency
|
||||
dd_transaction_2_46 = etree.SubElement(
|
||||
dd_transaction_info_2_28, 'DrctDbtTx')
|
||||
mandate_related_info_2_47 = etree.SubElement(
|
||||
dd_transaction_2_46, 'MndtRltdInf')
|
||||
mandate_identification_2_48 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'MndtId')
|
||||
mandate_identification_2_48.text = self._prepare_field(
|
||||
'Unique Mandate Reference',
|
||||
'line.mandate_id.unique_mandate_reference',
|
||||
{'line': line}, 35, gen_args=gen_args)
|
||||
mandate_signature_date_2_49 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'DtOfSgntr')
|
||||
mandate_signature_date_2_49.text = self._prepare_field(
|
||||
'Mandate Signature Date',
|
||||
'line.mandate_id.signature_date',
|
||||
{'line': line}, 10, gen_args=gen_args)
|
||||
if sequence_type == 'FRST' and (
|
||||
line.mandate_id.last_debit_date or
|
||||
not line.mandate_id.sepa_migrated):
|
||||
previous_bank = self._get_previous_bank(line)
|
||||
if previous_bank or not line.mandate_id.sepa_migrated:
|
||||
amendment_indicator_2_50 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'AmdmntInd')
|
||||
amendment_indicator_2_50.text = 'true'
|
||||
amendment_info_details_2_51 = etree.SubElement(
|
||||
mandate_related_info_2_47, 'AmdmntInfDtls')
|
||||
if previous_bank:
|
||||
if (previous_bank.bank.bic or
|
||||
previous_bank.bank_bic) == \
|
||||
(line.bank_id.bank.bic or
|
||||
line.bank_id.bank_bic):
|
||||
ori_debtor_account_2_57 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlDbtrAcct')
|
||||
ori_debtor_account_id = etree.SubElement(
|
||||
ori_debtor_account_2_57, 'Id')
|
||||
ori_debtor_account_iban = etree.SubElement(
|
||||
ori_debtor_account_id, 'IBAN')
|
||||
ori_debtor_account_iban.text = self._validate_iban(
|
||||
self._prepare_field(
|
||||
'Original Debtor Account',
|
||||
'previous_bank.acc_number',
|
||||
{'previous_bank': previous_bank},
|
||||
gen_args=gen_args))
|
||||
else:
|
||||
ori_debtor_agent_2_58 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlDbtrAgt')
|
||||
ori_debtor_agent_institution = etree.SubElement(
|
||||
ori_debtor_agent_2_58, 'FinInstnId')
|
||||
ori_debtor_agent_bic = etree.SubElement(
|
||||
ori_debtor_agent_institution, bic_xml_tag)
|
||||
ori_debtor_agent_bic.text = self._prepare_field(
|
||||
'Original Debtor Agent',
|
||||
'previous_bank.bank.bic or '
|
||||
'previous_bank.bank_bic',
|
||||
{'previous_bank': previous_bank},
|
||||
gen_args=gen_args)
|
||||
ori_debtor_agent_other = etree.SubElement(
|
||||
ori_debtor_agent_institution, 'Othr')
|
||||
ori_debtor_agent_other_id = etree.SubElement(
|
||||
ori_debtor_agent_other, 'Id')
|
||||
ori_debtor_agent_other_id.text = 'SMNDA'
|
||||
# SMNDA = Same Mandate New Debtor Agent
|
||||
elif not line.mandate_id.sepa_migrated:
|
||||
ori_mandate_identification_2_52 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlMndtId')
|
||||
ori_mandate_identification_2_52.text = \
|
||||
self._prepare_field(
|
||||
'Original Mandate Identification',
|
||||
'line.mandate_id.'
|
||||
'original_mandate_identification',
|
||||
{'line': line},
|
||||
gen_args=gen_args)
|
||||
ori_creditor_scheme_id_2_53 = etree.SubElement(
|
||||
amendment_info_details_2_51, 'OrgnlCdtrSchmeId')
|
||||
self.generate_creditor_scheme_identification(
|
||||
ori_creditor_scheme_id_2_53,
|
||||
'self.payment_order_ids[0].mode.'
|
||||
'original_creditor_identifier or '
|
||||
'self.payment_order_ids[0].company_id.'
|
||||
'original_creditor_identifier',
|
||||
'Original Creditor Identifier',
|
||||
{'self': self}, 'SEPA', gen_args)
|
||||
|
||||
self.generate_party_block(
|
||||
dd_transaction_info_2_28, 'Dbtr', 'C',
|
||||
'line.partner_id.name',
|
||||
'line.bank_id.acc_number',
|
||||
'line.bank_id.bank.bic or '
|
||||
'line.bank_id.bank_bic',
|
||||
{'line': line}, gen_args)
|
||||
|
||||
self.generate_remittance_info_block(
|
||||
dd_transaction_info_2_28, line, gen_args)
|
||||
|
||||
nb_of_transactions_2_4.text = unicode(transactions_count_2_4)
|
||||
control_sum_2_5.text = '%.2f' % amount_control_sum_2_5
|
||||
nb_of_transactions_1_6.text = unicode(transactions_count_1_6)
|
||||
control_sum_1_7.text = '%.2f' % amount_control_sum_1_7
|
||||
|
||||
return self.finalize_sepa_file_creation(
|
||||
xml_root, total_amount, transactions_count_1_6, gen_args)
|
||||
|
||||
@api.multi
|
||||
def save_sepa(self):
|
||||
"""Save the SEPA Direct Debit file: mark all payments in the file
|
||||
as 'sent'. Write 'last debit date' on mandate and set oneoff
|
||||
mandate to expired.
|
||||
"""
|
||||
abmo = self.env['account.banking.mandate']
|
||||
for order in self.payment_order_ids:
|
||||
workflow.trg_validate(
|
||||
self._uid, 'payment.order', order.id, 'done', self._cr)
|
||||
self.env['ir.attachment'].create({
|
||||
'res_model': 'payment.order',
|
||||
'res_id': order.id,
|
||||
'name': self.filename,
|
||||
'datas': self.file,
|
||||
})
|
||||
to_expire_mandates = abmo.browse([])
|
||||
first_mandates = abmo.browse([])
|
||||
all_mandates = abmo.browse([])
|
||||
for bline in order.bank_line_ids:
|
||||
if bline.mandate_id in all_mandates:
|
||||
continue
|
||||
all_mandates += bline.mandate_id
|
||||
if bline.mandate_id.type == 'oneoff':
|
||||
to_expire_mandates += bline.mandate_id
|
||||
elif bline.mandate_id.type == 'recurrent':
|
||||
seq_type = bline.mandate_id.recurrent_sequence_type
|
||||
if seq_type == 'final':
|
||||
to_expire_mandates += bline.mandate_id
|
||||
elif seq_type == 'first':
|
||||
first_mandates += bline.mandate_id
|
||||
all_mandates.write(
|
||||
{'last_debit_date': fields.Date.context_today(self)})
|
||||
to_expire_mandates.write({'state': 'expired'})
|
||||
first_mandates.write({
|
||||
'recurrent_sequence_type': 'recurring',
|
||||
'sepa_migrated': True,
|
||||
})
|
||||
return True
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2010-2012 Akretion (http://www.akretion.com)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="banking_export_sdd_wizard_view" model="ir.ui.view">
|
||||
<field name="name">banking.export.sdd.wizard.view</field>
|
||||
<field name="model">banking.export.sdd.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="SEPA Direct Debit XML file generation">
|
||||
<field name="state" invisible="True"/>
|
||||
<group states="create">
|
||||
<field name="batch_booking" />
|
||||
<field name="charge_bearer" />
|
||||
</group>
|
||||
<group states="finish">
|
||||
<field name="total_amount" />
|
||||
<field name="nb_transactions" />
|
||||
<field name="file" filename="filename" />
|
||||
<field name="filename" invisible="True"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="Generate" name="create_sepa" type="object" class="oe_highlight" states="create"/>
|
||||
<button string="Validate" name="save_sepa" type="object" class="oe_highlight" states="finish"/>
|
||||
<button string="Cancel" special="cancel" class="oe_link"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,77 +0,0 @@
|
||||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:alt: License: AGPL-3
|
||||
|
||||
Direct Debit
|
||||
============
|
||||
|
||||
This module adds support for direct debit orders, analogous to payment orders.
|
||||
A new entry in the Accounting/Payment menu allow you to create a direct debit
|
||||
order that helps you to select any customer invoices for you to collect.
|
||||
|
||||
Debit orders are advanced in total by the bank. Amounts that cannot be
|
||||
debited or are canceled by account owners are credited afterwards.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
This module depends on :
|
||||
* account_banking_payment_export
|
||||
|
||||
This module is part of the OCA/bank-payment suite.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
Please refer to module *Account Banking SEPA Direct Debit*
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Please refer to module *Account Banking SEPA Direct Debit*
|
||||
|
||||
|
||||
For further information, please visit:
|
||||
|
||||
* https://www.odoo.com/forum/help-1
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
* No known issues
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
|
||||
`here <https://github.com/OCA/bank-payment/issues/new?body=module:%20account_direct_debit%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Stefan Rijnhart
|
||||
* Pedro M. Baeza
|
||||
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
* Danimar Ribeiro
|
||||
* Stéphane Bidoul <stephane.bidoul@acsone.eu>
|
||||
* Alexandre Fayolle
|
||||
* Sandy Carter
|
||||
* Holger Brunn
|
||||
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: http://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: http://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.
|
||||
|
||||
To contribute to this module, please visit http://odoo-community.org.
|
||||
@@ -1,2 +0,0 @@
|
||||
from . import models
|
||||
from . import wizard
|
||||
@@ -1,25 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2011 Smile (<http://smile.fr>)
|
||||
# © 2011-2013 Therp BV (<http://therp.nl>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
{
|
||||
'name': 'Direct Debit',
|
||||
'version': '8.0.2.1.0',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Therp BV, '
|
||||
'Smile, '
|
||||
'Odoo Community Association (OCA)',
|
||||
'website': 'https://github.com/OCA/bank-payment',
|
||||
'category': 'Banking addons',
|
||||
'depends': ['account_banking_payment_export'],
|
||||
'data': [
|
||||
'views/account_payment.xml',
|
||||
'views/payment_mode.xml',
|
||||
'views/payment_mode_type.xml',
|
||||
'data/account_payment_term.xml',
|
||||
'data/payment_mode_type.xml'
|
||||
],
|
||||
'installable': False,
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="payment_term_direct_debit" model="account.payment.term">
|
||||
<field name="name">Direct debit</field>
|
||||
<field name="note">Direct debit in 14 days</field>
|
||||
</record>
|
||||
<record id="payment_term_line_direct_debit" model="account.payment.term.line">
|
||||
<field name="value">balance</field>
|
||||
<field eval="14" name="days"/>
|
||||
<field eval="0" name="days2"/>
|
||||
<field eval="payment_term_direct_debit" name="payment_id"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- Add direct debit as payment option -->
|
||||
<record model="payment.mode.type" id="manual_direct_debit">
|
||||
<field name="name">Manual Direct Debit</field>
|
||||
<field name="code">MANDDEB</field>
|
||||
<field name="suitable_bank_types"
|
||||
eval="[(6,0,[ref('base.bank_normal'),ref('base_iban.bank_iban'),])]" />
|
||||
<field name="ir_model_id"
|
||||
ref="account_banking_payment_export.model_payment_manual"/>
|
||||
<field name="payment_order_type">debit</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -1,127 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-10-31 23:05+0000\n"
|
||||
"PO-Revision-Date: 2014-10-31 23:05+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid "A debit order is a debit request from your company to collect customer invoices. Here you can register all debit orders that should be done, keep track of all debit orders and mention the invoice reference and the partner the withdrawal should be done for."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: field:account.move.line,amount_to_receive:0
|
||||
msgid "Amount to receive"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: code:addons/account_direct_debit/models/payment_line.py:133
|
||||
#, python-format
|
||||
msgid "Can not reconcile"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: code:addons/account_direct_debit/models/payment_line.py:134
|
||||
#, python-format
|
||||
msgid "Cancelation of payment line '%s' has already been processed"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:account.invoice:account_direct_debit.invoice_form
|
||||
msgid "Debit Denied"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:account.invoice:account_direct_debit.view_account_invoice_filter
|
||||
msgid "Debit denied"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: code:addons/account_direct_debit/models/account_invoice.py:149
|
||||
#, python-format
|
||||
msgid "Error !"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: help:payment.line,storno:0
|
||||
msgid "If this is true, the debit order has been canceled by the bank or by the customer"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_invoice
|
||||
msgid "Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: code:addons/account_direct_debit/models/account_invoice.py:154
|
||||
#, python-format
|
||||
msgid "Invoice '%s': direct debit is denied."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_order
|
||||
msgid "Payment Order"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:account.invoice:account_direct_debit.view_account_invoice_filter
|
||||
msgid "Show only invoices with state Debit denied"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: field:payment.line,storno:0
|
||||
msgid "Storno"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: code:addons/account_direct_debit/models/account_invoice.py:150
|
||||
#, python-format
|
||||
msgid "You cannot set invoice '%s' to state 'debit denied', as it is still reconciled."
|
||||
msgstr ""
|
||||
@@ -1,68 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-02-16 07:59+0000\n"
|
||||
"PO-Revision-Date: 2016-02-16 07:59+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid "A debit order is a debit request from your company to collect customer invoices. Here you can register all debit orders that should be done, keep track of all debit orders and mention the invoice reference and the partner the withdrawal should be done for."
|
||||
msgstr "Una orden de cobro es una petición de dinero de su compañía para saldar las facturas de cliente. Aquí puede registrar todas las órdenes de cobro que se deban realizar, seguirles el rastro, y apuntar la referencia de factura y de la empresa para la que se debe hacer el cargo."
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr "Órdenes de cobro"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr "Cobro"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr "Adeudo directo en 14 días"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr "Facturas"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr "Apuntes contables"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr "Línea de pago"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr "Seleccione facturas"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "[('payment_order_type', '=', payment_order_type)]"
|
||||
msgstr "[('payment_order_type', '=', payment_order_type)]"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', 'payment')]}"
|
||||
msgstr "{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', 'payment')]}"
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: bank-payment (8.0)\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-04-08 00:46+0000\n"
|
||||
"PO-Revision-Date: 2016-04-06 00:15+0000\n"
|
||||
"Last-Translator: <>\n"
|
||||
"Language-Team: French (http://www.transifex.com/oca/OCA-bank-payment-8-0/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid ""
|
||||
"A debit order is a debit request from your company to collect customer "
|
||||
"invoices. Here you can register all debit orders that should be done, keep "
|
||||
"track of all debit orders and mention the invoice reference and the partner "
|
||||
"the withdrawal should be done for."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr "Ligne de paiement"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "[('payment_order_type', '=', payment_order_type)]"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid ""
|
||||
"{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', "
|
||||
"'payment')]}"
|
||||
msgstr ""
|
||||
@@ -1,76 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
# Translators:
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: bank-payment (8.0)\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-04-08 00:46+0000\n"
|
||||
"PO-Revision-Date: 2016-04-06 00:15+0000\n"
|
||||
"Last-Translator: OCA Transbot <transbot@odoo-community.org>\n"
|
||||
"Language-Team: Dutch (http://www.transifex.com/oca/OCA-bank-payment-8-0/language/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: nl\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid ""
|
||||
"A debit order is a debit request from your company to collect customer "
|
||||
"invoices. Here you can register all debit orders that should be done, keep "
|
||||
"track of all debit orders and mention the invoice reference and the partner "
|
||||
"the withdrawal should be done for."
|
||||
msgstr "Een incasso opdracht is een opdracht van uw bedrijf aan uw klant voor het incasseren van openstaande posten. Hier kunt u alle incasso opdrachten invoeren die moeten worden uitgevoerd en overzicht houden op alle incasso opdrachten. Tevens voert u hier de factuurreferentie en klant in waar de afschrijving moet plaatsvinden."
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr "Incasso opdracht"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr "Incasso opdracht"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr "Incasso opdracht in 14 dagen"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr "Boekingen"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr "Betaalregel"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "[('payment_order_type', '=', payment_order_type)]"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid ""
|
||||
"{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', "
|
||||
"'payment')]}"
|
||||
msgstr ""
|
||||
@@ -1,76 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
# Translators:
|
||||
# danimaribeiro <danimaribeiro@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: bank-payment (8.0)\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-04-08 00:46+0000\n"
|
||||
"PO-Revision-Date: 2016-04-06 01:04+0000\n"
|
||||
"Last-Translator: danimaribeiro <danimaribeiro@gmail.com>\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/OCA-bank-payment-8-0/language/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid ""
|
||||
"A debit order is a debit request from your company to collect customer "
|
||||
"invoices. Here you can register all debit orders that should be done, keep "
|
||||
"track of all debit orders and mention the invoice reference and the partner "
|
||||
"the withdrawal should be done for."
|
||||
msgstr "A ordem de débito é um pedido de débito de sua empresa para coletar faturas de clientes. Aqui você pode registrar todas as ordens de débito que devem ser feitas, manter o controle de todas as ordens de débito e mencionar a referência da fatura e o parceiro que a retirada deve ser feita."
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr "Débito direto autorizado"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr "Débito direto"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr "Débito direto em 14 dias"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr "Faturas"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr "Itens de diário"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr "Linha de pagamento"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr "Selecione as faturas"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "[('payment_order_type', '=', payment_order_type)]"
|
||||
msgstr "[('payment_order_type', '=', payment_order_type)]"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid ""
|
||||
"{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', "
|
||||
"'payment')]}"
|
||||
msgstr "{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', 'payment')]}"
|
||||
@@ -1,76 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_direct_debit
|
||||
#
|
||||
# Translators:
|
||||
# Matjaž Mozetič <m.mozetic@matmoz.si>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: bank-payment (8.0)\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-04-08 00:46+0000\n"
|
||||
"PO-Revision-Date: 2016-04-08 05:55+0000\n"
|
||||
"Last-Translator: Matjaž Mozetič <m.mozetic@matmoz.si>\n"
|
||||
"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-bank-payment-8-0/language/sl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sl\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,help:account_direct_debit.action_debit_order_tree
|
||||
msgid ""
|
||||
"A debit order is a debit request from your company to collect customer "
|
||||
"invoices. Here you can register all debit orders that should be done, keep "
|
||||
"track of all debit orders and mention the invoice reference and the partner "
|
||||
"the withdrawal should be done for."
|
||||
msgstr "Bremenilni nalog je zahtevek vaše družbe po obremenitvi za zbir prejetih računov. Registrirate lahko vse bremenilne naloge, ki naj bi se izvedli, sledite bremenilnim nalogom in navedete sklic računa in partnerja, za katerega se izvaja nakazilo."
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.actions.act_window,name:account_direct_debit.action_debit_order_tree
|
||||
#: model:ir.ui.menu,name:account_direct_debit.menu_action_debit_order_form
|
||||
msgid "Direct Debit Orders"
|
||||
msgstr "Nalogi za direktne obremenitve"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,name:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit"
|
||||
msgstr "Direktna obremenitev"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:account.payment.term,note:account_direct_debit.payment_term_direct_debit
|
||||
msgid "Direct debit in 14 days"
|
||||
msgstr "Direktna obremenitev v 14 dneh"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Invoices"
|
||||
msgstr "Računi"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_account_move_line
|
||||
msgid "Journal Items"
|
||||
msgstr "Dnevniške postavke"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: model:ir.model,name:account_direct_debit.model_payment_line
|
||||
msgid "Payment Line"
|
||||
msgstr "Plačilna postavka"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "Select invoices to collect"
|
||||
msgstr "Izbira zbira računov"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid "[('payment_order_type', '=', payment_order_type)]"
|
||||
msgstr "[('payment_order_type', '=', payment_order_type)]"
|
||||
|
||||
#. module: account_direct_debit
|
||||
#: view:payment.order:account_direct_debit.view_payment_order_form
|
||||
msgid ""
|
||||
"{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', "
|
||||
"'payment')]}"
|
||||
msgstr "{'invisible': ['|', ('state', '!=', 'draft'), ('payment_order_type', '!=', 'payment')]}"
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import payment_line
|
||||
from . import account_move_line
|
||||
@@ -1,38 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2011 Smile (<http://smile.fr>)
|
||||
# © 2011-2013 Therp BV (<http://therp.nl>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = "account.move.line"
|
||||
|
||||
def line2bank(self, cr, uid, ids, payment_type=None, context=None):
|
||||
"""I have to inherit this function for direct debits to fix the
|
||||
following issue : if the customer invoice has a value for
|
||||
'partner_bank_id', then it will take this partner_bank_id
|
||||
in the payment line... but, on a customer invoice,
|
||||
the partner_bank_id is the bank account of the company,
|
||||
not the bank account of the customer !
|
||||
"""
|
||||
pay_mode_obj = self.pool['payment.mode']
|
||||
if payment_type:
|
||||
pay_mode = pay_mode_obj.browse(
|
||||
cr, uid, payment_type, context=context)
|
||||
if pay_mode.type.payment_order_type == 'debit':
|
||||
line2bank = {}
|
||||
bank_type = pay_mode_obj.suitable_bank_types(
|
||||
cr, uid, pay_mode.id, context=context)
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
line2bank[line.id] = False
|
||||
if line.partner_id:
|
||||
for bank in line.partner_id.bank_ids:
|
||||
if bank.state in bank_type:
|
||||
line2bank[line.id] = bank.id
|
||||
break
|
||||
return line2bank
|
||||
return super(AccountMoveLine, self).line2bank(
|
||||
cr, uid, ids, payment_type=pay_mode.id, context=context)
|
||||
@@ -1,14 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2011 Smile (<http://smile.fr>)
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields
|
||||
|
||||
|
||||
class PaymentLine(models.Model):
|
||||
_inherit = 'payment.line'
|
||||
|
||||
# The original string is "Destination Bank Account"...
|
||||
# but in direct debit this field is the *Source* Bank Account !
|
||||
bank_id = fields.Many2one(string='Partner Bank Account')
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user