From bee309384134cde9c4655f89a24c0612ddc84e56 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Sat, 30 Apr 2016 01:46:34 +0200 Subject: [PATCH] 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 --- account_banking_mandate/__openerp__.py | 11 +- .../data/mandate_reference_sequence.xml | 5 - account_banking_mandate/models/__init__.py | 3 +- .../models/account_banking_mandate.py | 63 +- .../models/account_invoice.py | 17 +- .../models/account_move_line.py | 23 + ...ayment_line.py => account_payment_line.py} | 34 +- .../models/bank_payment_line.py | 2 +- .../security/ir.model.access.csv | 6 +- .../views/account_banking_mandate_view.xml | 26 +- .../views/account_invoice_view.xml | 6 +- .../views/account_move_line.xml | 26 + .../views/account_payment_line.xml | 37 ++ .../views/account_payment_view.xml | 30 - .../views/bank_payment_line_view.xml | 14 +- .../views/res_partner_bank_view.xml | 21 +- account_banking_pain_base/__openerp__.py | 14 +- account_banking_pain_base/models/__init__.py | 8 +- .../models/account_payment_line.py | 23 + .../models/account_payment_method.py | 19 + ...ayment_mode.py => account_payment_mode.py} | 31 +- .../models/account_payment_order.py | 55 ++ .../models/bank_payment_line.py | 5 +- .../models/banking_export_pain.py | 100 +-- .../models/payment_line.py | 26 - account_banking_pain_base/post_install.py | 2 +- .../views/account_payment_line.xml | 22 + .../views/account_payment_method.xml | 30 + .../views/account_payment_mode.xml | 30 + .../views/account_payment_order.xml | 24 + .../views/bank_payment_line_view.xml | 9 +- .../views/payment_line_view.xml | 26 - .../views/payment_mode_view.xml | 33 - .../data/bank_payment_line_seq.xml | 26 - .../models/__init__.py | 11 - .../models/account_move_line.py | 37 -- .../models/account_payment.py | 159 ----- .../models/bank_payment_line.py | 68 -- .../models/payment_line.py | 22 - .../models/payment_mode.py | 119 ---- .../models/payment_mode_type.py | 44 -- .../security/ir.model.access.csv | 3 - .../views/account_payment.xml | 107 --- .../views/bank_payment_manual.xml | 18 - .../views/payment_mode.xml | 37 -- .../views/payment_mode_type.xml | 66 -- .../wizard/__init__.py | 3 - .../wizard/bank_payment_manual.py | 42 -- .../wizard/bank_payment_manual.xml | 18 - .../wizard/payment_order_create_view.xml | 70 -- .../workflow/account_payment.xml | 20 - .../__init__.py | 1 - .../__openerp__.py | 10 +- .../data/account_payment_method.xml | 15 + .../data/payment_type_sepa_sct.xml | 53 -- .../demo/sepa_credit_transfer_demo.xml | 11 +- .../models/__init__.py | 3 +- .../models/account_payment_method.py | 28 + .../account_payment_order.py} | 161 ++--- .../models/payment_mode.py | 16 - .../wizard/__init__.py | 5 - .../wizard/export_sepa_view.xml | 36 - account_banking_sepa_direct_debit/__init__.py | 3 - .../__openerp__.py | 13 +- .../data/account_payment_method.xml | 15 + .../data/mandate_expire_cron.xml | 2 +- .../data/pain.008.003.02.xsd | 614 ++++++++++++++++++ .../data/payment_type_sdd.xml | 35 - .../demo/sepa_direct_debit_demo.xml | 14 +- .../models/__init__.py | 4 +- .../models/account_banking_mandate.py | 70 +- .../models/account_payment_method.py | 27 + ...ayment_mode.py => account_payment_mode.py} | 19 +- .../models/account_payment_order.py | 298 +++++++++ .../models/bank_payment_line.py | 2 +- .../models/common.py | 2 +- .../models/res_company.py | 11 +- .../original_mandate_required_security.xml | 17 - .../views/account_banking_mandate_view.xml | 74 +-- .../views/account_payment_mode.xml | 23 + .../views/payment_mode_view.xml | 24 - .../views/res_company_view.xml | 5 +- .../wizard/__init__.py | 23 - .../wizard/export_sdd.py | 394 ----------- .../wizard/export_sdd_view.xml | 36 - account_direct_debit/README.rst | 77 --- account_direct_debit/__init__.py | 2 - account_direct_debit/__openerp__.py | 25 - .../data/account_payment_term.xml | 15 - .../data/payment_mode_type.xml | 15 - .../i18n/account_direct_debit.pot | 127 ---- account_direct_debit/i18n/es.po | 68 -- account_direct_debit/i18n/fr.po | 75 --- account_direct_debit/i18n/nl.po | 76 --- account_direct_debit/i18n/pt_BR.po | 76 --- account_direct_debit/i18n/sl.po | 76 --- account_direct_debit/models/__init__.py | 4 - .../models/account_move_line.py | 38 -- account_direct_debit/models/payment_line.py | 14 - .../static/description/icon.png | Bin 9455 -> 0 bytes .../views/account_payment.xml | 51 -- account_direct_debit/views/payment_mode.xml | 20 - .../views/payment_mode_type.xml | 31 - account_direct_debit/wizard/__init__.py | 1 - .../wizard/payment_order_create.py | 30 - account_payment_mode/README.rst | 58 ++ account_payment_mode/__init__.py | 3 + account_payment_mode/__openerp__.py | 21 + .../demo/payment_demo.xml | 76 ++- account_payment_mode/models/__init__.py | 5 + .../models/account_payment_method.py | 34 + .../models/account_payment_mode.py | 100 +++ .../models/res_partner_bank.py | 13 + .../security/ir.model.access.csv | 5 + .../views/account_payment_method.xml | 62 ++ .../views/account_payment_mode.xml | 71 ++ .../views/res_partner_bank.xml | 44 ++ .../README.rst | 0 .../__init__.py | 0 .../__openerp__.py | 31 +- .../data/payment_mode_type.xml | 0 account_payment_order/data/payment_seq.xml | 38 ++ account_payment_order/demo/payment_demo.xml | 34 + .../i18n/es.po | 0 .../i18n/fr.po | 0 .../i18n/nl.po | 0 .../i18n/pt_BR.po | 0 .../i18n/sl.po | 0 .../migrations/8.0.0.1.166/pre-migrate.py | 0 account_payment_order/models/__init__.py | 9 + .../models/account_invoice.py | 10 + .../models/account_move_line.py | 88 +++ .../models/account_payment_line.py | 124 ++++ .../models/account_payment_mode.py | 57 ++ .../models/account_payment_order.py | 261 ++++++++ .../models/bank_payment_line.py | 78 +++ .../models/res_bank.py | 18 +- .../security/ir.model.access.csv | 4 + .../security/payment_security.xml | 39 ++ .../static/description/icon.png | Bin .../views/account_move_line.xml | 27 + .../views/account_payment_line.xml | 66 ++ .../views/account_payment_mode.xml | 51 ++ .../views/account_payment_order.xml | 127 ++++ .../views/bank_payment_line.xml | 39 +- account_payment_order/views/ir_attachment.xml | 32 + .../views/payment_order_create_view.xml | 0 account_payment_order/wizard/__init__.py | 3 + .../wizard/account_payment_line_create.py | 205 +++--- .../account_payment_line_create_view.xml | 62 ++ account_payment_partner/__init__.py | 1 - account_payment_partner/__openerp__.py | 12 +- account_payment_partner/models/__init__.py | 2 +- .../models/account_invoice.py | 47 +- .../models/account_move_line.py | 13 + .../models/payment_mode.py | 16 - account_payment_partner/models/res_partner.py | 10 +- .../security/ir.model.access.csv | 3 - .../views/account_invoice_view.xml | 27 +- .../views/account_move_line.xml | 28 + .../views/payment_mode.xml | 20 - .../views/report_invoice.xml | 2 +- .../views/res_partner_view.xml | 12 +- account_payment_partner/wizard/__init__.py | 23 - .../wizard/payment_order_create.py | 60 -- .../wizard/payment_order_create_view.xml | 25 - portal_payment_mode/__openerp__.py | 2 +- 167 files changed, 3375 insertions(+), 3359 deletions(-) create mode 100644 account_banking_mandate/models/account_move_line.py rename account_banking_mandate/models/{payment_line.py => account_payment_line.py} (65%) create mode 100644 account_banking_mandate/views/account_move_line.xml create mode 100644 account_banking_mandate/views/account_payment_line.xml delete mode 100644 account_banking_mandate/views/account_payment_view.xml create mode 100644 account_banking_pain_base/models/account_payment_line.py create mode 100644 account_banking_pain_base/models/account_payment_method.py rename account_banking_pain_base/models/{payment_mode.py => account_payment_mode.py} (69%) create mode 100644 account_banking_pain_base/models/account_payment_order.py delete mode 100644 account_banking_pain_base/models/payment_line.py create mode 100644 account_banking_pain_base/views/account_payment_line.xml create mode 100644 account_banking_pain_base/views/account_payment_method.xml create mode 100644 account_banking_pain_base/views/account_payment_mode.xml create mode 100644 account_banking_pain_base/views/account_payment_order.xml delete mode 100644 account_banking_pain_base/views/payment_line_view.xml delete mode 100644 account_banking_pain_base/views/payment_mode_view.xml delete mode 100644 account_banking_payment_export/data/bank_payment_line_seq.xml delete mode 100644 account_banking_payment_export/models/__init__.py delete mode 100644 account_banking_payment_export/models/account_move_line.py delete mode 100644 account_banking_payment_export/models/account_payment.py delete mode 100644 account_banking_payment_export/models/bank_payment_line.py delete mode 100644 account_banking_payment_export/models/payment_line.py delete mode 100644 account_banking_payment_export/models/payment_mode.py delete mode 100644 account_banking_payment_export/models/payment_mode_type.py delete mode 100644 account_banking_payment_export/security/ir.model.access.csv delete mode 100644 account_banking_payment_export/views/account_payment.xml delete mode 100644 account_banking_payment_export/views/bank_payment_manual.xml delete mode 100644 account_banking_payment_export/views/payment_mode.xml delete mode 100644 account_banking_payment_export/views/payment_mode_type.xml delete mode 100644 account_banking_payment_export/wizard/__init__.py delete mode 100644 account_banking_payment_export/wizard/bank_payment_manual.py delete mode 100644 account_banking_payment_export/wizard/bank_payment_manual.xml delete mode 100644 account_banking_payment_export/wizard/payment_order_create_view.xml delete mode 100644 account_banking_payment_export/workflow/account_payment.xml create mode 100644 account_banking_sepa_credit_transfer/data/account_payment_method.xml delete mode 100644 account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml create mode 100644 account_banking_sepa_credit_transfer/models/account_payment_method.py rename account_banking_sepa_credit_transfer/{wizard/export_sepa.py => models/account_payment_order.py} (52%) delete mode 100644 account_banking_sepa_credit_transfer/models/payment_mode.py delete mode 100644 account_banking_sepa_credit_transfer/wizard/__init__.py delete mode 100644 account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml create mode 100644 account_banking_sepa_direct_debit/data/account_payment_method.xml create mode 100644 account_banking_sepa_direct_debit/data/pain.008.003.02.xsd delete mode 100644 account_banking_sepa_direct_debit/data/payment_type_sdd.xml create mode 100644 account_banking_sepa_direct_debit/models/account_payment_method.py rename account_banking_sepa_direct_debit/models/{payment_mode.py => account_payment_mode.py} (70%) create mode 100644 account_banking_sepa_direct_debit/models/account_payment_order.py delete mode 100644 account_banking_sepa_direct_debit/security/original_mandate_required_security.xml create mode 100644 account_banking_sepa_direct_debit/views/account_payment_mode.xml delete mode 100644 account_banking_sepa_direct_debit/views/payment_mode_view.xml delete mode 100644 account_banking_sepa_direct_debit/wizard/__init__.py delete mode 100644 account_banking_sepa_direct_debit/wizard/export_sdd.py delete mode 100644 account_banking_sepa_direct_debit/wizard/export_sdd_view.xml delete mode 100644 account_direct_debit/README.rst delete mode 100644 account_direct_debit/__init__.py delete mode 100644 account_direct_debit/__openerp__.py delete mode 100644 account_direct_debit/data/account_payment_term.xml delete mode 100644 account_direct_debit/data/payment_mode_type.xml delete mode 100644 account_direct_debit/i18n/account_direct_debit.pot delete mode 100644 account_direct_debit/i18n/es.po delete mode 100644 account_direct_debit/i18n/fr.po delete mode 100644 account_direct_debit/i18n/nl.po delete mode 100644 account_direct_debit/i18n/pt_BR.po delete mode 100644 account_direct_debit/i18n/sl.po delete mode 100644 account_direct_debit/models/__init__.py delete mode 100644 account_direct_debit/models/account_move_line.py delete mode 100644 account_direct_debit/models/payment_line.py delete mode 100644 account_direct_debit/static/description/icon.png delete mode 100644 account_direct_debit/views/account_payment.xml delete mode 100644 account_direct_debit/views/payment_mode.xml delete mode 100644 account_direct_debit/views/payment_mode_type.xml delete mode 100644 account_direct_debit/wizard/__init__.py delete mode 100644 account_direct_debit/wizard/payment_order_create.py create mode 100644 account_payment_mode/README.rst create mode 100644 account_payment_mode/__init__.py create mode 100644 account_payment_mode/__openerp__.py rename account_banking_payment_export/demo/banking_demo.xml => account_payment_mode/demo/payment_demo.xml (50%) create mode 100644 account_payment_mode/models/__init__.py create mode 100644 account_payment_mode/models/account_payment_method.py create mode 100644 account_payment_mode/models/account_payment_mode.py create mode 100644 account_payment_mode/models/res_partner_bank.py create mode 100644 account_payment_mode/security/ir.model.access.csv create mode 100644 account_payment_mode/views/account_payment_method.xml create mode 100644 account_payment_mode/views/account_payment_mode.xml create mode 100644 account_payment_mode/views/res_partner_bank.xml rename {account_banking_payment_export => account_payment_order}/README.rst (100%) rename {account_banking_payment_export => account_payment_order}/__init__.py (100%) rename {account_banking_payment_export => account_payment_order}/__openerp__.py (57%) rename {account_banking_payment_export => account_payment_order}/data/payment_mode_type.xml (100%) create mode 100644 account_payment_order/data/payment_seq.xml create mode 100644 account_payment_order/demo/payment_demo.xml rename {account_banking_payment_export => account_payment_order}/i18n/es.po (100%) rename {account_banking_payment_export => account_payment_order}/i18n/fr.po (100%) rename {account_banking_payment_export => account_payment_order}/i18n/nl.po (100%) rename {account_banking_payment_export => account_payment_order}/i18n/pt_BR.po (100%) rename {account_banking_payment_export => account_payment_order}/i18n/sl.po (100%) rename {account_banking_payment_export => account_payment_order}/migrations/8.0.0.1.166/pre-migrate.py (100%) create mode 100644 account_payment_order/models/__init__.py rename {account_banking_payment_export => account_payment_order}/models/account_invoice.py (80%) create mode 100644 account_payment_order/models/account_move_line.py create mode 100644 account_payment_order/models/account_payment_line.py create mode 100644 account_payment_order/models/account_payment_mode.py create mode 100644 account_payment_order/models/account_payment_order.py create mode 100644 account_payment_order/models/bank_payment_line.py rename account_banking_payment_export/models/res_partner_bank.py => account_payment_order/models/res_bank.py (52%) create mode 100644 account_payment_order/security/ir.model.access.csv create mode 100644 account_payment_order/security/payment_security.xml rename {account_banking_payment_export => account_payment_order}/static/description/icon.png (100%) create mode 100644 account_payment_order/views/account_move_line.xml create mode 100644 account_payment_order/views/account_payment_line.xml create mode 100644 account_payment_order/views/account_payment_mode.xml create mode 100644 account_payment_order/views/account_payment_order.xml rename {account_banking_payment_export => account_payment_order}/views/bank_payment_line.xml (58%) create mode 100644 account_payment_order/views/ir_attachment.xml rename {account_banking_payment_export => account_payment_order}/views/payment_order_create_view.xml (100%) create mode 100644 account_payment_order/wizard/__init__.py rename account_banking_payment_export/wizard/payment_order_create.py => account_payment_order/wizard/account_payment_line_create.py (55%) create mode 100644 account_payment_order/wizard/account_payment_line_create_view.xml create mode 100644 account_payment_partner/models/account_move_line.py delete mode 100644 account_payment_partner/models/payment_mode.py delete mode 100644 account_payment_partner/security/ir.model.access.csv create mode 100644 account_payment_partner/views/account_move_line.xml delete mode 100644 account_payment_partner/views/payment_mode.xml delete mode 100644 account_payment_partner/wizard/__init__.py delete mode 100644 account_payment_partner/wizard/payment_order_create.py delete mode 100644 account_payment_partner/wizard/payment_order_create_view.xml diff --git a/account_banking_mandate/__openerp__.py b/account_banking_mandate/__openerp__.py index cd91e8219..1fff79f66 100644 --- a/account_banking_mandate/__openerp__.py +++ b/account_banking_mandate/__openerp__.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # © 2014 Compassion CH - Cyril Sester # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # 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, } diff --git a/account_banking_mandate/data/mandate_reference_sequence.xml b/account_banking_mandate/data/mandate_reference_sequence.xml index 9a51db944..e3df03051 100644 --- a/account_banking_mandate/data/mandate_reference_sequence.xml +++ b/account_banking_mandate/data/mandate_reference_sequence.xml @@ -3,11 +3,6 @@ - - DD Mandate Reference - account.banking.mandate - - DD Mandate Reference account.banking.mandate diff --git a/account_banking_mandate/models/__init__.py b/account_banking_mandate/models/__init__.py index cb0da2fd5..646eec280 100644 --- a/account_banking_mandate/models/__init__.py +++ b/account_banking_mandate/models/__init__.py @@ -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 diff --git a/account_banking_mandate/models/account_banking_mandate.py b/account_banking_mandate/models/account_banking_mandate.py index 835ad3104..b723aa921 100644 --- a/account_banking_mandate/models/account_banking_mandate.py +++ b/account_banking_mandate/models/account_banking_mandate.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- # © 2014 Compassion CH - Cyril Sester # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # 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 diff --git a/account_banking_mandate/models/account_invoice.py b/account_banking_mandate/models/account_invoice.py index dd04f1a2a..771150c2d 100644 --- a/account_banking_mandate/models/account_invoice.py +++ b/account_banking_mandate/models/account_invoice.py @@ -1,10 +1,11 @@ # -*- coding: utf-8 -*- # © 2014 Compassion CH - Cyril Sester # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza +# © 2016 Akretion (Alexis de Lattre ) # 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 diff --git a/account_banking_mandate/models/account_move_line.py b/account_banking_mandate/models/account_move_line.py new file mode 100644 index 000000000..142bebf4e --- /dev/null +++ b/account_banking_mandate/models/account_move_line.py @@ -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 diff --git a/account_banking_mandate/models/payment_line.py b/account_banking_mandate/models/account_payment_line.py similarity index 65% rename from account_banking_mandate/models/payment_line.py rename to account_banking_mandate/models/account_payment_line.py index 96bd73f41..7083d3352 100644 --- a/account_banking_mandate/models/payment_line.py +++ b/account_banking_mandate/models/account_payment_line.py @@ -1,19 +1,21 @@ # -*- coding: utf-8 -*- # © 2014 Compassion CH - Cyril Sester # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # 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 ? diff --git a/account_banking_mandate/models/bank_payment_line.py b/account_banking_mandate/models/bank_payment_line.py index 4952c17a0..8dd2cbdc8 100644 --- a/account_banking_mandate/models/bank_payment_line.py +++ b/account_banking_mandate/models/bank_payment_line.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # © 2014 Compassion CH - Cyril Sester # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import models, fields, api diff --git a/account_banking_mandate/security/ir.model.access.csv b/account_banking_mandate/security/ir.model.access.csv index f89130b3f..e4d9c40fc 100644 --- a/account_banking_mandate/security/ir.model.access.csv +++ b/account_banking_mandate/security/ir.model.access.csv @@ -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 \ No newline at end of file +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 diff --git a/account_banking_mandate/views/account_banking_mandate_view.xml b/account_banking_mandate/views/account_banking_mandate_view.xml index f91c35bd3..a7112cc0f 100644 --- a/account_banking_mandate/views/account_banking_mandate_view.xml +++ b/account_banking_mandate/views/account_banking_mandate_view.xml @@ -101,33 +101,11 @@ - - - Mandate Validated - account.banking.mandate - - Banking Mandate Validated - - - - Mandate Expired - account.banking.mandate - - Banking Mandate has Expired - - - - Mandate Cancelled - account.banking.mandate - - Banking Mandate Cancelled - - diff --git a/account_banking_mandate/views/account_invoice_view.xml b/account_banking_mandate/views/account_invoice_view.xml index a21e83857..e562c8118 100644 --- a/account_banking_mandate/views/account_invoice_view.xml +++ b/account_banking_mandate/views/account_invoice_view.xml @@ -1,6 +1,6 @@ @@ -10,10 +10,10 @@ add.mandate.on.customer.invoice.form account.invoice - + - + diff --git a/account_banking_mandate/views/account_move_line.xml b/account_banking_mandate/views/account_move_line.xml new file mode 100644 index 000000000..69d51471d --- /dev/null +++ b/account_banking_mandate/views/account_move_line.xml @@ -0,0 +1,26 @@ + + + + + + + + + account_banking_mandate.move_line_form + account.move.line + + + + + + + + + + + diff --git a/account_banking_mandate/views/account_payment_line.xml b/account_banking_mandate/views/account_payment_line.xml new file mode 100644 index 000000000..48e6a753f --- /dev/null +++ b/account_banking_mandate/views/account_payment_line.xml @@ -0,0 +1,37 @@ + + + + + + + account_banking_mandate.account.payment.line.form + account.payment.line + + + + + + + + + + account_banking_mandate.account.payment.line.tree + account.payment.line + + + + + + + + + + diff --git a/account_banking_mandate/views/account_payment_view.xml b/account_banking_mandate/views/account_payment_view.xml deleted file mode 100644 index 9d2ced2cf..000000000 --- a/account_banking_mandate/views/account_payment_view.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - mandate.payment.order.form - payment.order - - - - - - - - - - - - - - diff --git a/account_banking_mandate/views/bank_payment_line_view.xml b/account_banking_mandate/views/bank_payment_line_view.xml index 25c8656e5..98ec669a1 100644 --- a/account_banking_mandate/views/bank_payment_line_view.xml +++ b/account_banking_mandate/views/bank_payment_line_view.xml @@ -1,6 +1,6 @@ @@ -10,11 +10,11 @@ banking.mandate.bank.payment.line.form bank.payment.line - + - + + invisible="context.get('default_payment_type')!='inbound'"/> @@ -22,11 +22,11 @@ banking.mandate.bank.payment.line.tree bank.payment.line - + - + + invisible="context.get('default_payment_type')!='inbound'"/> diff --git a/account_banking_mandate/views/res_partner_bank_view.xml b/account_banking_mandate/views/res_partner_bank_view.xml index 572fa766e..60f9cbce1 100644 --- a/account_banking_mandate/views/res_partner_bank_view.xml +++ b/account_banking_mandate/views/res_partner_bank_view.xml @@ -1,6 +1,6 @@ @@ -12,8 +12,8 @@ res.partner.bank - - + + @@ -26,23 +26,10 @@ - + - - - mandate.partner.form - res.partner - - - - - - - - diff --git a/account_banking_pain_base/__openerp__.py b/account_banking_pain_base/__openerp__.py index 1e129f554..809182e29 100644 --- a/account_banking_pain_base/__openerp__.py +++ b/account_banking_pain_base/__openerp__.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2013-2015 Akretion - Alexis de Lattre +# © 2013-2016 Akretion - Alexis de Lattre # © 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 '], '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, } diff --git a/account_banking_pain_base/models/__init__.py b/account_banking_pain_base/models/__init__.py index ffc2334f3..caf442d40 100644 --- a/account_banking_pain_base/models/__init__.py +++ b/account_banking_pain_base/models/__init__.py @@ -1,10 +1,12 @@ # -*- coding: utf-8 -*- -# © 2013 Akretion - Alexis de Lattre +# © 2013-2016 Akretion - Alexis de Lattre # 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 diff --git a/account_banking_pain_base/models/account_payment_line.py b/account_banking_pain_base/models/account_payment_line.py new file mode 100644 index 000000000..da183051c --- /dev/null +++ b/account_banking_pain_base/models/account_payment_line.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# © 2013-2016 Akretion - Alexis de Lattre +# © 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')]) diff --git a/account_banking_pain_base/models/account_payment_method.py b/account_banking_pain_base/models/account_payment_method.py new file mode 100644 index 000000000..90b485fa0 --- /dev/null +++ b/account_banking_pain_base/models/account_payment_method.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# 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) diff --git a/account_banking_pain_base/models/payment_mode.py b/account_banking_pain_base/models/account_payment_mode.py similarity index 69% rename from account_banking_pain_base/models/payment_mode.py rename to account_banking_pain_base/models/account_payment_mode.py index 832ff2bc9..48febc536 100644 --- a/account_banking_pain_base/models/payment_mode.py +++ b/account_banking_pain_base/models/account_payment_mode.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2013-2015 Akretion - Alexis de Lattre +# © 2013-2016 Akretion - Alexis de Lattre # © 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() diff --git a/account_banking_pain_base/models/account_payment_order.py b/account_banking_pain_base/models/account_payment_order.py new file mode 100644 index 000000000..a7e7106b9 --- /dev/null +++ b/account_banking_pain_base/models/account_payment_order.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# © 2013-2016 Akretion - Alexis de Lattre +# © 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 diff --git a/account_banking_pain_base/models/bank_payment_line.py b/account_banking_pain_base/models/bank_payment_line.py index e67a46be6..7885d701a 100644 --- a/account_banking_pain_base/models/bank_payment_line.py +++ b/account_banking_pain_base/models/bank_payment_line.py @@ -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 diff --git a/account_banking_pain_base/models/banking_export_pain.py b/account_banking_pain_base/models/banking_export_pain.py index c25229c42..af178327d 100644 --- a/account_banking_pain_base/models/banking_export_pain.py +++ b/account_banking_pain_base/models/banking_export_pain.py @@ -1,17 +1,16 @@ # -*- coding: utf-8 -*- -# © 2013-2015 Akretion - Alexis de Lattre +# © 2013-2016 Akretion - Alexis de Lattre # © 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', diff --git a/account_banking_pain_base/models/payment_line.py b/account_banking_pain_base/models/payment_line.py deleted file mode 100644 index 70f214721..000000000 --- a/account_banking_pain_base/models/payment_line.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2013-2015 Akretion - Alexis de Lattre -# © 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') diff --git a/account_banking_pain_base/post_install.py b/account_banking_pain_base/post_install.py index 90e46fec2..14a9259f9 100644 --- a/account_banking_pain_base/post_install.py +++ b/account_banking_pain_base/post_install.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). diff --git a/account_banking_pain_base/views/account_payment_line.xml b/account_banking_pain_base/views/account_payment_line.xml new file mode 100644 index 000000000..6adab6916 --- /dev/null +++ b/account_banking_pain_base/views/account_payment_line.xml @@ -0,0 +1,22 @@ + + + + + + + pain.base.account.payment.line + account.payment.line + + + + + + + + + + diff --git a/account_banking_pain_base/views/account_payment_method.xml b/account_banking_pain_base/views/account_payment_method.xml new file mode 100644 index 000000000..7a9e65982 --- /dev/null +++ b/account_banking_pain_base/views/account_payment_method.xml @@ -0,0 +1,30 @@ + + + + + + + pain_base.account_payment_method.form + account.payment.method + + + + + + + + + + pain_base.account_payment_method.tree + account.payment.method + + + + + + + + + + + diff --git a/account_banking_pain_base/views/account_payment_mode.xml b/account_banking_pain_base/views/account_payment_mode.xml new file mode 100644 index 000000000..d92a5e786 --- /dev/null +++ b/account_banking_pain_base/views/account_payment_mode.xml @@ -0,0 +1,30 @@ + + + + + + + + pain_base.account.payment.mode.form + account.payment.mode + + + + + + + + + + + + + + + + diff --git a/account_banking_pain_base/views/account_payment_order.xml b/account_banking_pain_base/views/account_payment_order.xml new file mode 100644 index 000000000..e99928637 --- /dev/null +++ b/account_banking_pain_base/views/account_payment_order.xml @@ -0,0 +1,24 @@ + + + + + + + pain.base.account.payment.order.form + account.payment.order + + + + + + + + + + + + diff --git a/account_banking_pain_base/views/bank_payment_line_view.xml b/account_banking_pain_base/views/bank_payment_line_view.xml index 65e993ad6..17d4e3049 100644 --- a/account_banking_pain_base/views/bank_payment_line_view.xml +++ b/account_banking_pain_base/views/bank_payment_line_view.xml @@ -1,6 +1,6 @@ @@ -10,14 +10,11 @@ pain.base.bank.payment.line.form bank.payment.line - + - + - - - diff --git a/account_banking_pain_base/views/payment_line_view.xml b/account_banking_pain_base/views/payment_line_view.xml deleted file mode 100644 index 03759b568..000000000 --- a/account_banking_pain_base/views/payment_line_view.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - pain.base.payment.line.inside.order.form - payment.order - - - - - - - - - - - - - - diff --git a/account_banking_pain_base/views/payment_mode_view.xml b/account_banking_pain_base/views/payment_mode_view.xml deleted file mode 100644 index 3ab148671..000000000 --- a/account_banking_pain_base/views/payment_mode_view.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - add.convert_to_ascii.in.payment.mode.form - payment.mode - - - - - - - - - - - - - - - - - - - diff --git a/account_banking_payment_export/data/bank_payment_line_seq.xml b/account_banking_payment_export/data/bank_payment_line_seq.xml deleted file mode 100644 index 37c572bf7..000000000 --- a/account_banking_payment_export/data/bank_payment_line_seq.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - Bank Payment Line - bank.payment.line - - - - Bank Payment Line - bank.payment.line - L - 5 - 1 - - - - - diff --git a/account_banking_payment_export/models/__init__.py b/account_banking_payment_export/models/__init__.py deleted file mode 100644 index f9da02f9f..000000000 --- a/account_banking_payment_export/models/__init__.py +++ /dev/null @@ -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 diff --git a/account_banking_payment_export/models/account_move_line.py b/account_banking_payment_export/models/account_move_line.py deleted file mode 100644 index 6e57cef19..000000000 --- a/account_banking_payment_export/models/account_move_line.py +++ /dev/null @@ -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 diff --git a/account_banking_payment_export/models/account_payment.py b/account_banking_payment_export/models/account_payment.py deleted file mode 100644 index 2508b8804..000000000 --- a/account_banking_payment_export/models/account_payment.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2009 EduSense BV () -# © 2011-2013 Therp BV () -# © 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 diff --git a/account_banking_payment_export/models/bank_payment_line.py b/account_banking_payment_export/models/bank_payment_line.py deleted file mode 100644 index 4de0508c1..000000000 --- a/account_banking_payment_export/models/bank_payment_line.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2015 Akretion - Alexis de Lattre -# 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) diff --git a/account_banking_payment_export/models/payment_line.py b/account_banking_payment_export/models/payment_line.py deleted file mode 100644 index 98b4fc600..000000000 --- a/account_banking_payment_export/models/payment_line.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2015 Akretion - Alexis de Lattre -# 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 diff --git a/account_banking_payment_export/models/payment_mode.py b/account_banking_payment_export/models/payment_mode.py deleted file mode 100644 index 152acf0b3..000000000 --- a/account_banking_payment_export/models/payment_mode.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2009 EduSense BV () -# © 2011-2013 Therp BV () -# © 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)] diff --git a/account_banking_payment_export/models/payment_mode_type.py b/account_banking_payment_export/models/payment_mode_type.py deleted file mode 100644 index 6dfcb4926..000000000 --- a/account_banking_payment_export/models/payment_mode_type.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2009 EduSense BV () -# © 2011-2013 Therp BV () -# © 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 diff --git a/account_banking_payment_export/security/ir.model.access.csv b/account_banking_payment_export/security/ir.model.access.csv deleted file mode 100644 index 3bcb21020..000000000 --- a/account_banking_payment_export/security/ir.model.access.csv +++ /dev/null @@ -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 diff --git a/account_banking_payment_export/views/account_payment.xml b/account_banking_payment_export/views/account_payment.xml deleted file mode 100644 index 8884061a8..000000000 --- a/account_banking_payment_export/views/account_payment.xml +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - account.payment.order.form.banking-1 - - payment.order - - - launch_wizard - - - - - - - - { - 'invisible': [('state', '!=', 'draft')]} - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
- -
- - - -
-
-
-
- - - account_banking_payment_export.payment.order.tree - - payment.order - - - - - - - -
-
diff --git a/account_banking_payment_export/views/bank_payment_manual.xml b/account_banking_payment_export/views/bank_payment_manual.xml deleted file mode 100644 index e350c9b6f..000000000 --- a/account_banking_payment_export/views/bank_payment_manual.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Form for manual payment wizard - payment.manual - -
-
-
-
-
diff --git a/account_banking_payment_export/views/payment_mode.xml b/account_banking_payment_export/views/payment_mode.xml deleted file mode 100644 index 93f616a4a..000000000 --- a/account_banking_payment_export/views/payment_mode.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - payment.mode.form.inherit - payment.mode - - - - - - - - -
- - - - - - - - - - - - -
-
-
- -
-
diff --git a/account_banking_payment_export/views/payment_mode_type.xml b/account_banking_payment_export/views/payment_mode_type.xml deleted file mode 100644 index 4ca3acac7..000000000 --- a/account_banking_payment_export/views/payment_mode_type.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - payment.mode.tree.inherit - payment.mode - - - - - - - - - - - view.payment.mode.type.form - payment.mode.type - -
- - - - - - - - - - - - - -
-
-
- - - view.payment.mode.type.tree - payment.mode.type - - - - - - - - - - - - Payment Export Types - payment.mode.type - form - tree,form - {'active_test': False} - - - - -
-
diff --git a/account_banking_payment_export/wizard/__init__.py b/account_banking_payment_export/wizard/__init__.py deleted file mode 100644 index f30ac09dd..000000000 --- a/account_banking_payment_export/wizard/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -from . import payment_order_create -from . import bank_payment_manual diff --git a/account_banking_payment_export/wizard/bank_payment_manual.py b/account_banking_payment_export/wizard/bank_payment_manual.py deleted file mode 100644 index c2ca42573..000000000 --- a/account_banking_payment_export/wizard/bank_payment_manual.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2009 EduSense BV (). -# (C) 2011 - 2013 Therp BV (). -# -# 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 . -# -############################################################################## - -"""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'} diff --git a/account_banking_payment_export/wizard/bank_payment_manual.xml b/account_banking_payment_export/wizard/bank_payment_manual.xml deleted file mode 100644 index e350c9b6f..000000000 --- a/account_banking_payment_export/wizard/bank_payment_manual.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - Form for manual payment wizard - payment.manual - -
-
-
-
-
diff --git a/account_banking_payment_export/wizard/payment_order_create_view.xml b/account_banking_payment_export/wizard/payment_order_create_view.xml deleted file mode 100644 index 3f07fd4d5..000000000 --- a/account_banking_payment_export/wizard/payment_order_create_view.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - payment.order.create.form.export - payment.order.create - - - - - - - - - - - - - {'required': [('date_type', '=', 'due')], 'invisible': [('date_type', '!=', 'due')]} - - - - - - add.context.to.display.maturity.date - payment.order.create - - - - {'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'} - 1 - - - - - - payment.order.populate.account.move.line.tree - account.move.line - - - - - - - - - - - - - - - - - - - - - - - diff --git a/account_banking_payment_export/workflow/account_payment.xml b/account_banking_payment_export/workflow/account_payment.xml deleted file mode 100644 index 7528a75a4..000000000 --- a/account_banking_payment_export/workflow/account_payment.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - action_done() - - - - action_cancel() - - - - diff --git a/account_banking_sepa_credit_transfer/__init__.py b/account_banking_sepa_credit_transfer/__init__.py index 31b508d85..711d83d4a 100644 --- a/account_banking_sepa_credit_transfer/__init__.py +++ b/account_banking_sepa_credit_transfer/__init__.py @@ -2,4 +2,3 @@ # © 2010-2013 Akretion (www.akretion.com) from . import models -from . import wizard diff --git a/account_banking_sepa_credit_transfer/__openerp__.py b/account_banking_sepa_credit_transfer/__openerp__.py index 8621dc6a2..e3adba80e 100644 --- a/account_banking_sepa_credit_transfer/__openerp__.py +++ b/account_banking_sepa_credit_transfer/__openerp__.py @@ -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, } diff --git a/account_banking_sepa_credit_transfer/data/account_payment_method.xml b/account_banking_sepa_credit_transfer/data/account_payment_method.xml new file mode 100644 index 000000000..36a8961c8 --- /dev/null +++ b/account_banking_sepa_credit_transfer/data/account_payment_method.xml @@ -0,0 +1,15 @@ + + + + + + + SEPA Credit Transfer to suppliers + sepa_credit_transfer + outbound + pain.001.001.03 + + + + + diff --git a/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml b/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml deleted file mode 100644 index dac1fffa7..000000000 --- a/account_banking_sepa_credit_transfer/data/payment_type_sepa_sct.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - SEPA Credit Transfer v05 - pain.001.001.05 - payment - - - - - - SEPA Credit Transfer v04 - pain.001.001.04 - payment - - - - - - SEPA Credit Transfer v03 (recommended) - pain.001.001.03 - payment - - - - - - SEPA Credit Transfer v02 - pain.001.001.02 - payment - - - - - - SEPA Credit Transfer pain 001.003.03 (used in Germany) - pain.001.003.03 - payment - - - - - - diff --git a/account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml b/account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml index 48e69a780..4b39a6779 100644 --- a/account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml +++ b/account_banking_sepa_credit_transfer/demo/sepa_credit_transfer_demo.xml @@ -3,13 +3,12 @@ - - SEPA Credit Transfer La Banque Postale - - + + SEPA Credit Transfer to suppliers - - + variable + + diff --git a/account_banking_sepa_credit_transfer/models/__init__.py b/account_banking_sepa_credit_transfer/models/__init__.py index b67eb49ee..105896fa3 100644 --- a/account_banking_sepa_credit_transfer/models/__init__.py +++ b/account_banking_sepa_credit_transfer/models/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- -from . import payment_mode +from . import account_payment_method +from . import account_payment_order diff --git a/account_banking_sepa_credit_transfer/models/account_payment_method.py b/account_banking_sepa_credit_transfer/models/account_payment_method.py new file mode 100644 index 000000000..d29411049 --- /dev/null +++ b/account_banking_sepa_credit_transfer/models/account_payment_method.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# 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() diff --git a/account_banking_sepa_credit_transfer/wizard/export_sepa.py b/account_banking_sepa_credit_transfer/models/account_payment_order.py similarity index 52% rename from account_banking_sepa_credit_transfer/wizard/export_sepa.py rename to account_banking_sepa_credit_transfer/models/account_payment_order.py index e0e475fb9..4babb602f 100644 --- a/account_banking_sepa_credit_transfer/wizard/export_sepa.py +++ b/account_banking_sepa_credit_transfer/models/account_payment_order.py @@ -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) diff --git a/account_banking_sepa_credit_transfer/models/payment_mode.py b/account_banking_sepa_credit_transfer/models/payment_mode.py deleted file mode 100644 index 8308c5f8e..000000000 --- a/account_banking_sepa_credit_transfer/models/payment_mode.py +++ /dev/null @@ -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 diff --git a/account_banking_sepa_credit_transfer/wizard/__init__.py b/account_banking_sepa_credit_transfer/wizard/__init__.py deleted file mode 100644 index fb941b55c..000000000 --- a/account_banking_sepa_credit_transfer/wizard/__init__.py +++ /dev/null @@ -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 diff --git a/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml b/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml deleted file mode 100644 index 38ab4b7a1..000000000 --- a/account_banking_sepa_credit_transfer/wizard/export_sepa_view.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - banking.export.sepa.wizard.view - banking.export.sepa.wizard - -
- - - - - - - - - - - -
-
- -
-
- -
-
diff --git a/account_banking_sepa_direct_debit/__init__.py b/account_banking_sepa_direct_debit/__init__.py index b4a69d367..cde864bae 100644 --- a/account_banking_sepa_direct_debit/__init__.py +++ b/account_banking_sepa_direct_debit/__init__.py @@ -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 diff --git a/account_banking_sepa_direct_debit/__openerp__.py b/account_banking_sepa_direct_debit/__openerp__.py index 7f7de6752..4898c90d5 100644 --- a/account_banking_sepa_direct_debit/__openerp__.py +++ b/account_banking_sepa_direct_debit/__openerp__.py @@ -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, } diff --git a/account_banking_sepa_direct_debit/data/account_payment_method.xml b/account_banking_sepa_direct_debit/data/account_payment_method.xml new file mode 100644 index 000000000..d2ef66bfd --- /dev/null +++ b/account_banking_sepa_direct_debit/data/account_payment_method.xml @@ -0,0 +1,15 @@ + + + + + + + SEPA Direct Debit for customers + sepa_direct_debit + inbound + pain.008.001.02 + + + + + diff --git a/account_banking_sepa_direct_debit/data/mandate_expire_cron.xml b/account_banking_sepa_direct_debit/data/mandate_expire_cron.xml index 48fe6fc63..fc411dacf 100644 --- a/account_banking_sepa_direct_debit/data/mandate_expire_cron.xml +++ b/account_banking_sepa_direct_debit/data/mandate_expire_cron.xml @@ -1,7 +1,7 @@ diff --git a/account_banking_sepa_direct_debit/data/pain.008.003.02.xsd b/account_banking_sepa_direct_debit/data/pain.008.003.02.xsd new file mode 100644 index 000000000..99992b5e2 --- /dev/null +++ b/account_banking_sepa_direct_debit/data/pain.008.003.02.xsd @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mandatory if changes occur in ‘Mandate Identification’, otherwise not to be used. + + + + + Mandatory if changes occur in 'Creditor Scheme Identification', otherwise not to be used. + + + + + To be used only for changes of accounts within the same bank. + + + + + 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’. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + It is recommended that this element be specified at ‘Payment Information’ level. + + + + + + This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level. + + + + + + + + Mandatory if provided by the debtor in the mandate. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Mandatory if 'Amendment Indicator' is 'TRUE' +The reason code from the Rulebook is indicated using one of the following message subelements. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Either ‘BIC or BEI’ or one +occurrence of ‘Other’ is allowed. + + + + + Either ‘Date and Place of Birth’ or one occurrence of ‘Other’ is allowed + + + + + + + + + + Private Identification is used to identify either an organisation or a private +person. + + + + + + + + + ‘Name’ is limited to 70 characters in length. + + + + + + + + + + ‘Name’ is limited to 70 characters in length. + + + + + + + + + + + + + + + + If present the new’ Name’ must be specified under ‘Creditor’. ‘Name’ is limited to 70 characters in length. + + + + + + + + + + ‘Name’ is limited to 70 characters in length. + + + + + + + + + + + + + + + + + + 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. + + + + + + + + + + + + This data element may be present either at ‘Payment Information’ or at ‘Direct Debit Transaction Information’ level. + + + + + It is recommended that this element be specified at ‘Payment Information’ level. + + + + + 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. + + + + + + + + + + + + + + + + Only ‘B2B’, 'CORE' or 'COR1' is allowed. The mixing of different Local Instrument values is not allowed in the same message. + + + + + If 'Amendment Indicator' is 'true' and 'Original Debtor Agent' is set to 'SMNDA' this message element must indicate 'FRST' + + + + + Depending on the agreement between the Creditor and the Creditor Bank, ‘Category Purpose’ may be forwarded to the Debtor Bank. + + + + + + + + + + + + + + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Only codes from the ISO 20022 ExternalPurposeCode list are allowed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + When present, the receiving bank is not obliged to validate the reference information. + + + + + + + + + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/data/payment_type_sdd.xml b/account_banking_sepa_direct_debit/data/payment_type_sdd.xml deleted file mode 100644 index a17b3b21c..000000000 --- a/account_banking_sepa_direct_debit/data/payment_type_sdd.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - SEPA Direct Debit v02 (recommended) - pain.008.001.02 - - - debit - - - - SEPA Direct Debit v03 - pain.008.001.03 - - - debit - - - - SEPA Direct Debit v04 - pain.008.001.04 - - - debit - - - - - diff --git a/account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml b/account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml index bcbeb7fb8..8c312cde5 100644 --- a/account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml +++ b/account_banking_sepa_direct_debit/demo/sepa_direct_debit_demo.xml @@ -3,13 +3,11 @@ - - SEPA Direct Debit La Banque Postale - - + + SEPA Direct Debit of customers - - + variable + @@ -18,7 +16,7 @@ - + sepa recurrent first @@ -27,7 +25,7 @@ - + sepa recurrent first diff --git a/account_banking_sepa_direct_debit/models/__init__.py b/account_banking_sepa_direct_debit/models/__init__.py index 93fb91cc8..5c9be9f71 100644 --- a/account_banking_sepa_direct_debit/models/__init__.py +++ b/account_banking_sepa_direct_debit/models/__init__.py @@ -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 diff --git a/account_banking_sepa_direct_debit/models/account_banking_mandate.py b/account_banking_sepa_direct_debit/models/account_banking_mandate.py index ca2381204..2c065b4ef 100644 --- a/account_banking_sepa_direct_debit/models/account_banking_mandate.py +++ b/account_banking_sepa_direct_debit/models/account_banking_mandate.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2013 Akretion - Alexis de Lattre +# © 2013-2016 Akretion - Alexis de Lattre # © 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 diff --git a/account_banking_sepa_direct_debit/models/account_payment_method.py b/account_banking_sepa_direct_debit/models/account_payment_method.py new file mode 100644 index 000000000..5a9327b19 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/account_payment_method.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# 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() diff --git a/account_banking_sepa_direct_debit/models/payment_mode.py b/account_banking_sepa_direct_debit/models/account_payment_mode.py similarity index 70% rename from account_banking_sepa_direct_debit/models/payment_mode.py rename to account_banking_sepa_direct_debit/models/account_payment_mode.py index f3c1ac1b6..0650736d0 100644 --- a/account_banking_sepa_direct_debit/models/payment_mode.py +++ b/account_banking_sepa_direct_debit/models/account_payment_mode.py @@ -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) diff --git a/account_banking_sepa_direct_debit/models/account_payment_order.py b/account_banking_sepa_direct_debit/models/account_payment_order.py new file mode 100644 index 000000000..fdea2b052 --- /dev/null +++ b/account_banking_sepa_direct_debit/models/account_payment_order.py @@ -0,0 +1,298 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# 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) diff --git a/account_banking_sepa_direct_debit/models/bank_payment_line.py b/account_banking_sepa_direct_debit/models/bank_payment_line.py index e28207ebc..5eb0b26b7 100644 --- a/account_banking_sepa_direct_debit/models/bank_payment_line.py +++ b/account_banking_sepa_direct_debit/models/bank_payment_line.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import models, api diff --git a/account_banking_sepa_direct_debit/models/common.py b/account_banking_sepa_direct_debit/models/common.py index dd507a4db..83f7bfa03 100644 --- a/account_banking_sepa_direct_debit/models/common.py +++ b/account_banking_sepa_direct_debit/models/common.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# © 2013 Akretion (www.akretion.com) +# © 2013-2016 Akretion (Alexis de Lattre ) # © 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). diff --git a/account_banking_sepa_direct_debit/models/res_company.py b/account_banking_sepa_direct_debit/models/res_company.py index c57dc8b04..ac58eb42f 100644 --- a/account_banking_sepa_direct_debit/models/res_company.py +++ b/account_banking_sepa_direct_debit/models/res_company.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- -# © 2013 Akretion (www.akretion.com) +# © 2013-2016 Akretion (Alexis de Lattre ) # © 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) diff --git a/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml b/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml deleted file mode 100644 index e6a8570cf..000000000 --- a/account_banking_sepa_direct_debit/security/original_mandate_required_security.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - Original Mandate Required (SEPA) - - - - - diff --git a/account_banking_sepa_direct_debit/views/account_banking_mandate_view.xml b/account_banking_sepa_direct_debit/views/account_banking_mandate_view.xml index 667cedb54..7d8d73312 100644 --- a/account_banking_sepa_direct_debit/views/account_banking_mandate_view.xml +++ b/account_banking_sepa_direct_debit/views/account_banking_mandate_view.xml @@ -1,6 +1,6 @@ @@ -11,7 +11,7 @@ - + sdd.mandate.form account.banking.mandate @@ -25,14 +25,10 @@ - - - - - + sdd.mandate.tree account.banking.mandate @@ -45,7 +41,7 @@ - + sdd.mandate.search account.banking.mandate @@ -66,67 +62,5 @@ - - SEPA Direct Debit Mandates - account.banking.mandate - tree,form - -

- Click to create a new SEPA Direct Debit Mandate. -

- 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. -

-
-
- - - - - sdd.mandate.res.partner.bank.tree - res.partner.bank - - - - SDD Mandates - - - - - - sdd.mandate.partner.form - res.partner - - - - SDD Mandates - - - - - - Sequence Type set to First - account.banking.mandate - - Sequence Type set to First - - - - Sequence Type set to Recurring - account.banking.mandate - - Sequence Type set to Recurring - - - - Sequence Type set to Final - account.banking.mandate - - Sequence Type set to Final - -
diff --git a/account_banking_sepa_direct_debit/views/account_payment_mode.xml b/account_banking_sepa_direct_debit/views/account_payment_mode.xml new file mode 100644 index 000000000..5f41be2f3 --- /dev/null +++ b/account_banking_sepa_direct_debit/views/account_payment_mode.xml @@ -0,0 +1,23 @@ + + + + + + + Add SEPA identifiers on payment mode form + account.payment.mode + + + + + + + + + + + diff --git a/account_banking_sepa_direct_debit/views/payment_mode_view.xml b/account_banking_sepa_direct_debit/views/payment_mode_view.xml deleted file mode 100644 index 9bba891d6..000000000 --- a/account_banking_sepa_direct_debit/views/payment_mode_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - Add SEPA identifiers - payment.mode - - - - - - - - - - - - - diff --git a/account_banking_sepa_direct_debit/views/res_company_view.xml b/account_banking_sepa_direct_debit/views/res_company_view.xml index e4c9e0b93..6b4d544ca 100644 --- a/account_banking_sepa_direct_debit/views/res_company_view.xml +++ b/account_banking_sepa_direct_debit/views/res_company_view.xml @@ -1,20 +1,19 @@ - + sepa_direct_debit.res.company.form res.company - diff --git a/account_banking_sepa_direct_debit/wizard/__init__.py b/account_banking_sepa_direct_debit/wizard/__init__.py deleted file mode 100644 index 3830e36d9..000000000 --- a/account_banking_sepa_direct_debit/wizard/__init__.py +++ /dev/null @@ -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 -# -# 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 . -# -############################################################################## - -from . import export_sdd diff --git a/account_banking_sepa_direct_debit/wizard/export_sdd.py b/account_banking_sepa_direct_debit/wizard/export_sdd.py deleted file mode 100644 index 9b4022d46..000000000 --- a/account_banking_sepa_direct_debit/wizard/export_sdd.py +++ /dev/null @@ -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 -# -# 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 . -# -############################################################################## - - -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 diff --git a/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml b/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml deleted file mode 100644 index 95117e270..000000000 --- a/account_banking_sepa_direct_debit/wizard/export_sdd_view.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - banking.export.sdd.wizard.view - banking.export.sdd.wizard - -
- - - - - - - - - - - -
-
- -
-
- -
-
diff --git a/account_direct_debit/README.rst b/account_direct_debit/README.rst deleted file mode 100644 index 337f4a7ad..000000000 --- a/account_direct_debit/README.rst +++ /dev/null @@ -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 `_. -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 `_. - -Credits -======= - -Contributors ------------- - -* Stefan Rijnhart -* Pedro M. Baeza -* Alexis de Lattre -* Danimar Ribeiro -* Stéphane Bidoul -* 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. diff --git a/account_direct_debit/__init__.py b/account_direct_debit/__init__.py deleted file mode 100644 index 9b4296142..000000000 --- a/account_direct_debit/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import models -from . import wizard diff --git a/account_direct_debit/__openerp__.py b/account_direct_debit/__openerp__.py deleted file mode 100644 index f112d72f2..000000000 --- a/account_direct_debit/__openerp__.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2011 Smile () -# © 2011-2013 Therp BV () -# © 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, -} diff --git a/account_direct_debit/data/account_payment_term.xml b/account_direct_debit/data/account_payment_term.xml deleted file mode 100644 index 61436c117..000000000 --- a/account_direct_debit/data/account_payment_term.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Direct debit - Direct debit in 14 days - - - balance - - - - - - diff --git a/account_direct_debit/data/payment_mode_type.xml b/account_direct_debit/data/payment_mode_type.xml deleted file mode 100644 index bbfd350ae..000000000 --- a/account_direct_debit/data/payment_mode_type.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Manual Direct Debit - MANDDEB - - - debit - - - diff --git a/account_direct_debit/i18n/account_direct_debit.pot b/account_direct_debit/i18n/account_direct_debit.pot deleted file mode 100644 index 191f17bec..000000000 --- a/account_direct_debit/i18n/account_direct_debit.pot +++ /dev/null @@ -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 "" diff --git a/account_direct_debit/i18n/es.po b/account_direct_debit/i18n/es.po deleted file mode 100644 index 10519aa70..000000000 --- a/account_direct_debit/i18n/es.po +++ /dev/null @@ -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')]}" - diff --git a/account_direct_debit/i18n/fr.po b/account_direct_debit/i18n/fr.po deleted file mode 100644 index 21d7e25af..000000000 --- a/account_direct_debit/i18n/fr.po +++ /dev/null @@ -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 "" diff --git a/account_direct_debit/i18n/nl.po b/account_direct_debit/i18n/nl.po deleted file mode 100644 index a75115b6c..000000000 --- a/account_direct_debit/i18n/nl.po +++ /dev/null @@ -1,76 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * account_direct_debit -# -# Translators: -# FIRST AUTHOR , 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 \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 "" diff --git a/account_direct_debit/i18n/pt_BR.po b/account_direct_debit/i18n/pt_BR.po deleted file mode 100644 index 149d12325..000000000 --- a/account_direct_debit/i18n/pt_BR.po +++ /dev/null @@ -1,76 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * account_direct_debit -# -# Translators: -# danimaribeiro , 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 \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')]}" diff --git a/account_direct_debit/i18n/sl.po b/account_direct_debit/i18n/sl.po deleted file mode 100644 index 758c2b2c5..000000000 --- a/account_direct_debit/i18n/sl.po +++ /dev/null @@ -1,76 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * account_direct_debit -# -# Translators: -# Matjaž Mozetič , 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č \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')]}" diff --git a/account_direct_debit/models/__init__.py b/account_direct_debit/models/__init__.py deleted file mode 100644 index cb28fc53b..000000000 --- a/account_direct_debit/models/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -*- coding: utf-8 -*- - -from . import payment_line -from . import account_move_line diff --git a/account_direct_debit/models/account_move_line.py b/account_direct_debit/models/account_move_line.py deleted file mode 100644 index 129b15487..000000000 --- a/account_direct_debit/models/account_move_line.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2011 Smile () -# © 2011-2013 Therp BV () -# © 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) diff --git a/account_direct_debit/models/payment_line.py b/account_direct_debit/models/payment_line.py deleted file mode 100644 index 366f522bc..000000000 --- a/account_direct_debit/models/payment_line.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2011 Smile () -# © 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') diff --git a/account_direct_debit/static/description/icon.png b/account_direct_debit/static/description/icon.png deleted file mode 100644 index 3a0328b516c4980e8e44cdb63fd945757ddd132d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9455 zcmW++2RxMjAAjx~&dlBk9S+%}OXg)AGE&Cb*&}d0jUxM@u(PQx^-s)697TX`ehR4?GS^qbkof1cslKgkU)h65qZ9Oc=ml_0temigYLJfnz{IDzUf>bGs4N!v3=Z3jMq&A#7%rM5eQ#dc?k~! zVpnB`o+K7|Al`Q_U;eD$B zfJtP*jH`siUq~{KE)`jP2|#TUEFGRryE2`i0**z#*^6~AI|YzIWy$Cu#CSLW3q=GA z6`?GZymC;dCPk~rBS%eCb`5OLr;RUZ;D`}um=H)BfVIq%7VhiMr)_#G0N#zrNH|__ zc+blN2UAB0=617@>_u;MPHN;P;N#YoE=)R#i$k_`UAA>WWCcEVMh~L_ zj--gtp&|K1#58Yz*AHCTMziU1Jzt_jG0I@qAOHsk$2}yTmVkBp_eHuY$A9)>P6o~I z%aQ?!(GqeQ-Y+b0I(m9pwgi(IIZZzsbMv+9w{PFtd_<_(LA~0H(xz{=FhLB@(1&qHA5EJw1>>=%q2f&^X>IQ{!GJ4e9U z&KlB)z(84HmNgm2hg2C0>WM{E(DdPr+EeU_N@57;PC2&DmGFW_9kP&%?X4}+xWi)( z;)z%wI5>D4a*5XwD)P--sPkoY(a~WBw;E~AW`Yue4kFa^LM3X`8x|}ZUeMnqr}>kH zG%WWW>3ml$Yez?i%)2pbKPI7?5o?hydokgQyZsNEr{a|mLdt;X2TX(#B1j35xPnPW z*bMSSOauW>o;*=kO8ojw91VX!qoOQb)zHJ!odWB}d+*K?#sY_jqPdg{Sm2HdYzdEx zOGVPhVRTGPtv0o}RfVP;Nd(|CB)I;*t&QO8h zFfekr30S!-LHmV_Su-W+rEwYXJ^;6&3|L$mMC8*bQptyOo9;>Qb9Q9`ySe3%V$A*9 zeKEe+b0{#KWGp$F+tga)0RtI)nhMa-K@JS}2krK~n8vJ=Ngm?R!9G<~RyuU0d?nz# z-5EK$o(!F?hmX*2Yt6+coY`6jGbb7tF#6nHA zuKk=GGJ;ZwON1iAfG$E#Y7MnZVmrY|j0eVI(DN_MNFJmyZ|;w4tf@=CCDZ#5N_0K= z$;R~bbk?}TpfDjfB&aiQ$VA}s?P}xPERJG{kxk5~R`iRS(SK5d+Xs9swCozZISbnS zk!)I0>t=A<-^z(cmSFz3=jZ23u13X><0b)P)^1T_))Kr`e!-pb#q&J*Q`p+B6la%C zuVl&0duN<;uOsB3%T9Fp8t{ED108<+W(nOZd?gDnfNBC3>M8WE61$So|P zVvqH0SNtDTcsUdzaMDpT=Ty0pDHHNL@Z0w$Y`XO z2M-_r1S+GaH%pz#Uy0*w$Vdl=X=rQXEzO}d6J^R6zjM1u&c9vYLvLp?W7w(?np9x1 zE_0JSAJCPB%i7p*Wvg)pn5T`8k3-uR?*NT|J`eS#_#54p>!p(mLDvmc-3o0mX*mp_ zN*AeS<>#^-{S%W<*mz^!X$w_2dHWpcJ6^j64qFBft-o}o_Vx80o0>}Du;>kLts;$8 zC`7q$QI(dKYG`Wa8#wl@V4jVWBRGQ@1dr-hstpQL)Tl+aqVpGpbSfN>5i&QMXfiZ> zaA?T1VGe?rpQ@;+pkrVdd{klI&jVS@I5_iz!=UMpTsa~mBga?1r}aRBm1WS;TT*s0f0lY=JBl66Upy)-k4J}lh=P^8(SXk~0xW=T9v*B|gzIhN z>qsO7dFd~mgxAy4V?&)=5ieYq?zi?ZEoj)&2o)RLy=@hbCRcfT5jigwtQGE{L*8<@Yd{zg;CsL5mvzfDY}P-wos_6PfprFVaeqNE%h zKZhLtcQld;ZD+>=nqN~>GvROfueSzJD&BE*}XfU|H&(FssBqY=hPCt`d zH?@s2>I(|;fcW&YM6#V#!kUIP8$Nkdh0A(bEVj``-AAyYgwY~jB zT|I7Bf@%;7aL7Wf4dZ%VqF$eiaC38OV6oy3Z#TER2G+fOCd9Iaoy6aLYbPTN{XRPz z;U!V|vBf%H!}52L2gH_+j;`bTcQRXB+y9onc^wLm5wi3-Be}U>k_u>2Eg$=k!(l@I zcCg+flakT2Nej3i0yn+g+}%NYb?ta;R?(g5SnwsQ49U8Wng8d|{B+lyRcEDvR3+`O{zfmrmvFrL6acVP%yG98X zo&+VBg@px@i)%o?dG(`T;n*$S5*rnyiR#=wW}}GsAcfyQpE|>a{=$Hjg=-*_K;UtD z#z-)AXwSRY?OPefw^iI+ z)AXz#PfEjlwTes|_{sB?4(O@fg0AJ^g8gP}ex9Ucf*@_^J(s_5jJV}c)s$`Myn|Kd z$6>}#q^n{4vN@+Os$m7KV+`}c%4)4pv@06af4-x5#wj!KKb%caK{A&Y#Rfs z-po?Dcb1({W=6FKIUirH&(yg=*6aLCekcKwyfK^JN5{wcA3nhO(o}SK#!CINhI`-I z1)6&n7O&ZmyFMuNwvEic#IiOAwNkR=u5it{B9n2sAJV5pNhar=j5`*N!Na;c7g!l$ z3aYBqUkqqTJ=Re-;)s!EOeij=7SQZ3Hq}ZRds%IM*PtM$wV z@;rlc*NRK7i3y5BETSKuumEN`Xu_8GP1Ri=OKQ$@I^ko8>H6)4rjiG5{VBM>B|%`&&s^)jS|-_95&yc=GqjNo{zFkw%%HHhS~e=s zD#sfS+-?*t|J!+ozP6KvtOl!R)@@-z24}`9{QaVLD^9VCSR2b`b!KC#o;Ki<+wXB6 zx3&O0LOWcg4&rv4QG0)4yb}7BFSEg~=IR5#ZRj8kg}dS7_V&^%#Do==#`u zpy6{ox?jWuR(;pg+f@mT>#HGWHAJRRDDDv~@(IDw&R>9643kK#HN`!1vBJHnC+RM&yIh8{gG2q zA%e*U3|N0XSRa~oX-3EAneep)@{h2vvd3Xvy$7og(sayr@95+e6~Xvi1tUqnIxoIH zVWo*OwYElb#uyW{Imam6f2rGbjR!Y3`#gPqkv57dB6K^wRGxc9B(t|aYDGS=m$&S!NmCtrMMaUg(c zc2qC=2Z`EEFMW-me5B)24AqF*bV5Dr-M5ig(l-WPS%CgaPzs6p_gnCIvTJ=Y<6!gT zVt@AfYCzjjsMEGi=rDQHo0yc;HqoRNnNFeWZgcm?f;cp(6CNylj36DoL(?TS7eU#+ z7&mfr#y))+CJOXQKUMZ7QIdS9@#-}7y2K1{8)cCt0~-X0O!O?Qx#E4Og+;A2SjalQ zs7r?qn0H044=sDN$SRG$arw~n=+T_DNdSrarmu)V6@|?1-ZB#hRn`uilTGPJ@fqEy zGt(f0B+^JDP&f=r{#Y_wi#AVDf-y!RIXU^0jXsFpf>=Ji*TeqSY!H~AMbJdCGLhC) zn7Rx+sXw6uYj;WRYrLd^5IZq@6JI1C^YkgnedZEYy<&4(z%Q$5yv#Boo{AH8n$a zhb4Y3PWdr269&?V%uI$xMcUrMzl=;w<_nm*qr=c3Rl@i5wWB;e-`t7D&c-mcQl7x! zZWB`UGcw=Y2=}~wzrfLx=uet<;m3~=8I~ZRuzvMQUQdr+yTV|ATf1Uuomr__nDf=X zZ3WYJtHp_ri(}SQAPjv+Y+0=fH4krOP@S&=zZ-t1jW1o@}z;xk8 z(Nz1co&El^HK^NrhVHa-_;&88vTU>_J33=%{if;BEY*J#1n59=07jrGQ#IP>@u#3A z;!q+E1Rj3ZJ+!4bq9F8PXJ@yMgZL;>&gYA0%_Kbi8?S=XGM~dnQZQ!yBSgcZhY96H zrWnU;k)qy`rX&&xlDyA%(a1Hhi5CWkmg(`Gb%m(HKi-7Z!LKGRP_B8@`7&hdDy5n= z`OIxqxiVfX@OX1p(mQu>0Ai*v_cTMiw4qRt3~NBvr9oBy0)r>w3p~V0SCm=An6@3n)>@z!|o-$HvDK z|3D2ZMJkLE5loMKl6R^ez@Zz%S$&mbeoqH5`Bb){Ei21q&VP)hWS2tjShfFtGE+$z zzCR$P#uktu+#!w)cX!lWN1XU%K-r=s{|j?)Akf@q#3b#{6cZCuJ~gCxuMXRmI$nGtnH+-h z+GEi!*X=AP<|fG`1>MBdTb?28JYc=fGvAi2I<$B(rs$;eoJCyR6_bc~p!XR@O-+sD z=eH`-ye})I5ic1eL~TDmtfJ|8`0VJ*Yr=hNCd)G1p2MMz4C3^Mj?7;!w|Ly%JqmuW zlIEW^Ft%z?*|fpXda>Jr^1noFZEwFgVV%|*XhH@acv8rdGxeEX{M$(vG{Zw+x(ei@ zmfXb22}8-?Fi`vo-YVrTH*C?a8%M=Hv9MqVH7H^J$KsD?>!SFZ;ZsvnHr_gn=7acz z#W?0eCdVhVMWN12VV^$>WlQ?f;P^{(&pYTops|btm6aj>_Uz+hqpGwB)vWp0Cf5y< zft8-je~nn?W11plq}N)4A{l8I7$!ks_x$PXW-2XaRFswX_BnF{R#6YIwMhAgd5F9X zGmwdadS6(a^fjHtXg8=l?Rc0Sm%hk6E9!5cLVloEy4eh(=FwgP`)~I^5~pBEWo+F6 zSf2ncyMurJN91#cJTy_u8Y}@%!bq1RkGC~-bV@SXRd4F{R-*V`bS+6;W5vZ(&+I<9$;-V|eNfLa5n-6% z2(}&uGRF;p92eS*sE*oR$@pexaqr*meB)VhmIg@h{uzkk$9~qh#cHhw#>O%)b@+(| z^IQgqzuj~Sk(J;swEM-3TrJAPCq9k^^^`q{IItKBRXYe}e0Tdr=Huf7da3$l4PdpwWDop%^}n;dD#K4s#DYA8SHZ z&1!riV4W4R7R#C))JH1~axJ)RYnM$$lIR%6fIVA@zV{XVyx}C+a-Dt8Y9M)^KU0+H zR4IUb2CJ{Hg>CuaXtD50jB(_Tcx=Z$^WYu2u5kubqmwp%drJ6 z?Fo40g!Qd<-l=TQxqHEOuPX0;^z7iX?Ke^a%XT<13TA^5`4Xcw6D@Ur&VT&CUe0d} z1GjOVF1^L@>O)l@?bD~$wzgf(nxX1OGD8fEV?TdJcZc2KoUe|oP1#=$$7ee|xbY)A zDZq+cuTpc(fFdj^=!;{k03C69lMQ(|>uhRfRu%+!k&YOi-3|1QKB z z?n?eq1XP>p-IM$Z^C;2L3itnbJZAip*Zo0aw2bs8@(s^~*8T9go!%dHcAz2lM;`yp zD=7&xjFV$S&5uDaiScyD?B-i1ze`+CoRtz`Wn+Zl&#s4&}MO{@N!ufrzjG$B79)Y2d3tBk&)TxUTw@QS0TEL_?njX|@vq?Uz(nBFK5Pq7*xj#u*R&i|?7+6# z+|r_n#SW&LXhtheZdah{ZVoqwyT{D>MC3nkFF#N)xLi{p7J1jXlmVeb;cP5?e(=f# zuT7fvjSbjS781v?7{)-X3*?>tq?)Yd)~|1{BDS(pqC zC}~H#WXlkUW*H5CDOo<)#x7%RY)A;ShGhI5s*#cRDA8YgqG(HeKDx+#(ZQ?386dv! zlXCO)w91~Vw4AmOcATuV653fa9R$fyK8ul%rG z-wfS zihugoZyr38Im?Zuh6@RcF~t1anQu7>#lPpb#}4cOA!EM11`%f*07RqOVkmX{p~KJ9 z^zP;K#|)$`^Rb{rnHGH{~>1(fawV0*Z#)}M`m8-?ZJV<+e}s9wE# z)l&az?w^5{)`S(%MRzxdNqrs1n*-=jS^_jqE*5XDrA0+VE`5^*p3CuM<&dZEeCjoz zR;uu_H9ZPZV|fQq`Cyw4nscrVwi!fE6ciMmX$!_hN7uF;jjKG)d2@aC4ropY)8etW=xJvni)8eHi`H$%#zn^WJ5NLc-rqk|u&&4Z6fD_m&JfSI1Bvb?b<*n&sfl0^t z=HnmRl`XrFvMKB%9}>PaA`m-fK6a0(8=qPkWS5bb4=v?XcWi&hRY?O5HdulRi4?fN zlsJ*N-0Qw+Yic@s0(2uy%F@ib;GjXt01Fmx5XbRo6+n|pP(&nodMoap^z{~q ziEeaUT@Mxe3vJSfI6?uLND(CNr=#^W<1b}jzW58bIfyWTDle$mmS(|x-0|2UlX+9k zQ^EX7Nw}?EzVoBfT(-LT|=9N@^hcn-_p&sqG z&*oVs2JSU+N4ZD`FhCAWaS;>|wH2G*Id|?pa#@>tyxX`+4HyIArWDvVrX)2WAOQff z0qyHu&-S@i^MS-+j--!pr4fPBj~_8({~e1bfcl0wI1kaoN>mJL6KUPQm5N7lB(ui1 zE-o%kq)&djzWJ}ob<-GfDlkB;F31j-VHKvQUGQ3sp`CwyGJk_i!y^sD0fqC@$9|jO zOqN!r!8-p==F@ZVP=U$qSpY(gQ0)59P1&t@y?5rvg<}E+GB}26NYPp4f2YFQrQtot5mn3wu_qprZ=>Ig-$ zbW26Ws~IgY>}^5w`vTB(G`PTZaDiGBo5o(tp)qli|NeV( z@H_=R8V39rt5J5YB2Ky?4eJJ#b`_iBe2ot~6%7mLt5t8Vwi^Jy7|jWXqa3amOIoRb zOr}WVFP--DsS`1WpN%~)t3R!arKF^Q$e12KEqU36AWwnCBICpH4XCsfnyrHr>$I$4 z!DpKX$OKLWarN7nv@!uIA+~RNO)l$$w}p(;b>mx8pwYvu;dD_unryX_NhT8*Tj>BTrTTL&!?O+%Rv;b?B??gSzdp?6Uug9{ zd@V08Z$BdI?fpoCS$)t4mg4rT8Q_I}h`0d-vYZ^|dOB*Q^S|xqTV*vIg?@fVFSmMpaw0qtTRbx} z({Pg?#{2`sc9)M5N$*N|4;^t$+QP?#mov zGVC@I*lBVrOU-%2y!7%)fAKjpEFsgQc4{amtiHb95KQEwvf<(3T<9-Zm$xIew#P22 zc2Ix|App^>v6(3L_MCU0d3W##AB0M~3D00EWoKZqsJYT(#@w$Y_H7G22M~ApVFTRHMI_3be)Lkn#0F*V8Pq zc}`Cjy$bE;FJ6H7p=0y#R>`}-m4(0F>%@P|?7fx{=R^uFdISRnZ2W_xQhD{YuR3t< z{6yxu=4~JkeA;|(J6_nv#>Nvs&FuLA&PW^he@t(UwFFE8)|a!R{`E`K`i^ZnyE4$k z;(749Ix|oi$c3QbEJ3b~D_kQsPz~fIUKym($a_7dJ?o+40*OLl^{=&oq$<#Q(yyrp z{J-FAniyAw9tPbe&IhQ|a`DqFTVQGQ&Gq3!C2==4x{6EJwiPZ8zub-iXoUtkJiG{} zPaR&}_fn8_z~(=;5lD-aPWD3z8PZS@AaUiomF!G8I}Mf>e~0g#BelA-5#`cj;O5>N Xviia!U7SGha1wx#SCgwmn*{w2TRX*I diff --git a/account_direct_debit/views/account_payment.xml b/account_direct_debit/views/account_payment.xml deleted file mode 100644 index 3b0977577..000000000 --- a/account_direct_debit/views/account_payment.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - [('payment_order_type', '=', 'payment')] - {'search_payment_order_type': 'payment'} - - - - Direct Debit Orders - payment.order - form - tree,form - {'search_payment_order_type': 'debit', - 'default_payment_order_type': 'debit'} - - [('payment_order_type', '=', 'debit')] - 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. - - - - - - direct.debit.payment.order.form - payment.order - - - - -
-
- - [('payment_order_type', '=', payment_order_type)] - -
-
- -
-
diff --git a/account_direct_debit/views/payment_mode.xml b/account_direct_debit/views/payment_mode.xml deleted file mode 100644 index 043990df0..000000000 --- a/account_direct_debit/views/payment_mode.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - payment.mode.form.inherit - payment.mode - - - - - - - - - - diff --git a/account_direct_debit/views/payment_mode_type.xml b/account_direct_debit/views/payment_mode_type.xml deleted file mode 100644 index 54c14367d..000000000 --- a/account_direct_debit/views/payment_mode_type.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - view.payment.mode.type.tree - payment.mode.type - - - - - - - - - - view.payment.mode.type.form - payment.mode.type - - - - - - - - - - diff --git a/account_direct_debit/wizard/__init__.py b/account_direct_debit/wizard/__init__.py deleted file mode 100644 index cbcdda94a..000000000 --- a/account_direct_debit/wizard/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import payment_order_create diff --git a/account_direct_debit/wizard/payment_order_create.py b/account_direct_debit/wizard/payment_order_create.py deleted file mode 100644 index eedfec69c..000000000 --- a/account_direct_debit/wizard/payment_order_create.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2013 Therp BV () -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from openerp import models, api - - -class PaymentOrderCreate(models.TransientModel): - _inherit = 'payment.order.create' - - @api.multi - def extend_payment_order_domain(self, payment_order, domain): - super(PaymentOrderCreate, self).extend_payment_order_domain( - payment_order, domain) - if payment_order.payment_order_type == 'debit': - # For receivables, propose all unreconciled debit lines, - # including partially reconciled ones. - # If they are partially reconciled with a customer refund, - # the residual will be added to the payment order. - # - # For payables, normally suppliers will be the initiating party - # for possible supplier refunds (via a transfer for example), - # or they keep the amount for decreasing future supplier invoices, - # so there's not too much sense for adding them to a direct debit - # order - domain += [ - ('debit', '>', 0), - ('account_id.type', '=', 'receivable'), - ] - return True diff --git a/account_payment_mode/README.rst b/account_payment_mode/README.rst new file mode 100644 index 000000000..c45ad9156 --- /dev/null +++ b/account_payment_mode/README.rst @@ -0,0 +1,58 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +==================== +Account Payment Mode +==================== + +This module adds a new object *account.payment.mode*. In Odoo v8, this object was part of the *account_payment* module from the official addons, but this module was dropped by the editor in Odoo v9. This object is also designed to replace the *payment.method* object of the *sale\_payment\_method* module of the `e-commerce `_ OCA project in v9. + +Configuration +============= + +To configure this module, you need to go to the menu *Account > Configuration > Management > Payment Mode*. + +Usage +===== + +This module doesn't add any feature, but it is used by several other modules. + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/173/9.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 +`_. + +Credits +======= + +Contributors +------------ + +* Alexis de Lattre + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://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 https://odoo-community.org. diff --git a/account_payment_mode/__init__.py b/account_payment_mode/__init__.py new file mode 100644 index 000000000..cde864bae --- /dev/null +++ b/account_payment_mode/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/account_payment_mode/__openerp__.py b/account_payment_mode/__openerp__.py new file mode 100644 index 000000000..2b229ea39 --- /dev/null +++ b/account_payment_mode/__openerp__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (). +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'Account Payment Mode', + 'version': '9.0.1.0.0', + 'license': 'AGPL-3', + 'author': "Akretion,Odoo Community Association (OCA)", + 'website': 'https://github.com/OCA/bank-payment', + 'category': 'Banking addons', + 'depends': ['account'], + 'data': [ + 'security/ir.model.access.csv', + 'views/account_payment_method.xml', + 'views/account_payment_mode.xml', + 'views/res_partner_bank.xml', + ], + 'demo': ['demo/payment_demo.xml'], + 'installable': True, +} diff --git a/account_banking_payment_export/demo/banking_demo.xml b/account_payment_mode/demo/payment_demo.xml similarity index 50% rename from account_banking_payment_export/demo/banking_demo.xml rename to account_payment_mode/demo/payment_demo.xml index be9cd471b..b105d8c9b 100644 --- a/account_banking_payment_export/demo/banking_demo.xml +++ b/account_payment_mode/demo/payment_demo.xml @@ -1,5 +1,4 @@ - @@ -40,63 +39,68 @@ FR76 4242 4242 4242 4242 4242 424 - iban - + - La Banque Postale - PSSTFRPPXXX FR20 1242 1242 1242 1242 1242 124 - iban - + - Société Générale - SOGEFRPPXXX FR66 1212 1212 1212 1212 1212 121 - iban - + - Fortuneo Banque - FTNOFRP1XXX BE96 9988 7766 5544 - iban - + - BNP Paribas Fortis Charleroi - GEBABEBB03A - - - - - - - Credit Trf Banque Postale - - + + Credit Transfer to Suppliers - - - + variable + - - Credit Trf Société Générale - - + + Direct Debit of suppliers from Société Générale - - - + variable + + + + + Direct Debit of suppliers from La Banque Postale + + variable + + + + + Inbound Credit Trf Société Générale + + variable + + + + + Inbound Credit Trf La Banque Postale + + variable + + + + + Direct Debit of customers + + variable + diff --git a/account_payment_mode/models/__init__.py b/account_payment_mode/models/__init__.py new file mode 100644 index 000000000..a40aa5c9e --- /dev/null +++ b/account_payment_mode/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +from . import account_payment_method +from . import account_payment_mode +from . import res_partner_bank diff --git a/account_payment_mode/models/account_payment_method.py b/account_payment_mode/models/account_payment_method.py new file mode 100644 index 000000000..5387f3843 --- /dev/null +++ b/account_payment_mode/models/account_payment_method.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# 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' + _rec_name = 'display_name' + + code = fields.Char( + string='Code (Do Not Modify)', + help="This code is used in the code of the Odoo module that handle " + "this payment method. Therefore, if you change it, " + "the generation of the payment file may fail.") + active = fields.Boolean(string='Active', default=True) + # In the pain_base module, we will add a default_pain_version + display_name = fields.Char( + compute='compute_display_name', + store=True, string='Display Name') + + @api.multi + @api.depends('code', 'name', 'payment_type') + def compute_display_name(self): + for method in self: + method.display_name = u'[%s] %s (%s)' % ( + method.code, method.name, method.payment_type) + + _sql_constraints = [( + 'code_payment_type_unique', + 'unique(code, payment_type)', + 'A payment method of the same type already exists with this code' + )] diff --git a/account_payment_mode/models/account_payment_mode.py b/account_payment_mode/models/account_payment_mode.py new file mode 100644 index 000000000..f001eefe8 --- /dev/null +++ b/account_payment_mode/models/account_payment_mode.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields, api, _ +from openerp.exceptions import ValidationError + + +class AccountPaymentMode(models.Model): + """This corresponds to the object payment.mode of v8 with some + important changes. It also replaces the object payment.method + of the module sale_payment_method of OCA/e-commerce""" + _name = "account.payment.mode" + _description = 'Payment Modes' + _order = 'name' + + name = fields.Char(string='Name', required=True) + company_id = fields.Many2one( + 'res.company', string='Company', required=True, ondelete='restrict', + default=lambda self: self.env['res.company']._company_default_get( + 'account.payment.mode')) + bank_account_link = fields.Selection([ + ('fixed', 'Fixed'), + ('variable', 'Variable'), + ], string='Link to Bank Account', required=True, + help="For payment modes that are always attached to the same bank " + "account of your company (such as wire transfer from customers or " + "SEPA direct debit from suppliers), select " + "'Fixed'. For payment modes that are not always attached to the same " + "bank account (such as SEPA Direct debit for customers, wire transfer " + "to suppliers), you should choose 'Variable', which means that you " + "will select the bank account on the payment order. If your company " + "only has one bank account, you should always select 'Fixed'.") + fixed_journal_id = fields.Many2one( + 'account.journal', string='Fixed Bank Journal', + domain=[('type', '=', 'bank')], ondelete='restrict') + # I need to use the old definition, because I have 2 M2M fields + # pointing to account.journal + variable_journal_ids = fields.Many2many( + 'account.journal', + 'account_payment_mode_variable_journal_rel', + 'payment_mode_id', 'journal_id', + string='Allowed Bank Journals', + domain=[('type', '=', 'bank')]) + payment_method_id = fields.Many2one( + 'account.payment.method', string='Payment Method', required=True, + ondelete='restrict') # equivalent v8 field : type + payment_type = fields.Selection( + related='payment_method_id.payment_type', readonly=True, store=True, + string="Payment Type") + payment_method_code = fields.Char( + related='payment_method_id.code', readonly=True, store=True, + string='Payment Method Code') + active = fields.Boolean(string='Active', default=True) + # I dropped sale_ok and purchase_ok fields, because it is replaced by + # payment_type = 'inbound' or 'outbound' + # In fact, with the new v9 datamodel, you MUST create 2 payment modes + # for wire transfer : one for wire transfer from your customers (inbound) + # and one for wire transfer to your suppliers (outbound) + note = fields.Text(string="Note", translate=True) + + @api.multi + @api.constrains( + 'bank_account_link', 'fixed_journal_id', 'payment_method_id') + def bank_account_link_constrains(self): + for mode in self: + if mode.bank_account_link == 'fixed': + if not mode.fixed_journal_id: + raise ValidationError(_( + "On the payment mode '%s', the bank account link is " + "'Fixed' but the fixed bank journal is not set") + % mode.name) + else: + if mode.payment_method_id.payment_type == 'outbound': + if ( + mode.payment_method_id.id not in + mode.fixed_journal_id. + outbound_payment_method_ids.ids): + raise ValidationError(_( + "On the payment mode '%s', the payment method " + "is '%s', but this payment method is not part " + "of the payment methods of the fixed bank " + "journal '%s'") % ( + mode.name, + mode.payment_method_id.name, + mode.fixed_journal_id.name)) + else: + if ( + mode.payment_method_id.id not in + mode.fixed_journal_id. + inbound_payment_method_ids.ids): + raise ValidationError(_( + "On the payment mode '%s', the payment method " + "is '%s' (it is in fact a debit method), " + "but this debit method is not part " + "of the debit methods of the fixed bank " + "journal '%s'") % ( + mode.name, + mode.payment_method_id.name, + mode.fixed_journal_id.name)) diff --git a/account_payment_mode/models/res_partner_bank.py b/account_payment_mode/models/res_partner_bank.py new file mode 100644 index 000000000..1f70f9f81 --- /dev/null +++ b/account_payment_mode/models/res_partner_bank.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields + + +class ResPartnerBank(models.Model): + _inherit = 'res.partner.bank' + + # TODO: It doesn't work, I don't understand why + # So I change the label of the field in the view + acc_type = fields.Char(string='Bank Account Type') diff --git a/account_payment_mode/security/ir.model.access.csv b/account_payment_mode/security/ir.model.access.csv new file mode 100644 index 000000000..0ff4035ea --- /dev/null +++ b/account_payment_mode/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +account.access_account_payment_method,Read access on account.payment.method to Invoice user,account.model_account_payment_method,account.group_account_invoice,1,0,0,0 +access_account_payment_method_full,Full access on account.payment.method to Financial Manager,account.model_account_payment_method,account.group_account_manager,1,1,1,1 +access_account_payment_mode_read,Read access on account.payment.mode to Employees,model_account_payment_mode,base.group_user,1,0,0,0 +access_account_payment_mode_full,Full access on account.payment.mode to Financial Manager,model_account_payment_mode,account.group_account_manager,1,1,1,1 diff --git a/account_payment_mode/views/account_payment_method.xml b/account_payment_mode/views/account_payment_method.xml new file mode 100644 index 000000000..f912e45e9 --- /dev/null +++ b/account_payment_mode/views/account_payment_method.xml @@ -0,0 +1,62 @@ + + + + + + + account_payment_method.form + account.payment.method + +
+ + + + + + +
+
+
+ + + account_payment_method.tree + account.payment.method + + + + + + + + + + + account_payment_method.search + account.payment.method + + + + + + + + + + + + + + Payment Methods + account.payment.method + tree,form + + + + +
+
diff --git a/account_payment_mode/views/account_payment_mode.xml b/account_payment_mode/views/account_payment_mode.xml new file mode 100644 index 000000000..8ea6332a2 --- /dev/null +++ b/account_payment_mode/views/account_payment_mode.xml @@ -0,0 +1,71 @@ + + + + + + account.payment.mode.form + account.payment.mode + +
+ + + + + + + + + + + + +
+
+
+ + + account.payment.mode.tree + account.payment.mode + + + + + + + + + + + + + account.payment.mode.search + account.payment.mode + + + + + + + + + + + + + + Payment Mode + account.payment.mode + tree,form + + + + +
+
diff --git a/account_payment_mode/views/res_partner_bank.xml b/account_payment_mode/views/res_partner_bank.xml new file mode 100644 index 000000000..da8984ac5 --- /dev/null +++ b/account_payment_mode/views/res_partner_bank.xml @@ -0,0 +1,44 @@ + + + + + + + account_payment_mode.res_partner_bank_form + res.partner.bank + + + + + + + + + + account_payment_mode.res_partner_bank_tree + res.partner.bank + + + + + + + + + + account_payment_mode.res_partner_bank_search + res.partner.bank + + + + + + + + + + + + + diff --git a/account_banking_payment_export/README.rst b/account_payment_order/README.rst similarity index 100% rename from account_banking_payment_export/README.rst rename to account_payment_order/README.rst diff --git a/account_banking_payment_export/__init__.py b/account_payment_order/__init__.py similarity index 100% rename from account_banking_payment_export/__init__.py rename to account_payment_order/__init__.py diff --git a/account_banking_payment_export/__openerp__.py b/account_payment_order/__openerp__.py similarity index 57% rename from account_banking_payment_export/__openerp__.py rename to account_payment_order/__openerp__.py index afc065106..55ed6afba 100644 --- a/account_banking_payment_export/__openerp__.py +++ b/account_payment_order/__openerp__.py @@ -3,35 +3,38 @@ # © 2011-2013 Therp BV () # © 2013-2014 ACSONE SA (). # © 2014-2016 Serv. Tecnol. Avanzados - Pedro M. Baeza +# © 2016 Akretion (). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'Account Banking - Payments Export Infrastructure', - 'version': '8.0.0.3.0', + 'name': 'Account Payment Order', + 'version': '9.0.1.0.0', 'license': 'AGPL-3', 'author': "ACSONE SA/NV, " "Therp BV, " "Serv. Tecnol. Avanzados - Pedro M. Baeza, " + "Akretion, " "Odoo Community Association (OCA)", 'website': 'https://github.com/OCA/bank-payment', 'category': 'Banking addons', 'depends': [ - 'account_payment', + 'account_payment_partner', 'base_iban', # for manual_bank_tranfer 'document', # to see the attachments on payment.order ], 'data': [ - 'views/account_payment.xml', - 'views/payment_mode.xml', - 'views/payment_mode_type.xml', - 'views/bank_payment_line.xml', - 'wizard/bank_payment_manual.xml', - 'wizard/payment_order_create_view.xml', - 'data/payment_mode_type.xml', - 'data/bank_payment_line_seq.xml', - 'workflow/account_payment.xml', + 'security/payment_security.xml', 'security/ir.model.access.csv', + 'wizard/account_payment_line_create_view.xml', + 'views/account_payment_mode.xml', + 'views/account_payment_order.xml', + 'views/account_payment_line.xml', + 'views/bank_payment_line.xml', + 'views/account_move_line.xml', + 'views/ir_attachment.xml', + #'views/res_partner_bank.xml', + 'data/payment_seq.xml', ], - 'demo': ['demo/banking_demo.xml'], - 'installable': False, + 'demo': ['demo/payment_demo.xml'], + 'installable': True, } diff --git a/account_banking_payment_export/data/payment_mode_type.xml b/account_payment_order/data/payment_mode_type.xml similarity index 100% rename from account_banking_payment_export/data/payment_mode_type.xml rename to account_payment_order/data/payment_mode_type.xml diff --git a/account_payment_order/data/payment_seq.xml b/account_payment_order/data/payment_seq.xml new file mode 100644 index 000000000..9f89b95af --- /dev/null +++ b/account_payment_order/data/payment_seq.xml @@ -0,0 +1,38 @@ + + + + + + + + + Bank Payment Line + bank.payment.line + L + 5 + + + + + Payment Line + account.payment.line + P + 5 + + + + + Payment Order + account.payment.order + PAY + 4 + + + + + + diff --git a/account_payment_order/demo/payment_demo.xml b/account_payment_order/demo/payment_demo.xml new file mode 100644 index 000000000..1644a907a --- /dev/null +++ b/account_payment_order/demo/payment_demo.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/account_banking_payment_export/i18n/es.po b/account_payment_order/i18n/es.po similarity index 100% rename from account_banking_payment_export/i18n/es.po rename to account_payment_order/i18n/es.po diff --git a/account_banking_payment_export/i18n/fr.po b/account_payment_order/i18n/fr.po similarity index 100% rename from account_banking_payment_export/i18n/fr.po rename to account_payment_order/i18n/fr.po diff --git a/account_banking_payment_export/i18n/nl.po b/account_payment_order/i18n/nl.po similarity index 100% rename from account_banking_payment_export/i18n/nl.po rename to account_payment_order/i18n/nl.po diff --git a/account_banking_payment_export/i18n/pt_BR.po b/account_payment_order/i18n/pt_BR.po similarity index 100% rename from account_banking_payment_export/i18n/pt_BR.po rename to account_payment_order/i18n/pt_BR.po diff --git a/account_banking_payment_export/i18n/sl.po b/account_payment_order/i18n/sl.po similarity index 100% rename from account_banking_payment_export/i18n/sl.po rename to account_payment_order/i18n/sl.po diff --git a/account_banking_payment_export/migrations/8.0.0.1.166/pre-migrate.py b/account_payment_order/migrations/8.0.0.1.166/pre-migrate.py similarity index 100% rename from account_banking_payment_export/migrations/8.0.0.1.166/pre-migrate.py rename to account_payment_order/migrations/8.0.0.1.166/pre-migrate.py diff --git a/account_payment_order/models/__init__.py b/account_payment_order/models/__init__.py new file mode 100644 index 000000000..48e597645 --- /dev/null +++ b/account_payment_order/models/__init__.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- + +from . import account_payment_mode +from . import account_payment_order +from . import account_payment_line +from . import bank_payment_line +from . import account_move_line +from . import account_invoice +from . import res_bank diff --git a/account_banking_payment_export/models/account_invoice.py b/account_payment_order/models/account_invoice.py similarity index 80% rename from account_banking_payment_export/models/account_invoice.py rename to account_payment_order/models/account_invoice.py index f500e99fd..b6516b708 100644 --- a/account_banking_payment_export/models/account_invoice.py +++ b/account_payment_order/models/account_invoice.py @@ -46,3 +46,13 @@ class AccountInvoice(models.Model): res['arch'] = etree.tostring(doc) res['fields'][field_name] = field return res + + @api.model + def line_get_convert(self, line, part): + """Copy supplier bank account 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 ('in_invoice', 'in_refund'): + res['partner_bank_id'] = invoice.partner_bank_id.id or False + return res diff --git a/account_payment_order/models/account_move_line.py b/account_payment_order/models/account_move_line.py new file mode 100644 index 000000000..b66cd3f4a --- /dev/null +++ b/account_payment_order/models/account_move_line.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +# © 2014-2016 Akretion (Alexis de Lattre ) +# © 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.tools import float_is_zero + + +class AccountMoveLine(models.Model): + _inherit = 'account.move.line' + + # TODO Should we keep this field ? +# journal_entry_ref = fields.Char(compute='_get_journal_entry_ref', +# string='Journal Entry Ref') + partner_bank_id = fields.Many2one( + 'res.partner.bank', string='Partner Bank Account', + help='Bank account on which we should pay the supplier') + +# @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 + + @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 + + @api.multi + def _prepare_payment_line_vals(self, payment_order): + self.ensure_one() + assert payment_order, 'Missing payment order' + aplo = self.env['account.payment.line'] + communication_type = 'normal' + communication = self.move_id.name or '-' + ref2comm_type = aplo.invoice_reference_type2communication_type() + if ( + self.invoice_id and + self.invoice_id.type in ('in_invoice', 'in_refund') and + self.invoice_id.reference): + communication = self.invoice_id.reference + if self.invoice_id.reference_type: + communication_type =\ + ref2comm_type[self.invoice_id.reference_type] + if self.currency_id: + currency_id = self.currency_id.id + amount_currency = self.amount_residual_currency + else: + currency_id = self.company_id.currency_id.id + amount_currency = self.amount_residual + # TODO : check that self.amount_residual_currency is 0 in this case + precision = self.env['decimal.precision'].precision_get('Account') + if payment_order.payment_type == 'outbound': + amount_currency *= -1 + # TODO : inherit for mandate + vals = { + 'order_id': payment_order.id, + 'partner_bank_id': self.partner_bank_id.id, + 'partner_id': self.partner_id.id, + 'move_line_id': self.id, + 'communication': communication, + 'communication_type': communication_type, + 'currency_id': currency_id, + 'amount_currency': amount_currency, + # date is set when the user confirms the payment order + } + return vals + + @api.multi + def create_payment_line_from_move_line(self, payment_order): + aplo = self.env['account.payment.line'] + for mline in self: + aplo.create(mline._prepare_payment_line_vals(payment_order)) + return diff --git a/account_payment_order/models/account_payment_line.py b/account_payment_order/models/account_payment_line.py new file mode 100644 index 000000000..2058c0e00 --- /dev/null +++ b/account_payment_order/models/account_payment_line.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +# © 2015-2016 Akretion - Alexis de Lattre +# 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 AccountPaymentLine(models.Model): + _name = 'account.payment.line' + _description = 'Payment Lines' + + name = fields.Char(string='Payment Reference', readonly=True, copy=False) + order_id = fields.Many2one( + 'account.payment.order', string='Payment Order', + ondelete='cascade', select=True) + company_id = fields.Many2one( + related='order_id.company_id', store=True, readonly=True) + company_currency_id = fields.Many2one( + related='order_id.company_currency_id', store=True, readonly=True) + payment_type = fields.Selection( + related='order_id.payment_type', store=True, readonly=True) + move_line_id = fields.Many2one( + 'account.move.line', string='Journal Item') + ml_maturity_date = fields.Date( + related='move_line_id.date_maturity', readonly=True) + currency_id = fields.Many2one( + 'res.currency', string='Currency of the Payment Transaction', + required=True, + default=lambda self: self.env.user.company_id.currency_id) + # v8 field : currency + amount_currency = fields.Monetary( + string="Amount", currency_field='currency_id') + amount_company_currency = fields.Monetary( + compute='compute_amount_company_currency', + string='Amount in Company Currency', readonly=True, + currency_field='company_currency_id') # v8 field : amount + partner_id = fields.Many2one( + 'res.partner', string='Partner', required=True, + domain=[('parent_id', '=', False)]) + partner_bank_id = fields.Many2one( + 'res.partner.bank', string='Partner Bank Account', required=False, + ondelete='restrict') # v8 field : bank_id + date = fields.Date(string='Payment Date') + communication = fields.Char( + string='Communication', required=True, + help="Label of the payment that will be seen by the destinee") + communication_type = fields.Selection([ + ('normal', 'Free'), + ], string='Communication Type', required=True, default='normal') + # v8 field : state + bank_line_id = fields.Many2one( + 'bank.payment.line', string='Bank Payment Line', readonly=True) + + _sql_constraints = [( + 'name_company_unique', + 'unique(name, company_id)', + 'A payment line already exists with this reference ' + 'in the same company!' + )] + + @api.model + def create(self, vals): + if vals.get('name', 'New') == 'New': + vals['name'] = self.env['ir.sequence'].next_by_code( + 'account.payment.line') or 'New' + return super(AccountPaymentLine, self).create(vals) + + @api.multi + @api.depends( + 'amount_currency', 'currency_id', 'company_currency_id', 'date') + def compute_amount_company_currency(self): + for line in self: + if line.currency_id and line.company_currency_id: + line.amount_company_currency = line.currency_id.with_context( + date=line.date).compute( + line.amount_currency, line.company_currency_id) + + @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 + + @api.onchange('partner_id') + def partner_id_change(self): + partner_bank = False + if self.partner_id and self.partner_id.bank_ids: + partner_bank = self.partner_id.bank_ids[0] + self.partner_bank_id = partner_bank + + @api.onchange('move_line_id') + def move_line_id_change(self): + if self.move_line_id: + vals = self.move_line_id._prepare_payment_line_vals(self.order_id) + vals.pop('order_id') + for field, value in vals.iteritems(): + self[field] = value + else: + self.partner_id = False + self.partner_bank_id = False + self.amount_currency = 0.0 + self.currency_id = False + self.communication = False + + def invoice_reference_type2communication_type(self): + """This method is designed to be inherited by + localization modules""" + # key = value of 'reference_type' field on account_invoice + # value = value of 'communication_type' field on account_payment_line + res = {'none': 'normal'} + return res + + @api.multi + def check_payment_line(self): + for line in self: + if not line.partner_bank_id: + raise UserError(_( + 'Missing Partner Bank Account on payment line %s') + % line.name) diff --git a/account_payment_order/models/account_payment_mode.py b/account_payment_order/models/account_payment_mode.py new file mode 100644 index 000000000..956f918c5 --- /dev/null +++ b/account_payment_order/models/account_payment_mode.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# © 2009 EduSense BV () +# © 2011-2013 Therp BV () +# © 2014-2016 Serv. Tecnol. Avanzados - Pedro M. Baeza +# © 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields, api + + +class AccountPaymentMode(models.Model): + """This corresponds to the object payment.mode of v8 with some + important changes""" + _inherit = "account.payment.mode" + + payment_order_ok = fields.Boolean( + string='Selectable in Payment Orders', default=True) + # Default options for the "payment.order.create" wizard + default_payment_mode = fields.Selection([ + ('same', 'Same'), + ('same_or_null', 'Same or empty'), + ('any', 'Any'), + ], string='Payment Mode on Invoice', default='same') + 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") + 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('payment_method_id') + def payment_method_id_change(self): + if self.payment_method_id: + ajo = self.env['account.journal'] + aj_ids = [] + if self.payment_method_id.payment_type == 'outbound': + aj_ids = ajo.search([ + ('type', 'in', ('purchase_refund', 'purchase'))]).ids + elif self.payment_method_id.payment_type == 'inbound': + aj_ids = ajo.search([ + ('type', 'in', ('sale_refund', 'sale'))]).ids + self.default_journal_ids = [(6, 0, aj_ids)] diff --git a/account_payment_order/models/account_payment_order.py b/account_payment_order/models/account_payment_order.py new file mode 100644 index 000000000..f23bb1b44 --- /dev/null +++ b/account_payment_order/models/account_payment_order.py @@ -0,0 +1,261 @@ +# -*- coding: utf-8 -*- +# © 2009 EduSense BV () +# © 2011-2013 Therp BV () +# © 2016 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, api, _ +from openerp.exceptions import UserError, ValidationError + + +class AccountPaymentOrder(models.Model): + _name = 'account.payment.order' + _description = 'Payment Order' + _inherit = ['mail.thread'] + _order = 'id desc' + + name = fields.Char( + string='Number', readonly=True, copy=False, + track_visibility='onchange') # v8 field : name + payment_mode_id = fields.Many2one( + 'account.payment.mode', 'Payment Method', required=True, + ondelete='restrict', track_visibility='onchange', + readonly=True, states={'draft': [('readonly', False)]}) + payment_type = fields.Selection([ + ('inbound', 'Inbound'), + ('outbound', 'Outbound'), + ], string='Payment Type', readonly=True, required=True) + company_id = fields.Many2one( + related='payment_mode_id.company_id', store=True, readonly=True) + company_currency_id = fields.Many2one( + related='payment_mode_id.company_id.currency_id', store=True, + readonly=True) + bank_account_link = fields.Selection( + related='payment_mode_id.bank_account_link', readonly=True) + journal_id = fields.Many2one( + 'account.journal', string='Bank Journal', + required=True) + company_partner_bank_id = fields.Many2one( + related='journal_id.bank_account_id', string='Company Bank Account', + readonly=True) + state = fields.Selection([ + ('draft', 'Draft'), + ('open', 'Confirmed'), + ('generated', 'File Generated'), + ('uploaded', 'File Uploaded'), + ('done', 'Done'), + ('cancel', 'Cancel'), + ], string='Status', readonly=True, copy=False, default='draft', + track_visibility='onchange') + date_prefered = fields.Selection([ + ('now', 'Immediately'), + ('due', 'Due Date'), + ('fixed', 'Fixed Date'), + ], string='Payment Execution Date Type', required=True, default='due', + track_visibility='onchange', readonly=True, + states={'draft': [('readonly', False)]}) + date_scheduled = fields.Date( + string='Payment Execution Date', readonly=True, + states={'draft': [('readonly', False)]}, track_visibility='onchange', + help="Select a requested date of execution if you selected 'Due Date' " + "as the Payment Execution Date Type.") + date_done = fields.Date(string='Date Done', readonly=True) + date_generated = fields.Date(string='Date Generated', readonly=True) + generated_user_id = fields.Many2one( + 'res.users', string='Generated by', readonly=True, ondelete='restrict', + copy=False) + payment_line_ids = fields.One2many( + 'account.payment.line', 'order_id', string='Transaction Lines', + readonly=True, states={'draft': [('readonly', False)]}) + # v8 field : line_ids + bank_line_ids = fields.One2many( + 'bank.payment.line', 'order_id', string="Bank Payment Lines", + readonly=True) + total_company_currency = fields.Monetary( + compute='_compute_total', store=True, readonly=True, + currency_field='company_currency_id') + bank_line_count = fields.Integer( + compute='_bank_line_count', string='Number of Bank Lines', + readonly=True) + + @api.multi + @api.constrains('payment_type', 'payment_mode_id') + def payment_order_constraints(self): + for order in self: + if ( + order.payment_mode_id.payment_type and + order.payment_mode_id.payment_type != order.payment_type): + raise ValidationError(_( + "The payment type (%s) is not the same as the payment " + "type of the payment mode (%s)") % ( + order.payment_type, + order.payment_mode_id.payment_type)) + + @api.one + @api.depends( + 'payment_line_ids', 'payment_line_ids.amount_company_currency') + def _compute_total(self): + self.total_company_currency = sum( + self.mapped('payment_line_ids.amount_company_currency') 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.model + def create(self, vals): + if vals.get('name', 'New') == 'New': + vals['name'] = self.env['ir.sequence'].next_by_code( + 'account.payment.order') or 'New' + return super(AccountPaymentOrder, self).create(vals) + + @api.onchange('payment_mode_id') + def payment_mode_id_change(self): + res = {'domain': {}} + if self.payment_mode_id: + if self.payment_mode_id.bank_account_link == 'fixed': + self.journal_id = self.payment_mode_id.fixed_journal_id + # journal_id is a required field, so I can't set it readonly + # so I restrict the domain so that the user cannot change + # the journal + res['domain']['journal_id'] = [( + 'id', + '=', + self.payment_mode_id.fixed_journal_id.id)] + else: + res['domain']['journal_id'] = [( + 'id', + 'in', + self.payment_mode_id.variable_journal_ids.ids)] + else: + self.journal_id = False + return res + + @api.multi + def action_done(self): + self.write({ + 'date_done': fields.Date.context_today(self), + 'state': 'done', + }) + return True + + @api.multi + def cancel2draft(self): + self.write({'state': 'draft'}) + 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 draft2open(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 + """ + 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.payment_line_ids: + payline.check_payment_line() + # 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.payment_mode_id.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 UserError(_( + "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) + self.write({'state': 'open'}) + return True + + @api.multi + def generate_payment_file(self): + """Returns (payment file as string, filename)""" + self.ensure_one() + raise UserError(_( + "No handler for this payment method. Maybe you haven't " + "installed the related Odoo module.")) + + @api.multi + def open2generated(self): + self.ensure_one() + payment_file_str, filename = self.generate_payment_file() + attachment = self.env['ir.attachment'].create({ + 'res_model': 'account.payment.order', + 'res_id': self.id, + 'name': filename, + 'datas': payment_file_str.encode('base64'), + 'datas_fname': filename, + }) + self.write({ + 'date_generated': fields.Date.context_today(self), + 'state': 'generated', + 'generated_user_id': self._uid, + }) + simplified_form_view = self.env.ref( + 'account_payment_order.view_attachment_simplified_form') + action = { + 'name': _('Payment File'), + 'view_mode': 'form', + 'view_id': simplified_form_view.id, + 'res_model': 'ir.attachment', + 'type': 'ir.actions.act_window', + 'target': 'current', + 'res_id': attachment.id, + } + return action + + @api.multi + def generated2uploaded(self): + self.write({'state': 'uploaded'}) + return True diff --git a/account_payment_order/models/bank_payment_line.py b/account_payment_order/models/bank_payment_line.py new file mode 100644 index 000000000..bc419eb73 --- /dev/null +++ b/account_payment_order/models/bank_payment_line.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# © 2015 Akretion - Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from openerp import models, fields, api + + +class BankPaymentLine(models.Model): + _name = 'bank.payment.line' + _description = 'Bank Payment Lines' + + name = fields.Char( + string='Bank Payment Line Ref', required=True, + readonly=True) + order_id = fields.Many2one( + 'account.payment.order', string='Order', ondelete='cascade', + select=True) + payment_type = fields.Selection( + related='order_id.payment_type', string="Payment Type", + readonly=True, store=True) + state = fields.Selection( + related='order_id.state', string='State', + readonly=True, store=True) + payment_line_ids = fields.One2many( + 'account.payment.line', 'bank_line_id', string='Payment Lines', + readonly=True) + partner_id = fields.Many2one( + 'res.partner', related='payment_line_ids.partner_id', + readonly=True) + # Function Float fields are sometimes badly displayed in tree view, + # see bug report https://github.com/odoo/odoo/issues/8632 + amount_currency = fields.Monetary( + string='Amount', currency_field='currency_id', + compute='_compute_amount', store=True, readonly=True) + currency_id = fields.Many2one( + 'res.currency', required=True, readonly=True, + related='payment_line_ids.currency_id') # v8 field: currency + partner_bank_id = fields.Many2one( + 'res.partner.bank', string='Bank Account', readonly=True, + related='payment_line_ids.partner_bank_id') # v8 field: bank_id + date = fields.Date( + related='payment_line_ids.date', readonly=True) + communication_type = fields.Selection( + related='payment_line_ids.communication_type', readonly=True) + communication = fields.Char( + string='Communication', required=True, + readonly=True) #, states={'draft': [('readonly', False)]}) + company_id = fields.Many2one( + related='order_id.payment_mode_id.company_id', store=True, + readonly=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_id', 'partner_id', + 'partner_bank_id', 'date', 'communication_type'] + 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', 'New') == 'New': + vals['name'] = self.env['ir.sequence'].next_by_code( + 'bank.payment.line') or 'New' + return super(BankPaymentLine, self).create(vals) diff --git a/account_banking_payment_export/models/res_partner_bank.py b/account_payment_order/models/res_bank.py similarity index 52% rename from account_banking_payment_export/models/res_partner_bank.py rename to account_payment_order/models/res_bank.py index ce805f82a..fa927bbd1 100644 --- a/account_banking_payment_export/models/res_partner_bank.py +++ b/account_payment_order/models/res_bank.py @@ -1,25 +1,11 @@ # -*- coding: utf-8 -*- -# © 2015 Akretion - Alexis de Lattre +# © 2015-2016 Akretion - Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import models, api, _ from openerp.exceptions import ValidationError -class ResPartnerBank(models.Model): - _inherit = 'res.partner.bank' - - @api.multi - @api.constrains('bank_bic') - def check_bic_length(self): - for pbank in self: - if pbank.bank_bic and len(pbank.bank_bic) not in (8, 11): - raise ValidationError(_( - "A valid BIC contains 8 or 11 caracters. The BIC '%s' " - "contains %d caracters, so it is not valid.") - % (pbank.bank_bic, len(pbank.bank_bic))) - - class ResBank(models.Model): _inherit = 'res.bank' @@ -32,3 +18,5 @@ class ResBank(models.Model): "A valid BIC contains 8 or 11 caracters. The BIC '%s' " "contains %d caracters, so it is not valid.") % (bank.bic, len(bank.bic))) + +# in v9, on res.partner.bank bank_bic is a related of bank_id.bic diff --git a/account_payment_order/security/ir.model.access.csv b/account_payment_order/security/ir.model.access.csv new file mode 100644 index 000000000..753793646 --- /dev/null +++ b/account_payment_order/security/ir.model.access.csv @@ -0,0 +1,4 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_payment_order,Full access on account.payment.order to Payment Manager,model_account_payment_order,group_account_payment,1,1,1,1 +access_account_payment_line,Full access on account.payment.line to Payment Manager,model_account_payment_line,group_account_payment,1,1,1,1 +access_bank_payment_line,Full access on bank.payment.line to Payment Manager,model_bank_payment_line,group_account_payment,1,1,1,1 diff --git a/account_payment_order/security/payment_security.xml b/account_payment_order/security/payment_security.xml new file mode 100644 index 000000000..cb5ce34f2 --- /dev/null +++ b/account_payment_order/security/payment_security.xml @@ -0,0 +1,39 @@ + + + + + + + Accounting / Payments + + + + + + + + + + + + Payment mode multi-company rule + + ['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])] + + + + + + diff --git a/account_banking_payment_export/static/description/icon.png b/account_payment_order/static/description/icon.png similarity index 100% rename from account_banking_payment_export/static/description/icon.png rename to account_payment_order/static/description/icon.png diff --git a/account_payment_order/views/account_move_line.xml b/account_payment_order/views/account_move_line.xml new file mode 100644 index 000000000..d9e606d11 --- /dev/null +++ b/account_payment_order/views/account_move_line.xml @@ -0,0 +1,27 @@ + + + + + + + + + + account_payment_order.move_line_form + account.move.line + + + + + + + + + + + diff --git a/account_payment_order/views/account_payment_line.xml b/account_payment_order/views/account_payment_line.xml new file mode 100644 index 000000000..152c119d4 --- /dev/null +++ b/account_payment_order/views/account_payment_line.xml @@ -0,0 +1,66 @@ + + + + + + + account.payment.line.form + account.payment.line + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + account.payment.line.tree + account.payment.line + + + + + + + + + + + + + + + + + + + Payment Lines + account.payment.line + tree,form + {'account_payment_line_main_view': True} + + + +
+
diff --git a/account_payment_order/views/account_payment_mode.xml b/account_payment_order/views/account_payment_mode.xml new file mode 100644 index 000000000..f0a8f6864 --- /dev/null +++ b/account_payment_order/views/account_payment_mode.xml @@ -0,0 +1,51 @@ + + + + + + + account_payment_order.account.payment.mode.form + account.payment.mode + + + + + + + + + + + + + + + + + + + account_payment_order.account.payment.mode.tree + account.payment.mode + + + + + + + + + + account_payment_order.account.payment.mode.search + account.payment.mode + + + + + + + + + + diff --git a/account_payment_order/views/account_payment_order.xml b/account_payment_order/views/account_payment_order.xml new file mode 100644 index 000000000..c71c33d25 --- /dev/null +++ b/account_payment_order/views/account_payment_order.xml @@ -0,0 +1,127 @@ + + + + + + + account.payment.order.form + account.payment.order + +
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + account.payment.order.tree + account.payment.order + + + + + + + + + + + + + + + + + account.payment.order.search + account.payment.order + + + + + + + + + + + + + + Payment Orders + account.payment.order + tree,form + [('payment_type', '=', 'outbound')] + {'default_payment_type': 'outbound'} + + + + Debit Orders + account.payment.order + tree,form + [('payment_type', '=', 'inbound')] + {'default_payment_type': 'inbound'} + + + + + + + + +
+
diff --git a/account_banking_payment_export/views/bank_payment_line.xml b/account_payment_order/views/bank_payment_line.xml similarity index 58% rename from account_banking_payment_export/views/bank_payment_line.xml rename to account_payment_order/views/bank_payment_line.xml index a159af44d..bd62865f0 100644 --- a/account_banking_payment_export/views/bank_payment_line.xml +++ b/account_payment_order/views/bank_payment_line.xml @@ -2,7 +2,7 @@ @@ -20,11 +20,10 @@ invisible="not context.get('bank_payment_line_main_view')"/> - - - - + + + +
@@ -43,12 +42,10 @@ invisible="not context.get('bank_payment_line_main_view')"/> - + - - + + @@ -56,6 +53,23 @@ + + bank.payment.line.search + bank.payment.line + + + + + + + + + + + + + + Bank Payment Lines bank.payment.line @@ -63,5 +77,8 @@ {'bank_payment_line_main_view': True} + + diff --git a/account_payment_order/views/ir_attachment.xml b/account_payment_order/views/ir_attachment.xml new file mode 100644 index 000000000..98f5ac991 --- /dev/null +++ b/account_payment_order/views/ir_attachment.xml @@ -0,0 +1,32 @@ + + + + + + + ir.attachment.simplified.form + ir.attachment + +
+ + +
+
+
+ +
+
diff --git a/account_banking_payment_export/views/payment_order_create_view.xml b/account_payment_order/views/payment_order_create_view.xml similarity index 100% rename from account_banking_payment_export/views/payment_order_create_view.xml rename to account_payment_order/views/payment_order_create_view.xml diff --git a/account_payment_order/wizard/__init__.py b/account_payment_order/wizard/__init__.py new file mode 100644 index 000000000..0cbec9692 --- /dev/null +++ b/account_payment_order/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import account_payment_line_create diff --git a/account_banking_payment_export/wizard/payment_order_create.py b/account_payment_order/wizard/account_payment_line_create.py similarity index 55% rename from account_banking_payment_export/wizard/payment_order_create.py rename to account_payment_order/wizard/account_payment_line_create.py index 6fea3a8fe..944382de5 100644 --- a/account_banking_payment_export/wizard/payment_order_create.py +++ b/account_payment_order/wizard/account_payment_line_create.py @@ -1,34 +1,19 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# Copyright (C) 2009 EduSense BV (). -# (C) 2011 - 2013 Therp BV (). -# (C) 2014 - 2015 ACSONE SA/NV (). -# (C) 2015 Akretion (). -# -# All other contributions are (C) by their respective contributors -# -# 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 . -# -############################################################################## +# © 2009 EduSense BV () +# © 2011-2013 Therp BV () +# © 2014-2015 ACSONE SA/NV () +# © 2015-2016 Akretion () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from openerp import models, fields, api, _ -class PaymentOrderCreate(models.TransientModel): - _inherit = 'payment.order.create' +class AccountPaymentLineCreate(models.TransientModel): + _name = 'account.payment.line.create' + _description = 'Wizard to create payment lines' + order_id = fields.Many2one( + 'account.payment.order', string='Payment Order') journal_ids = fields.Many2many( 'account.journal', string='Journals Filter') invoice = fields.Boolean( @@ -37,34 +22,63 @@ class PaymentOrderCreate(models.TransientModel): ('due', 'Due Date'), ('move', 'Move Date'), ], string="Type of Date Filter", required=True) - duedate = fields.Date(required=False) + due_date = fields.Date(string="Due Date") move_date = fields.Date( string='Move Date', default=fields.Date.context_today) - populate_results = fields.Boolean(string="Populate Results Directly") + payment_mode = fields.Selection([ + ('same', 'Same'), + ('same_or_null', 'Same or Empty'), + ('any', 'Any'), + ], string='Payment Mode') + move_line_ids = fields.Many2many( + 'account.move.line', string='Move Lines') @api.model def default_get(self, field_list): - res = super(PaymentOrderCreate, self).default_get(field_list) + res = super(AccountPaymentLineCreate, self).default_get(field_list) context = self.env.context - if ('entries' in field_list and context.get('line_ids') and - context.get('populate_results')): - res.update({'entries': context['line_ids']}) - assert context.get('active_model') == 'payment.order',\ + assert context.get('active_model') == 'account.payment.order',\ 'active_model should be payment.order' assert context.get('active_id'), 'Missing active_id in context !' - pay_order = self.env['payment.order'].browse(context['active_id']) + order = self.env['account.payment.order'].browse(context['active_id']) + mode = order.payment_mode_id res.update({ - 'journal_ids': pay_order.mode.default_journal_ids.ids or False, - 'invoice': pay_order.mode.default_invoice, - 'date_type': pay_order.mode.default_date_type, - 'populate_results': pay_order.mode.default_populate_results, + 'journal_ids': mode.default_journal_ids.ids or False, + 'invoice': mode.default_invoice, + 'date_type': mode.default_date_type, + 'payment_mode': mode.default_payment_mode, + 'order_id': order.id, }) return res @api.multi - def extend_payment_order_domain(self, payment_order, domain): + def _prepare_move_line_domain(self): self.ensure_one() - if payment_order.payment_order_type == 'payment': + journals = self.journal_ids or self.env['account.journal'].search([]) + domain = [('move_id.state', '=', 'posted'), + ('reconciled', '=', False), + ('company_id', '=', self.order_id.company_id.id), + ('journal_id', 'in', journals.ids)] + if self.date_type == 'due': + domain += [ + '|', + ('date_maturity', '<=', self.due_date), + ('date_maturity', '=', False)] + elif self.date_type == 'move': + domain.append(('date', '<=', self.move_date)) + if self.invoice: + domain.append(('invoice_id', '!=', False)) + if self.payment_mode: + if self.payment_mode == 'same': + domain.append( + ('payment_mode_id', '=', self.order_id.payment_mode_id.id)) + elif self.payment_mode == 'same_or_null': + domain += [ + '|', + ('payment_mode_id', '=', False), + ('payment_mode_id', '=', self.order_id.payment_mode_id.id)] + + if self.order_id.payment_type == 'outbound': # For payables, propose all unreconciled credit lines, # including partially reconciled ones. # If they are partially reconciled with a supplier refund, @@ -77,12 +91,41 @@ class PaymentOrderCreate(models.TransientModel): # will not be refunded with a payment. domain += [ ('credit', '>', 0), - '|', - ('account_id.type', '=', 'payable'), - '&', - ('account_id.type', '=', 'receivable'), - ('reconcile_partial_id', '=', False), + #'|', + ('account_id.internal_type', '=', 'payable'), + #'&', + #('account_id.internal_type', '=', 'receivable'), + #('reconcile_partial_id', '=', False), # TODO uncomment ] + elif self.order_id.payment_type == 'inbound': + domain += [ + ('debit', '>', 0), + ('account_id.internal_type', '=', 'receivable'), + ] + return domain + + @api.multi + def populate(self): + domain = self._prepare_move_line_domain() + lines = self.env['account.move.line'].search(domain) + self.move_line_ids = [(6, 0, lines.ids)] + action = { + 'name': _('Select Move Lines to Create Transactions'), + 'type': 'ir.actions.act_window', + 'res_model': 'account.payment.line.create', + 'view_mode': 'form', + 'target': 'new', + 'res_id': self.id, + 'context': self._context, + } + return action + + @api.onchange( + 'date_type', 'move_date', 'due_date', 'journal_ids', 'invoice') + def move_line_filters_change(self): + domain = self._prepare_move_line_domain() + res = {'domain': {'move_line_ids': domain}} + return res @api.multi def filter_lines(self, lines): @@ -103,62 +146,12 @@ class PaymentOrderCreate(models.TransientModel): :returns: list of move line ids """ self.ensure_one() - payment_lines = self.env['payment.line'].\ + payment_lines = self.env['account.payment.line'].\ search([('order_id.state', 'in', ('draft', 'open')), ('move_line_id', 'in', lines.ids)]) to_exclude = set([l.move_line_id.id for l in payment_lines]) return [l.id for l in lines if l.id not in to_exclude] - @api.multi - def search_entries(self): - """This method taken from account_payment module. - We adapt the domain based on the payment_order_type - """ - line_obj = self.env['account.move.line'] - model_data_obj = self.env['ir.model.data'] - # -- start account_banking_payment -- - payment = self.env['payment.order'].browse( - self.env.context['active_id']) - # Search for move line to pay: - journals = self.journal_ids or self.env['account.journal'].search([]) - domain = [('move_id.state', '=', 'posted'), - ('reconcile_id', '=', False), - ('company_id', '=', payment.mode.company_id.id), - ('journal_id', 'in', journals.ids)] - if self.date_type == 'due': - domain += [ - '|', - ('date_maturity', '<=', self.duedate), - ('date_maturity', '=', False)] - elif self.date_type == 'move': - domain.append(('date', '<=', self.move_date)) - if self.invoice: - domain.append(('invoice', '!=', False)) - self.extend_payment_order_domain(payment, domain) - # -- end account_direct_debit -- - lines = line_obj.search(domain) - context = self.env.context.copy() - context['line_ids'] = self.filter_lines(lines) - context['populate_results'] = self.populate_results - if payment.payment_order_type == 'payment': - context['display_credit'] = True - context['display_debit'] = False - else: - context['display_credit'] = False - context['display_debit'] = True - model_datas = model_data_obj.search( - [('model', '=', 'ir.ui.view'), - ('name', '=', 'view_create_payment_order_lines')]) - return {'name': _('Entry Lines'), - 'context': context, - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'payment.order.create', - 'views': [(model_datas[0].res_id, 'form')], - 'type': 'ir.actions.act_window', - 'target': 'new', - } - @api.multi def _prepare_payment_line(self, payment, line): """This function is designed to be inherited @@ -224,23 +217,11 @@ class PaymentOrderCreate(models.TransientModel): return res @api.multi - def create_payment(self): - """This method is a slightly modified version of the existing method on - this model in account_payment. - - pass the payment mode to line2bank() - - allow invoices to create influence on the payment process: not only - 'Free' references are allowed, but others as well - - check date_to_pay is not in the past. - """ - if not self.entries: - return {'type': 'ir.actions.act_window_close'} - context = self.env.context - payment_line_obj = self.env['payment.line'] - payment = self.env['payment.order'].browse(context['active_id']) - # Populate the current payment with new lines: - for line in self.entries: - vals = self._prepare_payment_line(payment, line) - payment_line_obj.create(vals) + def create_payment_lines(self): + if self.move_line_ids: + self.move_line_ids.create_payment_line_from_move_line( + self.order_id) + return True # Force reload of payment order view as a workaround for lp:1155525 return {'name': _('Payment Orders'), 'context': context, diff --git a/account_payment_order/wizard/account_payment_line_create_view.xml b/account_payment_order/wizard/account_payment_line_create_view.xml new file mode 100644 index 000000000..85234ae2f --- /dev/null +++ b/account_payment_order/wizard/account_payment_line_create_view.xml @@ -0,0 +1,62 @@ + + + + + + + account_payment_line_create.form + account.payment.line.create + +
+ + + + + + + + +