diff --git a/account_banking_payment/__openerp__.py b/account_banking_payment/__openerp__.py index 033485126..7ff0465f0 100644 --- a/account_banking_payment/__openerp__.py +++ b/account_banking_payment/__openerp__.py @@ -38,12 +38,11 @@ 'view/account_payment.xml', 'view/banking_transaction_wizard.xml', 'view/payment_mode.xml', - 'view/payment_mode_type.xml', 'view/payment_order_create_view.xml', 'workflow/account_payment.xml', ], 'description': ''' - This addon adds payment infrastructure to the Banking Addons. + This addon adds payment reconciliation infrastructure to the Banking Addons. * Extends payments for digital banking: + Adapted workflow in payments to reflect banking operations diff --git a/account_banking_payment/model/__init__.py b/account_banking_payment/model/__init__.py index cf509d816..60600f542 100644 --- a/account_banking_payment/model/__init__.py +++ b/account_banking_payment/model/__init__.py @@ -1,6 +1,5 @@ import account_payment import payment_line -import payment_mode_type import payment_mode import payment_order_create import banking_import_transaction diff --git a/account_banking_payment/model/account_payment.py b/account_banking_payment/model/account_payment.py index bfe33fb2f..0f4763af3 100644 --- a/account_banking_payment/model/account_payment.py +++ b/account_banking_payment/model/account_payment.py @@ -104,18 +104,9 @@ class payment_order(orm.Model): "execution." ) ), - 'payment_order_type': fields.selection( - [('payment', 'Payment'),('debit', 'Direct debit')], - 'Payment order type', required=True, - readonly=True, states={'draft': [('readonly', False)]}, - ), 'date_sent': fields.date('Send date', readonly=True), } - _defaults = { - 'payment_order_type': 'payment', - } - def _write_payment_lines(self, cr, uid, ids, **kwargs): ''' ORM method for setting attributes of corresponding payment.line objects. diff --git a/account_banking_payment/model/payment_mode.py b/account_banking_payment/model/payment_mode.py index 31e1cb65b..7a3e1be98 100644 --- a/account_banking_payment/model/payment_mode.py +++ b/account_banking_payment/model/payment_mode.py @@ -49,8 +49,4 @@ class payment_mode(orm.Model): help=('Limit selected invoices to invoices with these payment ' 'terms') ), - 'payment_order_type': fields.related( - 'type', 'payment_order_type', readonly=True, type='selection', - selection=[('payment', 'Payment'), ('debit', 'Direct debit')], - string="Payment Order Type"), } diff --git a/account_banking_payment/model/payment_mode_type.py b/account_banking_payment/model/payment_mode_type.py deleted file mode 100644 index 572cce869..000000000 --- a/account_banking_payment/model/payment_mode_type.py +++ /dev/null @@ -1,41 +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 . -# -############################################################################## - -from openerp.osv import orm, fields - - -class payment_mode_type(orm.Model): - _inherit = 'payment.mode.type' - - _columns = { - 'payment_order_type': fields.selection( - [('payment', 'Payment'),('debit', 'Direct debit')], - 'Payment order type', required=True, - ), - } - - _defaults = { - 'payment_order_type': 'payment', - } diff --git a/account_banking_payment/model/payment_order_create.py b/account_banking_payment/model/payment_order_create.py index 33c10ded1..b2b339374 100644 --- a/account_banking_payment/model/payment_order_create.py +++ b/account_banking_payment/model/payment_order_create.py @@ -3,6 +3,7 @@ # # Copyright (C) 2009 EduSense BV (). # (C) 2011 - 2013 Therp BV (). +# (C) 2014 ACSONE SA/NV (). # # All other contributions are (C) by their respective contributors # @@ -23,8 +24,7 @@ # ############################################################################## -from openerp.osv import orm, fields -from openerp.tools.translate import _ +from openerp.osv import orm class payment_order_create(orm.TransientModel): @@ -32,173 +32,13 @@ class payment_order_create(orm.TransientModel): def extend_payment_order_domain( self, cr, uid, payment_order, domain, context=None): - if payment_order.payment_order_type == 'payment': - domain += [ - ('account_id.type', 'in', ('payable', 'receivable')), - ('amount_to_pay', '>', 0) - ] - return True - - def search_entries(self, cr, uid, ids, context=None): - """ - This method taken from account_payment module. - We adapt the domain based on the payment_order_type - """ - line_obj = self.pool.get('account.move.line') - mod_obj = self.pool.get('ir.model.data') - if context is None: - context = {} - data = self.read(cr, uid, ids, ['duedate'], context=context)[0] - search_due_date = data['duedate'] - - ### start account_banking_payment ### - payment = self.pool.get('payment.order').browse( - cr, uid, context['active_id'], context=context) - # Search for move line to pay: - domain = [ - ('move_id.state', '=', 'posted'), - ('reconcile_id', '=', False), - ('company_id', '=', payment.mode.company_id.id), - ] + super(self, payment_order_create).extend_payment_order_domain( + cr, uid, payment_order, domain, context=context) # apply payment term filter - if payment.mode.payment_term_ids: + if payment_order.mode.payment_term_ids: domain += [ - ('invoice.payment_term', 'in', - [term.id for term in payment.mode.payment_term_ids] + ('invoice.payment_term', 'in', + [term.id for term in payment_order.mode.payment_term_ids] ) ] - self.extend_payment_order_domain( - cr, uid, payment, domain, context=context) - ### end account_direct_debit ### - - domain = domain + [ - '|', ('date_maturity', '<=', search_due_date), - ('date_maturity', '=', False) - ] - line_ids = line_obj.search(cr, uid, domain, context=context) - context.update({'line_ids': line_ids}) - model_data_ids = mod_obj.search( - cr, uid,[ - ('model', '=', 'ir.ui.view'), - ('name', '=', 'view_create_payment_order_lines')], - context=context) - resource_id = mod_obj.read( - cr, uid, model_data_ids, fields=['res_id'], - context=context)[0]['res_id'] - return {'name': _('Entry Lines'), - 'context': context, - 'view_type': 'form', - 'view_mode': 'form', - 'res_model': 'payment.order.create', - 'views': [(resource_id, 'form')], - 'type': 'ir.actions.act_window', - 'target': 'new', - } - - def create_payment(self, cr, uid, ids, context=None): - ''' - 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. - ''' - - order_obj = self.pool.get('payment.order') - line_obj = self.pool.get('account.move.line') - payment_obj = self.pool.get('payment.line') - if context is None: - context = {} - data = self.read(cr, uid, ids, [], context=context)[0] - line_ids = data['entries'] - if not line_ids: - return {'type': 'ir.actions.act_window_close'} - - payment = order_obj.browse( - cr, uid, context['active_id'], context=context) - ### account banking - # t = None - # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context) - line2bank = line_obj.line2bank( - cr, uid, line_ids, payment.mode.id, context) - _today = fields.date.context_today(self, cr, uid, context=context) - ### end account banking - - ## Finally populate the current payment with new lines: - for line in line_obj.browse(cr, uid, line_ids, context=context): - if payment.date_prefered == "now": - #no payment date => immediate payment - date_to_pay = False - elif payment.date_prefered == 'due': - ### account_banking - # date_to_pay = line.date_maturity - date_to_pay = ( - line.date_maturity - if line.date_maturity and line.date_maturity > _today - else False) - ### end account banking - elif payment.date_prefered == 'fixed': - ### account_banking - # date_to_pay = payment.date_scheduled - date_to_pay = ( - payment.date_scheduled - if payment.date_scheduled and payment.date_scheduled > _today - else False) - ### end account banking - - ### account_banking - state = communication2 = False - communication = line.ref or '/' - if line.invoice: - if line.invoice.type in ('in_invoice', 'in_refund'): - if line.invoice.reference_type == 'structured': - state = 'structured' - communication = line.invoice.reference - else: - state = 'normal' - communication2 = line.invoice.reference - else: - # Make sure that the communication includes the - # customer invoice number (in the case of debit order) - communication = line.invoice.number.replace('/', '') - state = 'structured' - if line.invoice.number != line.ref: - communication2 = line.ref - else: - state = 'normal' - communication2 = line.ref - - # support debit orders when enabled - if (payment.payment_order_type == 'debit' and - 'amount_to_receive' in line): - amount_currency = line.amount_to_receive - else: - amount_currency = line.amount_to_pay - ### end account_banking - - payment_obj.create(cr, uid, { - 'move_line_id': line.id, - 'amount_currency': amount_currency, - 'bank_id': line2bank.get(line.id), - 'order_id': payment.id, - 'partner_id': line.partner_id and line.partner_id.id or False, - ### account banking - # 'communication': line.ref or '/' - 'communication': communication, - 'communication2': communication2, - 'state': state, - ### end account banking - 'date': date_to_pay, - 'currency': (line.invoice and line.invoice.currency_id.id - or line.journal_id.currency.id - or line.journal_id.company_id.currency_id.id), - }, context=context) - return {'name': _('Payment Orders'), - 'context': context, - 'view_type': 'form', - 'view_mode': 'form,tree', - 'res_model': 'payment.order', - 'res_id': context['active_id'], - 'type': 'ir.actions.act_window', - } + return True diff --git a/account_banking_payment/view/payment_mode.xml b/account_banking_payment/view/payment_mode.xml index 95d250652..c46823c8d 100644 --- a/account_banking_payment/view/payment_mode.xml +++ b/account_banking_payment/view/payment_mode.xml @@ -11,7 +11,6 @@ - ). # (C) 2011 - 2013 Therp BV (). +# (C) 2013 - 2014 ACSONE SA (). # # All other contributions are (C) by their respective contributors # @@ -64,6 +65,10 @@ * a better implementation of payment_mode.suitable_bank_types() based on payment.mode.type * the "make payment" button launches a wizard depending on the payment.mode.type * a manual payment mode type is provided as an example, with a default "do nothing" wizard + * add a payment_order_type (payment|debit) as a basis of direct debit support + (this field becomes visible when account_direct_debit is installed) + * make the search function of the payment export wizard extensible + * fix lp:1275478: allow payment of customer refunds ''', 'installable': True, } diff --git a/account_banking_payment_export/model/account_payment.py b/account_banking_payment_export/model/account_payment.py index e5a14e8aa..045b3d867 100644 --- a/account_banking_payment_export/model/account_payment.py +++ b/account_banking_payment_export/model/account_payment.py @@ -23,7 +23,7 @@ # ############################################################################## -from openerp.osv import orm +from openerp.osv import orm, fields from openerp.tools.translate import _ from openerp import netsvc @@ -31,6 +31,18 @@ from openerp import netsvc class payment_order(orm.Model): _inherit = 'payment.order' + _columns = { + 'payment_order_type': fields.selection( + [('payment', 'Payment'), ('debit', 'Direct debit')], + 'Payment order type', required=True, + readonly=True, states={'draft': [('readonly', False)]}, + ), + } + + _defaults = { + 'payment_order_type': 'payment', + } + def launch_wizard(self, cr, uid, ids, context=None): """ Search for a wizard to launch according to the type. diff --git a/account_banking_payment_export/model/payment_mode.py b/account_banking_payment_export/model/payment_mode.py index 0d85d3aa3..798c8ed20 100644 --- a/account_banking_payment_export/model/payment_mode.py +++ b/account_banking_payment_export/model/payment_mode.py @@ -49,4 +49,8 @@ class payment_mode(orm.Model): required=True, help='Select the Payment Type for the Payment Mode.' ), + 'payment_order_type': fields.related( + 'type', 'payment_order_type', readonly=True, type='selection', + selection=[('payment', 'Payment'), ('debit', 'Direct debit')], + string="Payment Order Type"), } diff --git a/account_banking_payment_export/model/payment_mode_type.py b/account_banking_payment_export/model/payment_mode_type.py index dbc60d5ab..a50e56a85 100644 --- a/account_banking_payment_export/model/payment_mode_type.py +++ b/account_banking_payment_export/model/payment_mode_type.py @@ -41,7 +41,7 @@ class payment_mode_type(orm.Model): 'suitable_bank_types': fields.many2many( 'res.partner.bank.type', 'bank_type_payment_type_rel', - 'pay_type_id','bank_type_id', + 'pay_type_id', 'bank_type_id', 'Suitable bank types', required=True), 'ir_model_id': fields.many2one( 'ir.model', 'Payment wizard', @@ -49,8 +49,16 @@ class payment_mode_type(orm.Model): 'Leave empty for manual processing'), domain=[('osv_memory', '=', True)], ), + 'payment_order_type': fields.selection( + [('payment', 'Payment'), ('debit', 'Direct debit')], + 'Payment order type', required=True, + ), } - + + _defaults = { + 'payment_order_type': 'payment', + } + def _auto_init(self, cr, context=None): r = super(payment_mode_type, self)._auto_init(cr, context=context) # migrate xmlid from manual_bank_transfer to avoid dependency on account_banking diff --git a/account_banking_payment_export/model/payment_order_create.py b/account_banking_payment_export/model/payment_order_create.py index 278d4327a..8e32831bc 100644 --- a/account_banking_payment_export/model/payment_order_create.py +++ b/account_banking_payment_export/model/payment_order_create.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- ############################################################################## # -# Copyright (C) 2013 ACSONE SA/NV ();. +# Copyright (C) 2009 EduSense BV (). +# (C) 2011 - 2013 Therp BV (). # # All other contributions are (C) by their respective contributors # @@ -22,37 +23,175 @@ # ############################################################################## -from openerp.osv import orm +from openerp.osv import orm, fields +from openerp.tools.translate import _ class payment_order_create(orm.TransientModel): _inherit = 'payment.order.create' + def extend_payment_order_domain( + self, cr, uid, payment_order, domain, context=None): + if payment_order.payment_order_type == 'payment': + domain += [ + ('account_id.type', 'in', ('payable', 'receivable')), + ('amount_to_pay', '>', 0) + ] + return True + + def search_entries(self, cr, uid, ids, context=None): + """ + This method taken from account_payment module. + We adapt the domain based on the payment_order_type + """ + line_obj = self.pool.get('account.move.line') + mod_obj = self.pool.get('ir.model.data') + if context is None: + context = {} + data = self.read(cr, uid, ids, ['duedate'], context=context)[0] + search_due_date = data['duedate'] + + ### start account_banking_payment ### + payment = self.pool.get('payment.order').browse( + cr, uid, context['active_id'], context=context) + # Search for move line to pay: + domain = [ + ('move_id.state', '=', 'posted'), + ('reconcile_id', '=', False), + ('company_id', '=', payment.mode.company_id.id), + ] + self.extend_payment_order_domain( + cr, uid, payment, domain, context=context) + ### end account_direct_debit ### + + domain = domain + [ + '|', ('date_maturity', '<=', search_due_date), + ('date_maturity', '=', False) + ] + line_ids = line_obj.search(cr, uid, domain, context=context) + context.update({'line_ids': line_ids}) + model_data_ids = mod_obj.search( + cr, uid,[ + ('model', '=', 'ir.ui.view'), + ('name', '=', 'view_create_payment_order_lines')], + context=context) + resource_id = mod_obj.read( + cr, uid, model_data_ids, fields=['res_id'], + context=context)[0]['res_id'] + return {'name': _('Entry Lines'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form', + 'res_model': 'payment.order.create', + 'views': [(resource_id, 'form')], + 'type': 'ir.actions.act_window', + 'target': 'new', + } + def create_payment(self, cr, uid, ids, context=None): - '''This method adapts the core create_payment() - to pass the payment mode to line2bank() through the context, - so it is in turn propagated to suitable_bank_types(). - - This is necessary because the core does not propagate the payment mode to line2bank: t = None in - http://bazaar.launchpad.net/~openerp/openobject-addons/7.0/view/head:/account_payment/wizard/account_payment_order.py#L72 - - Hack idea courtesy Stefan Rijnhart. ''' - if context is None: - context = {} + 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. + ''' + order_obj = self.pool.get('payment.order') - payment = order_obj.browse(cr, uid, context['active_id'], context=context) - context['_fix_payment_mode_id'] = payment.mode.id - return super(payment_order_create, self).create_payment(cr, uid, ids, context=context) - - -class account_move_line(orm.Model): - _inherit = 'account.move.line' - - def line2bank(self, cr, uid, ids, payment_mode_id=None, context=None): - '''Obtain payment_type from context, see create_payment above''' + line_obj = self.pool.get('account.move.line') + payment_obj = self.pool.get('payment.line') if context is None: context = {} - payment_mode_id = payment_mode_id or context.get('_fix_payment_mode_id') - return super(account_move_line, self).line2bank(cr, uid, ids, payment_mode_id, context=context) + data = self.read(cr, uid, ids, [], context=context)[0] + line_ids = data['entries'] + if not line_ids: + return {'type': 'ir.actions.act_window_close'} + payment = order_obj.browse( + cr, uid, context['active_id'], context=context) + ### account banking + # t = None + # line2bank = line_obj.line2bank(cr, uid, line_ids, t, context) + line2bank = line_obj.line2bank( + cr, uid, line_ids, payment.mode.id, context) + _today = fields.date.context_today(self, cr, uid, context=context) + ### end account banking + + ## Finally populate the current payment with new lines: + for line in line_obj.browse(cr, uid, line_ids, context=context): + if payment.date_prefered == "now": + #no payment date => immediate payment + date_to_pay = False + elif payment.date_prefered == 'due': + ### account_banking + # date_to_pay = line.date_maturity + date_to_pay = ( + line.date_maturity + if line.date_maturity and line.date_maturity > _today + else False) + ### end account banking + elif payment.date_prefered == 'fixed': + ### account_banking + # date_to_pay = payment.date_scheduled + date_to_pay = ( + payment.date_scheduled + if payment.date_scheduled and payment.date_scheduled > _today + else False) + ### end account banking + + ### account_banking + state = communication2 = False + communication = line.ref or '/' + if line.invoice: + if line.invoice.type in ('in_invoice', 'in_refund'): + if line.invoice.reference_type == 'structured': + state = 'structured' + communication = line.invoice.reference + else: + state = 'normal' + communication2 = line.invoice.reference + else: + # Make sure that the communication includes the + # customer invoice number (in the case of debit order) + communication = line.invoice.number.replace('/', '') + state = 'structured' + if line.invoice.number != line.ref: + communication2 = line.ref + else: + state = 'normal' + communication2 = line.ref + + # support debit orders when enabled + if (payment.payment_order_type == 'debit' and + 'amount_to_receive' in line): + amount_currency = line.amount_to_receive + else: + amount_currency = line.amount_to_pay + ### end account_banking + + payment_obj.create(cr, uid, { + 'move_line_id': line.id, + 'amount_currency': amount_currency, + 'bank_id': line2bank.get(line.id), + 'order_id': payment.id, + 'partner_id': line.partner_id and line.partner_id.id or False, + ### account banking + # 'communication': line.ref or '/' + 'communication': communication, + 'communication2': communication2, + 'state': state, + ### end account banking + 'date': date_to_pay, + 'currency': (line.invoice and line.invoice.currency_id.id + or line.journal_id.currency.id + or line.journal_id.company_id.currency_id.id), + }, context=context) + return {'name': _('Payment Orders'), + 'context': context, + 'view_type': 'form', + 'view_mode': 'form,tree', + 'res_model': 'payment.order', + 'res_id': context['active_id'], + 'type': 'ir.actions.act_window', + } diff --git a/account_banking_tests/__openerp__.py b/account_banking_tests/__openerp__.py index 59eff6ce9..04e3fdd70 100644 --- a/account_banking_tests/__openerp__.py +++ b/account_banking_tests/__openerp__.py @@ -37,6 +37,5 @@ dependencies installed, so that you can run the tests. If you only run the tests manually, you don't even have to install this module, only its dependencies. ''', - 'auto_install': False, 'installable': True, } diff --git a/account_direct_debit/__openerp__.py b/account_direct_debit/__openerp__.py index 5cc16dcac..12fa1d227 100644 --- a/account_direct_debit/__openerp__.py +++ b/account_direct_debit/__openerp__.py @@ -25,10 +25,12 @@ 'author': ['Therp BV', 'Smile'], 'website': 'https://launchpad.net/banking-addons', 'category': 'Banking addons', - 'depends': ['account_banking_payment'], + 'depends': ['account_banking_payment_export'], 'data': [ 'view/account_payment.xml', 'view/account_invoice.xml', + 'view/payment_mode.xml', + 'view/payment_mode_type.xml', 'workflow/account_invoice.xml', 'data/account_payment_term.xml', ], diff --git a/account_direct_debit/model/account_move_line.py b/account_direct_debit/model/account_move_line.py index d71f2f4e2..4cd7fab6c 100644 --- a/account_direct_debit/model/account_move_line.py +++ b/account_direct_debit/model/account_move_line.py @@ -87,7 +87,7 @@ class account_move_line(orm.Model): return [('id', '=', '0')] return [('id', 'in', map(lambda x:x[0], res))] - def line2bank(self, cr, uid, ids, payment_mode_id=None, context=None): + def line2bank(self, cr, uid, ids, payment_mode_id, 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 @@ -98,8 +98,6 @@ class account_move_line(orm.Model): if context is None: context = {} pay_mode_obj = self.pool['payment.mode'] - payment_mode_id = ( - payment_mode_id or context.get('_fix_payment_mode_id')) if payment_mode_id: pay_mode = pay_mode_obj.browse( cr, uid, payment_mode_id, context=context) @@ -116,7 +114,7 @@ class account_move_line(orm.Model): break return line2bank return super(account_move_line, self).line2bank( - cr, uid, ids, payment_mode_id=payment_mode_id, context=context) + cr, uid, ids, payment_mode_id, context=context) _columns = { 'amount_to_receive': fields.function( diff --git a/account_direct_debit/view/payment_mode.xml b/account_direct_debit/view/payment_mode.xml new file mode 100644 index 000000000..043990df0 --- /dev/null +++ b/account_direct_debit/view/payment_mode.xml @@ -0,0 +1,20 @@ + + + + + + + payment.mode.form.inherit + payment.mode + + + + + + + + + + diff --git a/account_banking_payment/view/payment_mode_type.xml b/account_direct_debit/view/payment_mode_type.xml similarity index 83% rename from account_banking_payment/view/payment_mode_type.xml rename to account_direct_debit/view/payment_mode_type.xml index eb8ce821a..eb726750d 100644 --- a/account_banking_payment/view/payment_mode_type.xml +++ b/account_direct_debit/view/payment_mode_type.xml @@ -2,6 +2,9 @@ + view.payment.mode.type.form payment.mode.type