From 8f9fada3517de1abc9039aa79ad4ec668200f0d5 Mon Sep 17 00:00:00 2001 From: Stefan Rijnhart Date: Sat, 16 Mar 2013 17:44:19 +0100 Subject: [PATCH 01/39] [RFR] Split off payment functionality in a different addon --- account_banking/__openerp__.py | 1 - account_banking/account_banking.py | 475 ------------------ account_banking/account_banking_view.xml | 87 ---- account_banking/banking_import_transaction.py | 368 ++------------ account_banking/data/account_banking_data.xml | 7 - account_banking/security/ir.model.access.csv | 1 - account_banking/wizard/__init__.py | 2 - account_banking/wizard/bank_import.py | 3 - .../wizard/banking_transaction_wizard.py | 9 - .../wizard/banking_transaction_wizard.xml | 8 - account_banking_payment/__init__.py | 1 + account_banking_payment/__openerp__.py | 55 ++ .../banking_import_line.py | 45 ++ .../data/payment_mode_type.xml | 12 + account_banking_payment/model/__init__.py | 10 + .../model/account_bank_statement_line.py | 15 + .../model/account_payment.py | 246 +++++++++ .../model}/bank_payment_manual.py | 0 .../model/banking_import_transaction.py | 385 ++++++++++++++ .../model/banking_transaction_wizard.py | 41 ++ account_banking_payment/model/payment_line.py | 221 ++++++++ account_banking_payment/model/payment_mode.py | 52 ++ .../model/payment_mode_type.py | 62 +++ .../model/payment_order_create.py | 20 +- .../security/ir.model.access.csv | 2 + .../view/account_payment.xml | 45 ++ .../view/banking_transaction_wizard.xml | 35 ++ .../view/payment_mode_type.xml | 47 ++ .../workflow/account_payment.xml | 21 +- 29 files changed, 1331 insertions(+), 945 deletions(-) create mode 100644 account_banking_payment/__init__.py create mode 100644 account_banking_payment/__openerp__.py create mode 100644 account_banking_payment/banking_import_line.py create mode 100644 account_banking_payment/data/payment_mode_type.xml create mode 100644 account_banking_payment/model/__init__.py create mode 100644 account_banking_payment/model/account_bank_statement_line.py create mode 100644 account_banking_payment/model/account_payment.py rename {account_banking/wizard => account_banking_payment/model}/bank_payment_manual.py (100%) create mode 100644 account_banking_payment/model/banking_import_transaction.py create mode 100644 account_banking_payment/model/banking_transaction_wizard.py create mode 100644 account_banking_payment/model/payment_line.py create mode 100644 account_banking_payment/model/payment_mode.py create mode 100644 account_banking_payment/model/payment_mode_type.py rename account_banking/wizard/account_payment_order.py => account_banking_payment/model/payment_order_create.py (90%) create mode 100644 account_banking_payment/security/ir.model.access.csv create mode 100644 account_banking_payment/view/account_payment.xml create mode 100644 account_banking_payment/view/banking_transaction_wizard.xml create mode 100644 account_banking_payment/view/payment_mode_type.xml rename account_banking/account_banking_workflow.xml => account_banking_payment/workflow/account_payment.xml (69%) diff --git a/account_banking/__openerp__.py b/account_banking/__openerp__.py index 552803eb6..41110935b 100644 --- a/account_banking/__openerp__.py +++ b/account_banking/__openerp__.py @@ -43,7 +43,6 @@ 'data/account_banking_data.xml', 'wizard/bank_import_view.xml', 'account_banking_view.xml', - 'account_banking_workflow.xml', 'wizard/banking_transaction_wizard.xml', 'workflow/account_invoice.xml', ], diff --git a/account_banking/account_banking.py b/account_banking/account_banking.py index be2f61e78..c9a35114d 100644 --- a/account_banking/account_banking.py +++ b/account_banking/account_banking.py @@ -272,68 +272,6 @@ class account_banking_imported_file(osv.osv): } account_banking_imported_file() -class payment_mode_type(osv.osv): - _name= 'payment.mode.type' - _description= 'Payment Mode Type' - _columns= { - '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' - ), - # Setting suitable_bank_types to required pending - # https://bugs.launchpad.net/openobject-addons/+bug/786845 - 'suitable_bank_types': fields.many2many( - 'res.partner.bank.type', - 'bank_type_payment_type_rel', - 'pay_type_id','bank_type_id', - 'Suitable bank types', required=True), - 'ir_model_id': fields.many2one( - 'ir.model', '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', 'Direct debit')], - 'Payment order type', required=True, - ), - } - - _defaults = { - 'payment_order_type': lambda *a: 'payment', - } - -payment_mode_type() - -class payment_mode(osv.osv): - ''' Restoring the payment type from version 5, - used to select the export wizard (if any) ''' - _inherit = "payment.mode" - - 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) - if (payment_mode and payment_mode.type and - payment_mode.type.suitable_bank_types): - res = [type.code for type in payment_mode.type.suitable_bank_types] - return res - - _columns = { - 'type': fields.many2one( - 'payment.mode.type', 'Payment type', - help='Select the Payment Type for the Payment Mode.' - ), - } -payment_mode() - class account_bank_statement(osv.osv): ''' Extensions from account_bank_statement: @@ -785,419 +723,6 @@ class account_bank_statement_line(osv.osv): account_bank_statement_line() -class payment_line(osv.osv): - ''' - Add extra export_state and date_done fields; make destination bank account - mandatory, as it makes no sense to send payments into thin air. - Edit: Payments can be by cash too, which is prohibited by mandatory bank - accounts. - ''' - _inherit = 'payment.line' - _columns = { - # New fields - 'export_state': fields.selection([ - ('draft', 'Draft'), - ('open','Confirmed'), - ('cancel','Cancelled'), - ('sent', 'Sent'), - ('rejected', 'Rejected'), - ('done','Done'), - ], 'State', select=True - ), - 'msg': fields.char('Message', size=255, required=False, readonly=True), - - # Redefined fields: added states - 'date_done': fields.datetime('Date Confirmed', select=True, - readonly=True), - 'name': fields.char( - 'Your Reference', size=64, required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'communication': fields.char( - 'Communication', size=64, required=False, - help=("Used as the message between ordering customer and current " - "company. Depicts 'What do you want to say to the recipient" - " about this order ?'" - ), - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'communication2': fields.char( - 'Communication 2', size=128, - help='The successor message of Communication.', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'move_line_id': fields.many2one( - 'account.move.line', 'Entry line', - domain=[('reconcile_id','=', False), - ('account_id.type', '=','payable') - ], - help=('This Entry Line will be referred for the information of ' - 'the ordering customer.' - ), - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'amount_currency': fields.float( - 'Amount in Partner Currency', digits=(16,2), - required=True, - help='Payment amount in the partner currency', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'currency': fields.many2one( - 'res.currency', 'Partner Currency', required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'bank_id': fields.many2one( - 'res.partner.bank', 'Destination Bank account', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'order_id': fields.many2one( - 'payment.order', 'Order', required=True, - ondelete='cascade', select=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'partner_id': fields.many2one( - 'res.partner', string="Partner", required=True, - help='The Ordering Customer', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'date': fields.date( - 'Payment Date', - help=("If no payment date is specified, the bank will treat this " - "payment line directly" - ), - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'state': fields.selection([ - ('normal','Free'), - ('structured','Structured') - ], 'Communication Type', required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - } - _defaults = { - 'export_state': lambda *a: 'draft', - 'date_done': lambda *a: False, - 'msg': lambda *a: '', - } - - def fields_get(self, cr, uid, fields=None, context=None): - res = super(payment_line, self).fields_get(cr, uid, fields, context) - if 'communication' in res: - res['communication'].setdefault('states', {}) - res['communication']['states']['structured'] = [('required', True)] - if 'communication2' in res: - res['communication2'].setdefault('states', {}) - res['communication2']['states']['structured'] = [('readonly', True)] - res['communication2']['states']['normal'] = [('readonly', False)] - - return res - - """ - Hooks for processing direct debit orders, such as implemented in - account_direct_debit module. - """ - def get_storno_account_id(self, cr, uid, payment_line_id, amount, - currency_id, context=None): - """ - Hook for verifying a match of the payment line with the amount. - Return the account associated with the storno. - Used in account_banking interactive mode - :param payment_line_id: the single payment line id - :param amount: the (signed) amount debited from the bank account - :param currency: the bank account's currency *browse object* - :return: an account if there is a full match, False otherwise - :rtype: database id of an account.account resource. - """ - - return False - - def debit_storno(self, cr, uid, payment_line_id, amount, - currency_id, storno_retry=True, context=None): - """ - Hook for handling a canceled item of a direct debit order. - Presumably called from a bank statement import routine. - - Decide on the direction that the invoice's workflow needs to take. - You may optionally return an incomplete reconcile for the caller - to reconcile the now void payment. - - :param payment_line_id: the single payment line id - :param amount: the (negative) amount debited from the bank account - :param currency: the bank account's currency *browse object* - :param boolean storno_retry: whether the storno is considered fatal \ - or not. - :return: an incomplete reconcile for the caller to fill - :rtype: database id of an account.move.reconcile resource. - """ - - return False - -payment_line() - -class payment_order(osv.osv): - ''' - Enable extra states for payment exports - ''' - _inherit = 'payment.order' - - _columns = { - 'date_scheduled': fields.date( - 'Scheduled date if fixed', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - help='Select a date if you have chosen Preferred Date to be fixed.' - ), - 'reference': fields.char( - 'Reference', size=128, required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'mode': fields.many2one( - 'payment.mode', 'Payment mode', select=True, required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - help='Select the Payment Mode to be applied.', - ), - 'state': fields.selection([ - ('draft', 'Draft'), - ('open','Confirmed'), - ('cancel','Cancelled'), - ('sent', 'Sent'), - ('rejected', 'Rejected'), - ('done','Done'), - ], 'State', select=True - ), - 'line_ids': fields.one2many( - 'payment.line', 'order_id', 'Payment lines', - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'user_id': fields.many2one( - 'res.users','User', required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - ), - 'date_prefered': fields.selection([ - ('now', 'Directly'), - ('due', 'Due date'), - ('fixed', 'Fixed date') - ], "Preferred date", change_default=True, required=True, - states={ - 'sent': [('readonly', True)], - 'rejected': [('readonly', True)], - 'done': [('readonly', True)] - }, - help=("Choose an option for the Payment Order:'Fixed' stands for a " - "date specified by you.'Directly' stands for the direct " - "execution.'Due date' stands for the scheduled date of " - "execution." - ) - ), - 'payment_order_type': fields.selection( - [('payment', 'Payment'),('debit', 'Direct debit')], - 'Payment order type', required=True, - ), - 'date_sent': fields.date('Send date', readonly=True), - } - - _defaults = { - 'payment_order_type': lambda *a: 'payment', - } - - def launch_wizard(self, cr, uid, ids, context=None): - """ - 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 - """ - if context == None: - context = {} - result = {} - orders = self.browse(cr, uid, ids, context) - order = orders[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'] = ids - wizard_model = order.mode.type.ir_model_id.model - wizard_obj = self.pool.get(wizard_model) - wizard_id = wizard_obj.create(cr, uid, {}, context) - result = { - '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', - 'res_id': wizard_id, - 'nodestroy': True, - } - else: - # should all be manual orders without type or wizard model - for order in orders[1:]: - if order.mode.type and order.mode.type.ir_model_id: - raise osv.except_osv( - _('Error'), - _('You can only combine payment orders of the same type') - ) - # process manual payments - wf_service = netsvc.LocalService('workflow') - for order_id in ids: - wf_service.trg_validate(uid, 'payment.order', order_id, 'sent', cr) - return result - - def _write_payment_lines(self, cursor, uid, ids, **kwargs): - ''' - ORM method for setting attributes of corresponding payment.line objects. - Note that while this is ORM compliant, it is also very ineffecient due - to the absence of filters on writes and hence the requirement to - filter on the client(=OpenERP server) side. - ''' - if not hasattr(ids, '__iter__'): - ids = [ids] - payment_line_obj = self.pool.get('payment.line') - line_ids = payment_line_obj.search( - cursor, uid, [ - ('order_id', 'in', ids) - ]) - payment_line_obj.write(cursor, uid, line_ids, kwargs) - - def set_to_draft(self, cursor, uid, ids, *args): - ''' - Set both self and payment lines to state 'draft'. - ''' - self._write_payment_lines(cursor, uid, ids, export_state='draft') - return super(payment_order, self).set_to_draft( - cursor, uid, ids, *args - ) - - def action_sent(self, cursor, uid, ids, *args): - ''' - Set both self and payment lines to state 'sent'. - ''' - self._write_payment_lines(cursor, uid, ids, export_state='sent') - self.write(cursor, uid, ids, {'state':'sent', - 'date_sent': time.strftime('%Y-%m-%d')}) - return True - - def action_rejected(self, cursor, uid, ids, *args): - ''' - Set both self and payment lines to state 'rejected'. - ''' - self._write_payment_lines(cursor, uid, ids, export_state='rejected') - wf_service = netsvc.LocalService('workflow') - for id in ids: - wf_service.trg_validate(uid, 'payment.order', id, 'rejected', cursor) - return True - - def set_done(self, cursor, uid, ids, *args): - ''' - Extend standard transition to update children as well. - ''' - self._write_payment_lines(cursor, uid, ids, - export_state='done', - date_done=time.strftime('%Y-%m-%d') - ) - return super(payment_order, self).set_done( - cursor, uid, ids, *args - ) - - def get_wizard(self, type): - ''' - Intercept manual bank payments to include 'sent' state. Default - 'manual' payments are flagged 'done' immediately. - ''' - if type == 'BANKMAN': - # Note that self._module gets overwritten by inheriters, so make - # the module name hard coded. - return 'account_banking', 'wizard_account_banking_payment_manual' - return super(payment_order, self).get_wizard(type) - - """ - Hooks for processing direct debit orders, such as implemented in - account_direct_debit module. - """ - def debit_reconcile_transfer( - self, cr, uid, payment_order_id, amount, currency, context=None): - """ - Reconcile the payment order if the amount is correct. Return the - id of the reconciliation. - """ - raise osv.except_osv( - _("Cannot reconcile"), - _("Cannot reconcile debit order: "+ - "Not implemented.")) - - def debit_unreconcile_transfer( - self, cr, uid, payment_order_id, reconcile_id, amount, currency, - context=None): - """ Unreconcile the payment_order if at all possible """ - raise osv.except_osv( - _("Cannot unreconcile"), - _("Cannot unreconcile debit order: "+ - "Not implemented.")) - -payment_order() class res_partner_bank(osv.osv): ''' diff --git a/account_banking/account_banking_view.xml b/account_banking/account_banking_view.xml index 4b26380a0..b251e079c 100644 --- a/account_banking/account_banking_view.xml +++ b/account_banking/account_banking_view.xml @@ -330,45 +330,6 @@ - - - - account.payment.order.form.banking-1 - - payment.order - form - - - - - - - - - payment.mode.form.inherit - payment.mode - - form - - - - - - - - payment.mode.tree.inherit - payment.mode - - tree - - - - - - - - - - view.payment.mode.type.form - payment.mode.type - form - -
- - - - - - - -
- - - - - - - Bank statement line tree view account.bank.statement.line diff --git a/account_banking/banking_import_transaction.py b/account_banking/banking_import_transaction.py index aad6cc8a8..ba15bcef1 100644 --- a/account_banking/banking_import_transaction.py +++ b/account_banking/banking_import_transaction.py @@ -123,43 +123,6 @@ class banking_import_transaction(osv.osv): # return move_lines to mix with the rest return [x for x in invoice.move_id.line_id if x.account_id.reconcile] - def _match_debit_order( - self, cr, uid, trans, log, context=None): - - def is_zero(total): - return self.pool.get('res.currency').is_zero( - cr, uid, trans.statement_id.currency, total) - - payment_order_obj = self.pool.get('payment.order') - order_ids = payment_order_obj.search( - cr, uid, [('payment_order_type', '=', 'debit'), - ('state', '=', 'sent'), - ('date_sent', '<=', str2date(trans.execution_date, - '%Y-%m-%d')) - ], - limit=0, context=context) - orders = payment_order_obj.browse(cr, uid, order_ids, context) - candidates = [x for x in orders if - is_zero(x.total - trans.transferred_amount)] - if len(candidates) > 0: - # retrieve the common account_id, if any - account_id = False - for line in candidates[0].line_ids[0].debit_move_line_id.move_id.line_id: - if line.account_id.type == 'other': - account_id = line.account_id.id - break - return dict( - move_line_ids = False, - match_type = 'payment_order', - payment_order_ids = [x.id for x in candidates], - account_id = account_id, - partner_id = False, - partner_bank_id = False, - reference = False, - type='general', - ) - return False - def _match_invoice(self, cr, uid, trans, move_lines, partner_ids, bank_account_ids, log, linked_invoices, @@ -542,101 +505,6 @@ class banking_import_transaction(osv.osv): {'voucher_id': voucher_id}, context=context) transaction.refresh() - def _confirm_storno( - self, cr, uid, transaction_id, context=None): - """ - Creation of the reconciliation has been delegated to - *a* direct debit module, to allow for various direct debit styles - """ - payment_line_pool = self.pool.get('payment.line') - statement_line_pool = self.pool.get('account.bank.statement.line') - transaction = self.browse(cr, uid, transaction_id, context=context) - if not transaction.payment_line_id: - raise osv.except_osv( - _("Cannot link with storno"), - _("No direct debit order item")) - reconcile_id = payment_line_pool.debit_storno( - cr, uid, - transaction.payment_line_id.id, - transaction.statement_line_id.amount, - transaction.statement_line_id.currency, - transaction.storno_retry, - context=context) - statement_line_pool.write( - cr, uid, transaction.statement_line_id.id, - {'reconcile_id': reconcile_id}, context=context) - transaction.refresh() - - def _confirm_payment_order( - self, cr, uid, transaction_id, context=None): - """ - Creation of the reconciliation has been delegated to - *a* direct debit module, to allow for various direct debit styles - """ - payment_order_obj = self.pool.get('payment.order') - statement_line_pool = self.pool.get('account.bank.statement.line') - transaction = self.browse(cr, uid, transaction_id, context=context) - if not transaction.payment_order_id: - raise osv.except_osv( - _("Cannot reconcile"), - _("Cannot reconcile: no direct debit order")) - if transaction.payment_order_id.payment_order_type != 'debit': - raise osv.except_osv( - _("Cannot reconcile"), - _("Reconcile payment order not implemented")) - reconcile_id = payment_order_obj.debit_reconcile_transfer( - cr, uid, - transaction.payment_order_id.id, - transaction.statement_line_id.amount, - transaction.statement_line_id.currency, - context=context) - statement_line_pool.write( - cr, uid, transaction.statement_line_id.id, - {'reconcile_id': reconcile_id}, context=context) - - def _confirm_payment( - self, cr, uid, transaction_id, context=None): - """ - Do some housekeeping on the payment line - then pass on to _reconcile_move - """ - transaction = self.browse(cr, uid, transaction_id, context=context) - payment_line_obj = self.pool.get('payment.line') - payment_line_obj.write( - cr, uid, transaction.payment_line_id.id, { - 'export_state': 'done', - 'date_done': transaction.statement_line_id.date, - } - ) - self._confirm_move(cr, uid, transaction_id, context=context) - - def _cancel_payment( - self, cr, uid, transaction_id, context=None): - raise osv.except_osv( - _("Cannot unreconcile"), - _("Cannot unreconcile: this operation is not yet supported for " - "match type 'payment'")) - - def _cancel_payment_order( - self, cr, uid, transaction_id, context=None): - """ - """ - payment_order_obj = self.pool.get('payment.order') - transaction = self.browse(cr, uid, transaction_id, context=context) - if not transaction.payment_order_id: - raise osv.except_osv( - _("Cannot unreconcile"), - _("Cannot unreconcile: no direct debit order")) - if transaction.payment_order_id.payment_order_type != 'debit': - raise osv.except_osv( - _("Cannot unreconcile"), - _("Unreconcile payment order not implemented")) - return payment_order_obj.debit_unreconcile_transfer( - cr, uid, transaction.payment_order_id.id, - transaction.statement_line_id.reconcile_id.id, - transaction.statement_line_id.amount, - transaction.statement_line_id.currency) - def _legacy_do_move_unreconcile(self, cr, uid, move_line_ids, currency, context=None): """ Legacy method. Allow for canceling bank statement lines that @@ -768,70 +636,10 @@ class banking_import_transaction(osv.osv): return True - def _cancel_storno( - self, cr, uid, transaction_id, context=None): - """ - TODO: delegate unreconciliation to the direct debit module, - to allow for various direct debit styles - """ - payment_line_obj = self.pool.get('payment.line') - reconcile_obj = self.pool.get('account.move.reconcile') - transaction = self.browse(cr, uid, transaction_id, context=context) - - if not transaction.payment_line_id: - raise osv.except_osv( - _("Cannot cancel link with storno"), - _("No direct debit order item")) - if not transaction.payment_line_id.storno: - raise osv.except_osv( - _("Cannot cancel link with storno"), - _("The direct debit order item is not marked for storno")) - - journal = transaction.statement_line_id.statement_id.journal_id - if transaction.statement_line_id.amount >= 0: - account_id = journal.default_credit_account_id.id - else: - account_id = journal.default_debit_account_id.id - cancel_line = False - move_lines = [] - for move in transaction.statement_line_id.move_ids: - # There should usually be just one move, I think - move_lines += move.line_id - for line in move_lines: - if line.account_id.id != account_id: - cancel_line = line - break - if not cancel_line: - raise osv.except_osv( - _("Cannot cancel link with storno"), - _("Line id not found")) - reconcile = cancel_line.reconcile_id or cancel_line.reconcile_partial_id - lines_reconcile = reconcile.line_id or reconcile.line_partial_ids - if len(lines_reconcile) < 3: - # delete the full reconciliation - reconcile_obj.unlink(cr, uid, reconcile.id, context) - else: - # we are left with a partial reconciliation - reconcile_obj.write( - cr, uid, reconcile.id, - {'line_partial_ids': - [(6, 0, [x.id for x in lines_reconcile if x.id != cancel_line.id])], - 'line_id': [(6, 0, [])], - }, context) - # redo the original payment line reconciliation with the invoice - payment_line_obj.write( - cr, uid, transaction.payment_line_id.id, - {'storno': False}, context) - payment_line_obj.debit_reconcile( - cr, uid, transaction.payment_line_id.id, context) - cancel_map = { - 'storno': _cancel_storno, 'invoice': _cancel_voucher, 'manual': _cancel_voucher, 'move': _cancel_voucher, - 'payment_order': _cancel_payment_order, - 'payment': _cancel_payment, } def cancel(self, cr, uid, ids, context=None): @@ -850,11 +658,8 @@ class banking_import_transaction(osv.osv): return True confirm_map = { - 'storno': _confirm_storno, 'invoice': _confirm_move, 'manual': _confirm_move, - 'payment_order': _confirm_payment_order, - 'payment': _confirm_payment, 'move': _confirm_move, } @@ -892,66 +697,6 @@ class banking_import_transaction(osv.osv): """ return True - def _match_storno( - self, cr, uid, trans, log, context=None): - payment_line_obj = self.pool.get('payment.line') - line_ids = payment_line_obj.search( - cr, uid, [ - ('order_id.payment_order_type', '=', 'debit'), - ('order_id.state', 'in', ['sent', 'done']), - ('communication', '=', trans.reference) - ], context=context) - # stornos MUST have an exact match - if len(line_ids) == 1: - account_id = payment_line_obj.get_storno_account_id( - cr, uid, line_ids[0], trans.transferred_amount, - trans.statement_id.currency, context=None) - if account_id: - return dict( - account_id = account_id, - match_type = 'storno', - payment_line_id = line_ids[0], - move_line_ids=False, - partner_id=False, - partner_bank_id=False, - reference=False, - type='customer', - ) - # TODO log the reason why there is no result for transfers marked - # as storno - return False - - def _match_payment(self, cr, uid, trans, payment_lines, - partner_ids, bank_account_ids, log, linked_payments): - ''' - Find the payment order belonging to this reference - if there is one - This is the easiest part: when sending payments, the returned bank info - should be identical to ours. - This also means that we do not allow for multiple candidates. - ''' - # TODO: Not sure what side effects are created when payments are done - # for credited customer invoices, which will be matched later on too. - digits = dp.get_precision('Account')(cr)[1] - candidates = [x for x in payment_lines - if x.communication == trans.reference - and round(x.amount, digits) == -round(trans.transferred_amount, digits) - and trans.remote_account in (x.bank_id.acc_number, - x.bank_id.acc_number_domestic) - ] - if len(candidates) == 1: - candidate = candidates[0] - # Check cache to prevent multiple matching of a single payment - if candidate.id not in linked_payments: - linked_payments[candidate.id] = True - move_info = self._get_move_info(cr, uid, [candidate.move_line_id.id]) - move_info.update({ - 'match_type': 'payment', - 'payment_line_id': candidate.id, - }) - return move_info - - return False - signal_duplicate_keys = [ # does not include float values # such as transferred_amount @@ -1059,6 +804,22 @@ class banking_import_transaction(osv.osv): retval['invoice_ids'] = [x.invoice.id for x in move_lines] retval['type'] = type_map[move_lines[0].invoice.type] return retval + + def move_info2values(move_info): + vals = {} + vals['match_type'] = move_info['match_type'] + vals['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])] + vals['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])] + vals['move_line_id'] = (move_info.get('move_line_ids', False) and + len(move_info['move_line_ids']) == 1 and + move_info['move_line_ids'][0] + ) + if move_info['match_type'] == 'invoice': + vals['invoice_id'] = (move_info.get('invoice_ids', False) and + len(move_info['invoice_ids']) == 1 and + move_info['invoice_ids'][0] + ) + return vals def match(self, cr, uid, ids, results=None, context=None): if not ids: @@ -1069,6 +830,7 @@ class banking_import_transaction(osv.osv): journal_obj = self.pool.get('account.journal') move_line_obj = self.pool.get('account.move.line') payment_line_obj = self.pool.get('payment.line') + has_payment = bool(payment_line_obj) statement_line_obj = self.pool.get('account.bank.statement.line') statement_obj = self.pool.get('account.bank.statement') payment_order_obj = self.pool.get('payment.order') @@ -1098,14 +860,15 @@ class banking_import_transaction(osv.osv): # communication. Most likely there are much less sent payments # than reconciled and open/draft payments. # Strangely, payment_orders still do not have company_id - cr.execute("SELECT l.id FROM payment_order o, payment_line l " - "WHERE l.order_id = o.id AND " - "o.state = 'sent' AND " - "l.date_done IS NULL" - ) - payment_line_ids = [x[0] for x in cr.fetchall()] - if payment_line_ids: - payment_lines = payment_line_obj.browse(cr, uid, payment_line_ids) + if has_payment: + payment_line_ids = payment_line_obj.search( + cr, uid, [ + ('order_id.state', '=', 'sent'), + ('date_done', '=', False)], context=context) + payment_lines = payment_line_obj.browse( + cr, uid, payment_line_ids) + else: + payment_lines = False # Start the loop over the transactions requested to match transactions = self.browse(cr, uid, ids, context) @@ -1270,10 +1033,10 @@ class banking_import_transaction(osv.osv): # rebrowse the current record after writing transaction = self.browse(cr, uid, transaction.id, context=context) # Match full direct debit orders - if transaction.type == bt.DIRECT_DEBIT: + if transaction.type == bt.DIRECT_DEBIT and has_payment: move_info = self._match_debit_order( cr, uid, transaction, results['log'], context) - if transaction.type == bt.STORNO: + if transaction.type == bt.STORNO and has_payment: move_info = self._match_storno( cr, uid, transaction, results['log'], context) # Allow inclusion of generated bank invoices @@ -1340,6 +1103,10 @@ class banking_import_transaction(osv.osv): if (not move_info and transaction.transferred_amount < 0 and payment_lines): # Link open payment - if any + # Note that _match_payment is defined in the + # account_banking_payment module which should be installed + # automatically if account_payment is. And if account_payment + # is not installed, then payment_lines will be empty. move_info = self._match_payment( cr, uid, transaction, payment_lines, partner_ids, @@ -1385,28 +1152,12 @@ class banking_import_transaction(osv.osv): self_values = {} if move_info: results['trans_matched_cnt'] += 1 - self_values['match_type'] = move_info['match_type'] - self_values['payment_line_id'] = move_info.get('payment_line_id', False) - self_values['move_line_ids'] = [(6, 0, move_info.get('move_line_ids') or [])] - self_values['invoice_ids'] = [(6, 0, move_info.get('invoice_ids') or [])] - self_values['payment_order_ids'] = [(6, 0, move_info.get('payment_order_ids') or [])] - self_values['payment_order_id'] = (move_info.get('payment_order_ids', False) and - len(move_info['payment_order_ids']) == 1 and - move_info['payment_order_ids'][0] - ) - self_values['move_line_id'] = (move_info.get('move_line_ids', False) and - len(move_info['move_line_ids']) == 1 and - move_info['move_line_ids'][0] - ) - if move_info['match_type'] == 'invoice': - self_values['invoice_id'] = (move_info.get('invoice_ids', False) and - len(move_info['invoice_ids']) == 1 and - move_info['invoice_ids'][0] - ) + self_values.update( + self.move_info2values(move_info)) + # values['match_type'] = move_info['match_type'] values['partner_id'] = move_info['partner_id'] values['partner_bank_id'] = move_info['partner_bank_id'] values['type'] = move_info['type'] - # values['match_type'] = move_info['match_type'] else: values['partner_id'] = values['partner_bank_id'] = False if not values['partner_id'] and partner_ids and len(partner_ids) == 1: @@ -1446,34 +1197,6 @@ class banking_import_transaction(osv.osv): statement_obj.button_dummy( cr, uid, imported_statement_ids, context=context) - if payment_lines: - # As payments lines are treated as individual transactions, the - # batch as a whole is only marked as 'done' when all payment lines - # have been reconciled. - cr.execute( - "SELECT DISTINCT o.id " - "FROM payment_order o, payment_line l " - "WHERE o.state = 'sent' " - "AND o.id = l.order_id " - "AND o.id NOT IN (" - "SELECT DISTINCT order_id AS id " - "FROM payment_line " - "WHERE date_done IS NULL " - "AND id IN (%s)" - ")" % (','.join([str(x) for x in payment_line_ids])) - ) - order_ids = [x[0] for x in cr.fetchall()] - if order_ids: - # Use workflow logics for the orders. Recode logic from - # account_payment, in order to increase efficiency. - payment_order_obj.set_done(cr, uid, order_ids, - {'state': 'done'} - ) - wf_service = netsvc.LocalService('workflow') - for id in order_ids: - wf_service.trg_validate( - uid, 'payment.order', id, 'done', cr) - def _get_residual(self, cr, uid, ids, name, args, context=None): """ Calculate the residual against the candidate reconciliation. @@ -1518,10 +1241,6 @@ class banking_import_transaction(osv.osv): elif transaction.match_type == 'invoice': if transaction.invoice_ids and not transaction.invoice_id: res[transaction.id] = True - elif transaction.match_type == 'payment_order': - if (transaction.payment_order_ids and not - transaction.payment_order_id): - res[transaction.id] = True return res def clear_and_write(self, cr, uid, ids, vals=None, context=None): @@ -1535,12 +1254,10 @@ class banking_import_transaction(osv.osv): 'invoice_id', 'manual_invoice_id', 'manual_move_line_id', - 'payment_line_id', ]] + [(x, [(6, 0, [])]) for x in [ 'move_line_ids', 'invoice_ids', - 'payment_order_ids', ]])) write_vals.update(vals or {}) return self.write(cr, uid, ids, write_vals, context=context) @@ -1645,23 +1362,15 @@ class banking_import_transaction(osv.osv): # match fields 'match_type': fields.selection( [('manual', 'Manual'), ('move','Move'), ('invoice', 'Invoice'), - ('payment', 'Payment'), ('payment_order', 'Payment order'), - ('storno', 'Storno')], - 'Match type'), + ], 'Match type'), 'match_multi': fields.function( _get_match_multi, method=True, string='Multi match', type='boolean'), - 'payment_order_ids': fields.many2many( - 'payment.order', 'banking_transaction_payment_order_rel', - 'order_id', 'transaction_id', 'Payment orders'), - 'payment_order_id': fields.many2one( - 'payment.order', 'Payment order to reconcile'), 'move_line_ids': fields.many2many( 'account.move.line', 'banking_transaction_move_line_rel', 'move_line_id', 'transaction_id', 'Matching entries'), 'move_line_id': fields.many2one( 'account.move.line', 'Entry to reconcile'), - 'payment_line_id': fields.many2one('payment.line', 'Payment line'), 'invoice_ids': fields.many2many( 'account.invoice', 'banking_transaction_invoice_rel', 'invoice_id', 'transaction_id', 'Matching invoices'), @@ -1722,9 +1431,8 @@ class account_bank_statement_line(osv.osv): 'match_type': fields.related( 'import_transaction_id', 'match_type', type='selection', selection=[('manual', 'Manual'), ('move','Move'), - ('invoice', 'Invoice'), ('payment', 'Payment'), - ('payment_order', 'Payment order'), - ('storno', 'Storno')], + ('invoice', 'Invoice'), + ], string='Match type', readonly=True,), 'state': fields.selection( [('draft', 'Draft'), ('confirmed', 'Confirmed')], 'State', diff --git a/account_banking/data/account_banking_data.xml b/account_banking/data/account_banking_data.xml index 6a662268d..3d47ad718 100644 --- a/account_banking/data/account_banking_data.xml +++ b/account_banking/data/account_banking_data.xml @@ -20,12 +20,5 @@ - - - Manual Bank Transfer - BANKMAN - - diff --git a/account_banking/security/ir.model.access.csv b/account_banking/security/ir.model.access.csv index 498785595..5e9d5f05b 100644 --- a/account_banking/security/ir.model.access.csv +++ b/account_banking/security/ir.model.access.csv @@ -2,6 +2,5 @@ "access_account_banking_settings","account.banking.account.settings","model_account_banking_account_settings","account.group_account_manager",1,1,1,1 "access_account_banking_settings_user","account.banking.account.settings user","model_account_banking_account_settings","account.group_account_user",1,0,0,0 "access_account_banking_import","account.bankimport","model_account_banking_imported_file","account.group_account_user",1,1,1,1 -"access_payment_mode_type","payment.mode.type","model_payment_mode_type","account_payment.group_account_payment",1,1,1,1 "access_banking_import_transaction","Banking addons - Bank import transaction","model_banking_import_transaction","account.group_account_user",1,1,1,1 "access_banking_transaction_wizard","Banking addons - Transaction wizard","model_banking_transaction_wizard","account.group_account_user",1,1,1,1 diff --git a/account_banking/wizard/__init__.py b/account_banking/wizard/__init__.py index 242510630..22c76197e 100644 --- a/account_banking/wizard/__init__.py +++ b/account_banking/wizard/__init__.py @@ -19,8 +19,6 @@ # ############################################################################## import bank_import -import bank_payment_manual -import account_payment_order import banking_transaction_wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_banking/wizard/bank_import.py b/account_banking/wizard/bank_import.py index 9dc222272..8d09e6c76 100644 --- a/account_banking/wizard/bank_import.py +++ b/account_banking/wizard/bank_import.py @@ -85,13 +85,10 @@ class banking_import_line(osv.osv_memory): 'invoice_ids': fields.many2many( 'account.invoice', 'banking_import_line_invoice_rel', 'line_id', 'invoice_id'), - 'payment_order_id': fields.many2one('payment.order', 'Payment order'), 'partner_bank_id': fields.many2one('res.partner.bank', 'Bank Account'), 'transaction_type': fields.selection([ # TODO: payment terminal etc... ('invoice', 'Invoice payment'), - ('payment_order_line', 'Payment from a payment order'), - ('payment_order', 'Aggregate payment order'), ('storno', 'Canceled debit order'), ('bank_costs', 'Bank costs'), ('unknown', 'Unknown'), diff --git a/account_banking/wizard/banking_transaction_wizard.py b/account_banking/wizard/banking_transaction_wizard.py index 53d2158d3..2be8827d3 100644 --- a/account_banking/wizard/banking_transaction_wizard.py +++ b/account_banking/wizard/banking_transaction_wizard.py @@ -320,15 +320,6 @@ class banking_transaction_wizard(osv.osv_memory): 'import_transaction_id', 'writeoff_journal_id', type='many2one', relation='account.journal', string='Write-off journal'), - 'payment_line_id': fields.related( - 'import_transaction_id', 'payment_line_id', string="Matching payment or storno", - type='many2one', relation='payment.line', readonly=True), - 'payment_order_ids': fields.related( - 'import_transaction_id', 'payment_order_ids', string="Matching payment orders", - type='many2many', relation='payment.order'), - 'payment_order_id': fields.related( - 'import_transaction_id', 'payment_order_id', string="Payment order to reconcile", - type='many2one', relation='payment.order'), 'invoice_ids': fields.related( 'import_transaction_id', 'invoice_ids', string="Matching invoices", type='many2many', relation='account.invoice'), diff --git a/account_banking/wizard/banking_transaction_wizard.xml b/account_banking/wizard/banking_transaction_wizard.xml index 1d76fd29c..47aa7bab0 100644 --- a/account_banking/wizard/banking_transaction_wizard.xml +++ b/account_banking/wizard/banking_transaction_wizard.xml @@ -8,7 +8,6 @@
- @@ -36,9 +35,6 @@