mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Finalise the wizard of selection of move lines to pay
Add button "Add to payment/debit order" on invoice form view Started to integrate payment transfer in account_payment_order (not finished at all though) Various fixes/changes/improvements/...
This commit is contained in:
committed by
Enric Tobella
parent
e00c726c7b
commit
469af80ee7
@@ -28,7 +28,7 @@ Installation
|
||||
|
||||
This module depends on:
|
||||
|
||||
* account_payment
|
||||
* account_payment_partner
|
||||
* base_iban
|
||||
|
||||
This modules is part of the OCA/bank-payment suite.
|
||||
@@ -36,16 +36,16 @@ This modules is part of the OCA/bank-payment suite.
|
||||
Configuration
|
||||
=============
|
||||
|
||||
No configuration required.
|
||||
This module adds several options on Payment Modes, cf Accounting > Configuration > Management > Payment Modes.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
This module provides a menu to configure payment order types : Accounting > Configuration > Miscellaneous > Payment Export Types
|
||||
You can create a Payment Order via the menu Accounting > Payments > Payment Orders and then select the move lines to pay.
|
||||
|
||||
For further information, please visit:
|
||||
You can create a Debit Order via the menu Accounting > Payments > Debit Orders and then select the move lines to debit.
|
||||
|
||||
* https://www.odoo.com/forum/help-1
|
||||
This module also adds a button *Add to Payment Order* on supplier invoices and a button *Add to Debit Order* on customer invoices.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
@@ -58,7 +58,7 @@ Bug Tracker
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
|
||||
`here <https://github.com/OCA/bank-payment/issues/new?body=module:%20account_banking_payment_export%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
`here <https://github.com/OCA/bank-payment/issues/new?body=module:%20account_banking_payment_export%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
|
||||
Credits
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
'views/bank_payment_line.xml',
|
||||
'views/account_move_line.xml',
|
||||
'views/ir_attachment.xml',
|
||||
#'views/res_partner_bank.xml',
|
||||
'views/account_invoice_view.xml',
|
||||
'data/payment_seq.xml',
|
||||
],
|
||||
'demo': ['demo/payment_demo.xml'],
|
||||
|
||||
@@ -3,50 +3,22 @@
|
||||
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import api, models, _
|
||||
from lxml import etree
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
payment_order_ok = fields.Boolean(
|
||||
related='payment_mode_id.payment_order_ok', readonly=True)
|
||||
|
||||
@api.model
|
||||
def _get_reference_type(self):
|
||||
rt = super(AccountInvoice, self)._get_reference_type()
|
||||
rt.append(('structured', _('Structured Reference')))
|
||||
return rt
|
||||
|
||||
@api.model
|
||||
def fields_view_get(self, view_id=None, view_type=False, toolbar=False,
|
||||
submenu=False):
|
||||
"""This adds the field 'reference_type' only if the view doesn't
|
||||
contain this field (this is for customer invoice and with
|
||||
l10n_be_invoice_bba not installed).
|
||||
"""
|
||||
res = super(AccountInvoice, self).fields_view_get(
|
||||
view_id=view_id, view_type=view_type, toolbar=toolbar,
|
||||
submenu=submenu)
|
||||
if view_type != 'form':
|
||||
return res
|
||||
field_name = 'reference_type'
|
||||
doc = etree.XML(res['arch'])
|
||||
if not doc.xpath("//field[@name='%s']" % field_name):
|
||||
nodes = doc.xpath("//field[@name='origin']")
|
||||
if nodes:
|
||||
field = self.fields_get([field_name])[field_name]
|
||||
field_xml = etree.Element(
|
||||
'field', {'name': field_name,
|
||||
'widget': 'selection',
|
||||
'states': str(field['states']),
|
||||
'selection': str(field['selection']),
|
||||
'required': '1' if field['required'] else '0',
|
||||
'string': field['string'],
|
||||
'nolabel': '0'})
|
||||
nodes[0].addnext(field_xml)
|
||||
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"""
|
||||
@@ -56,3 +28,72 @@ class AccountInvoice(models.Model):
|
||||
if invoice.type in ('in_invoice', 'in_refund'):
|
||||
res['partner_bank_id'] = invoice.partner_bank_id.id or False
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _prepare_new_payment_order(self):
|
||||
self.ensure_one()
|
||||
vals = {
|
||||
'payment_mode_id': self.payment_mode_id.id,
|
||||
'payment_type': self.payment_mode_id.payment_type,
|
||||
}
|
||||
if self.payment_mode_id.bank_account_link == 'fixed':
|
||||
vals['journal_id'] = self.payment_mode_id.fixed_journal_id.id
|
||||
# TODO : else: no filter on allowed bank accounts, because onchange not played ??
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def create_account_payment_line(self):
|
||||
apoo = self.env['account.payment.order']
|
||||
aplo = self.env['account.payment.line']
|
||||
action = {}
|
||||
for inv in self:
|
||||
if not inv.payment_mode_id:
|
||||
raise UserError(_(
|
||||
"No Payment Mode on invoice %s") % inv.number)
|
||||
if not inv.move_id:
|
||||
raise UserError(_(
|
||||
"No Journal Entry on invoice %s") % inv.number)
|
||||
payorders = apoo.search([
|
||||
('payment_mode_id', '=', inv.payment_mode_id.id),
|
||||
('state', '=', 'draft')])
|
||||
if payorders:
|
||||
payorder = payorders[0]
|
||||
new_payorder = False
|
||||
else:
|
||||
payorder = apoo.create(inv._prepare_new_payment_order())
|
||||
new_payorder = True
|
||||
count = 0
|
||||
for line in inv.move_id.line_ids:
|
||||
if line.account_id == inv.account_id and not line.reconciled:
|
||||
paylines = aplo.search([
|
||||
('move_line_id', '=', line.id),
|
||||
('state', '!=', 'cancel')])
|
||||
if paylines:
|
||||
continue
|
||||
line.create_payment_line_from_move_line(payorder)
|
||||
count += 1
|
||||
if count:
|
||||
if new_payorder:
|
||||
inv.message_post(_(
|
||||
'%d payment lines added to the new draft payment '
|
||||
'order %s which has been automatically created.')
|
||||
% (count, payorder.name))
|
||||
else:
|
||||
inv.message_post(_(
|
||||
'%d payment lines added to the existing draft '
|
||||
'payment order %s.')
|
||||
% (count, payorder.name))
|
||||
else:
|
||||
raise UserError(_(
|
||||
'No Payment Line created for invoice %s because '
|
||||
'it already exists or because this invoice is '
|
||||
'already paid.') % inv.number)
|
||||
action = self.env['ir.actions.act_window'].for_xml_id(
|
||||
'account_payment_order',
|
||||
'account_payment_order_%s_action' % payorder.payment_type)
|
||||
action.update({
|
||||
'view_mode': 'form,tree,pivot,graph',
|
||||
'res_id': payorder.id,
|
||||
'views': False,
|
||||
})
|
||||
return action
|
||||
|
||||
@@ -45,17 +45,22 @@ class AccountMoveLine(models.Model):
|
||||
self.ensure_one()
|
||||
assert payment_order, 'Missing payment order'
|
||||
aplo = self.env['account.payment.line']
|
||||
# default values for communication_type and communication
|
||||
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:
|
||||
# change these default values if move line is linked to an invoice
|
||||
if self.invoice_id:
|
||||
if self.invoice_id.reference_type != 'none':
|
||||
communication = self.invoice_id.reference
|
||||
ref2comm_type =\
|
||||
aplo.invoice_reference_type2communication_type()
|
||||
communication_type =\
|
||||
ref2comm_type[self.invoice_id.reference_type]
|
||||
else:
|
||||
if (
|
||||
self.invoice_id.type in ('in_invoice', 'in_refund')
|
||||
and self.invoice_id.reference):
|
||||
communication = self.invoice_id.reference
|
||||
if self.currency_id:
|
||||
currency_id = self.currency_id.id
|
||||
amount_currency = self.amount_residual_currency
|
||||
@@ -66,7 +71,6 @@ class AccountMoveLine(models.Model):
|
||||
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,
|
||||
|
||||
@@ -20,6 +20,9 @@ class AccountPaymentLine(models.Model):
|
||||
related='order_id.company_currency_id', store=True, readonly=True)
|
||||
payment_type = fields.Selection(
|
||||
related='order_id.payment_type', store=True, readonly=True)
|
||||
state = fields.Selection(
|
||||
related='order_id.state', string='State',
|
||||
readonly=True, store=True)
|
||||
move_line_id = fields.Many2one(
|
||||
'account.move.line', string='Journal Item')
|
||||
ml_maturity_date = fields.Date(
|
||||
@@ -83,6 +86,11 @@ class AccountPaymentLine(models.Model):
|
||||
values = []
|
||||
for field in bplo.same_fields_payment_line_and_bank_payment_line():
|
||||
values.append(unicode(self[field]))
|
||||
# Don't group the payment lines that are attached to the same supplier
|
||||
# but to move lines with different accounts (very unlikely),
|
||||
# for easier generation/comprehension of the transfer move
|
||||
# TODO Alexis : but this is for ????
|
||||
values.append(unicode(self.move_line_id.account_id or False))
|
||||
hashcode = '-'.join(values)
|
||||
return hashcode
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields, api
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import ValidationError
|
||||
|
||||
|
||||
class AccountPaymentMode(models.Model):
|
||||
@@ -42,6 +43,38 @@ class AccountPaymentMode(models.Model):
|
||||
"* Payment Date\n"
|
||||
"(other modules can set additional fields to restrict the "
|
||||
"grouping.)")
|
||||
transfer_move = fields.Boolean(
|
||||
'Generate Accounting Entries On File Upload')
|
||||
transfer_account_id = fields.Many2one(
|
||||
'account.account', string='Transfer Account',
|
||||
domain=[('internal_type', '=', 'other'), ('reconcile', '=', True)],
|
||||
help="Pay off lines in 'file uploaded' payment orders with a move on "
|
||||
"this account. You can only select accounts of type regular "
|
||||
"that are marked for reconciliation")
|
||||
transfer_journal_id = fields.Many2one(
|
||||
'account.journal', string='Transfer Journal',
|
||||
help='Journal to write payment entries when confirming '
|
||||
'payment/debit orders of this mode')
|
||||
transfer_move_option = fields.Selection([
|
||||
('date', 'One move per payment date'),
|
||||
('line', 'One move per payment line'),
|
||||
], string='Transfer Move Option', default='date')
|
||||
|
||||
@api.multi
|
||||
@api.constrains(
|
||||
'transfer_move', 'transfer_account_id', 'transfer_journal_id',
|
||||
'transfer_move_option')
|
||||
def transfer_move_constrains(self):
|
||||
for mode in self:
|
||||
if mode.transfer_move and (
|
||||
not mode.transfer_account_id or
|
||||
not mode.transfer_journal_id or
|
||||
not mode.transfer_move_option):
|
||||
raise ValidationError(_(
|
||||
"The option 'Generate Accounting Entries On File Upload' "
|
||||
"is active on payment mode '%s', so the three parameters "
|
||||
"'Transfer Account', 'Transfer Journal' and "
|
||||
"'Transfer Move Option' must be set.") % mode.name)
|
||||
|
||||
@api.onchange('payment_method_id')
|
||||
def payment_method_id_change(self):
|
||||
|
||||
@@ -35,7 +35,9 @@ class AccountPaymentOrder(models.Model):
|
||||
related='payment_mode_id.bank_account_link', readonly=True)
|
||||
journal_id = fields.Many2one(
|
||||
'account.journal', string='Bank Journal',
|
||||
required=True)
|
||||
readonly=True, states={'draft': [('readonly', False)]})
|
||||
# The journal_id field is only required at confirm step, to
|
||||
# allow auto-creation of payment order from invoice
|
||||
company_partner_bank_id = fields.Many2one(
|
||||
related='journal_id.bank_account_id', string='Company Bank Account',
|
||||
readonly=True)
|
||||
@@ -174,6 +176,9 @@ class AccountPaymentOrder(models.Model):
|
||||
bplo = self.env['bank.payment.line']
|
||||
today = fields.Date.context_today(self)
|
||||
for order in self:
|
||||
if not order.journal_id:
|
||||
raise UserError(_(
|
||||
'Missing Bank Journal on payment order %s') % order.name)
|
||||
# Delete existing bank payment lines
|
||||
order.bank_line_ids.unlink()
|
||||
# Create the bank payment lines from the payment lines
|
||||
@@ -257,5 +262,144 @@ class AccountPaymentOrder(models.Model):
|
||||
|
||||
@api.multi
|
||||
def generated2uploaded(self):
|
||||
for order in self:
|
||||
if order.payment_mode_id.transfer_move:
|
||||
order.generate_transfer_move()
|
||||
self.write({'state': 'uploaded'})
|
||||
return True
|
||||
|
||||
# Generation of transfer move
|
||||
@api.multi
|
||||
def _prepare_transfer_move(self):
|
||||
vals = {
|
||||
'journal_id': self.mode.transfer_journal_id.id,
|
||||
'ref': '%s %s' % (
|
||||
self.payment_order_type[:3].upper(), self.reference)
|
||||
}
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def _prepare_move_line_transfer_account(
|
||||
self, amount, move, bank_payment_lines, labels):
|
||||
if len(bank_payment_lines) == 1:
|
||||
partner_id = bank_payment_lines[0].partner_id.id
|
||||
name = _('%s bank line %s') % (labels[self.payment_order_type],
|
||||
bank_payment_lines[0].name)
|
||||
else:
|
||||
partner_id = False
|
||||
name = '%s %s' % (
|
||||
labels[self.payment_order_type], self.reference)
|
||||
date_maturity = bank_payment_lines[0].date
|
||||
vals = {
|
||||
'name': name,
|
||||
'move_id': move.id,
|
||||
'partner_id': partner_id,
|
||||
'account_id': self.mode.transfer_account_id.id,
|
||||
'credit': (self.payment_order_type == 'payment' and
|
||||
amount or 0.0),
|
||||
'debit': (self.payment_order_type == 'debit' and
|
||||
amount or 0.0),
|
||||
'date_maturity': date_maturity,
|
||||
}
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def _prepare_move_line_partner_account(self, bank_line, move, labels):
|
||||
# TODO : ALEXIS check don't group if move_line_id.account_id
|
||||
# is not the same
|
||||
if bank_line.payment_line_ids[0].move_line_id:
|
||||
account_id =\
|
||||
bank_line.payment_line_ids[0].move_line_id.account_id.id
|
||||
else:
|
||||
if self.payment_order_type == 'debit':
|
||||
account_id =\
|
||||
bank_line.partner_id.property_account_receivable.id
|
||||
else:
|
||||
account_id = bank_line.partner_id.property_account_payable.id
|
||||
vals = {
|
||||
'name': _('%s line %s') % (
|
||||
labels[self.payment_order_type], bank_line.name),
|
||||
'move_id': move.id,
|
||||
'partner_id': bank_line.partner_id.id,
|
||||
'account_id': account_id,
|
||||
'credit': (self.payment_order_type == 'debit' and
|
||||
bank_line.amount_currency or 0.0),
|
||||
'debit': (self.payment_order_type == 'payment' and
|
||||
bank_line.amount_currency or 0.0),
|
||||
}
|
||||
return vals
|
||||
|
||||
@api.multi
|
||||
def action_sent_no_move_line_hook(self, pay_line):
|
||||
"""This function is designed to be inherited"""
|
||||
return
|
||||
|
||||
@api.multi
|
||||
def _create_move_line_partner_account(self, bank_line, move, labels):
|
||||
"""This method is designed to be inherited in a custom module"""
|
||||
# TODO: take multicurrency into account
|
||||
company_currency = self.env.user.company_id.currency_id
|
||||
if bank_line.currency != company_currency:
|
||||
raise UserError(_(
|
||||
"Cannot generate the transfer move when "
|
||||
"the currency of the payment (%s) is not the "
|
||||
"same as the currency of the company (%s). This "
|
||||
"is not supported for the moment.")
|
||||
% (bank_line.currency.name, company_currency.name))
|
||||
aml_obj = self.env['account.move.line']
|
||||
# create the payment/debit counterpart move line
|
||||
# on the partner account
|
||||
partner_ml_vals = self._prepare_move_line_partner_account(
|
||||
bank_line, move, labels)
|
||||
partner_move_line = aml_obj.create(partner_ml_vals)
|
||||
|
||||
# register the payment/debit move line
|
||||
# on the payment line and call reconciliation on it
|
||||
bank_line.write({'transit_move_line_id': partner_move_line.id})
|
||||
|
||||
@api.multi
|
||||
def _reconcile_payment_lines(self, bank_payment_lines):
|
||||
for bline in bank_payment_lines:
|
||||
if all([pline.move_line_id for pline in bline.payment_line_ids]):
|
||||
bline.debit_reconcile()
|
||||
else:
|
||||
self.action_sent_no_move_line_hook(bline)
|
||||
|
||||
@api.multi
|
||||
def generate_transfer_move(self):
|
||||
"""
|
||||
Create the moves that pay off the move lines from
|
||||
the debit order.
|
||||
"""
|
||||
self.ensure_one()
|
||||
am_obj = self.env['account.move']
|
||||
aml_obj = self.env['account.move.line']
|
||||
labels = {
|
||||
'outbound': _('Payment'),
|
||||
'inbound': _('Direct debit'),
|
||||
}
|
||||
# prepare a dict "trfmoves" that can be used when
|
||||
# self.mode.transfer_move_option = date or line
|
||||
# key = unique identifier (date or True or line.id)
|
||||
# value = [pay_line1, pay_line2, ...]
|
||||
trfmoves = {}
|
||||
for bline in self.bank_line_ids:
|
||||
hashcode = bline.move_line_transfer_account_hashcode()
|
||||
if hashcode in trfmoves:
|
||||
trfmoves[hashcode].append(bline)
|
||||
else:
|
||||
trfmoves[hashcode] = [bline]
|
||||
|
||||
for hashcode, blines in trfmoves.iteritems():
|
||||
mvals = self._prepare_transfer_move()
|
||||
move = am_obj.create(mvals)
|
||||
total_amount = 0
|
||||
for bline in blines:
|
||||
total_amount += bline.amount_currency
|
||||
self._create_move_line_partner_account(bline, move, labels)
|
||||
# create the payment/debit move line on the transfer account
|
||||
trf_ml_vals = self._prepare_move_line_transfer_account(
|
||||
total_amount, move, blines, labels)
|
||||
aml_obj.create(trf_ml_vals)
|
||||
self._reconcile_payment_lines(blines)
|
||||
move.post()
|
||||
|
||||
@@ -29,6 +29,7 @@ class BankPaymentLine(models.Model):
|
||||
readonly=True)
|
||||
# Function Float fields are sometimes badly displayed in tree view,
|
||||
# see bug report https://github.com/odoo/odoo/issues/8632
|
||||
# But is it still true in v9 ?
|
||||
amount_currency = fields.Monetary(
|
||||
string='Amount', currency_field='currency_id',
|
||||
compute='_compute_amount', store=True, readonly=True)
|
||||
@@ -48,6 +49,28 @@ class BankPaymentLine(models.Model):
|
||||
company_id = fields.Many2one(
|
||||
related='order_id.payment_mode_id.company_id', store=True,
|
||||
readonly=True)
|
||||
# TODO : not shown in view ?
|
||||
# why on bank payment line and not on payment line ?
|
||||
transit_move_line_id = fields.Many2one(
|
||||
'account.move.line', string='Transfer Move Line', readonly=True,
|
||||
help="Move line through which the payment/debit order "
|
||||
"pays the invoice")
|
||||
transfer_move_line_id = fields.Many2one(
|
||||
'account.move.line', compute='_get_transfer_move_line',
|
||||
string='Transfer move line counterpart',
|
||||
help="Counterpart move line on the transfer account")
|
||||
|
||||
@api.multi
|
||||
def _get_transfer_move_line(self):
|
||||
for bank_line in self:
|
||||
if bank_line.transit_move_line_id:
|
||||
payment_type = bank_line.payment_type
|
||||
trf_lines = bank_line.transit_move_line_id.move_id.line_id
|
||||
for move_line in trf_lines:
|
||||
if payment_type == 'inbound' and move_line.debit > 0:
|
||||
bank_line.transfer_move_line_id = move_line
|
||||
elif payment_type == 'outbound' and move_line.credit > 0:
|
||||
bank_line.transfer_move_line_id = move_line
|
||||
|
||||
@api.model
|
||||
def same_fields_payment_line_and_bank_payment_line(self):
|
||||
@@ -76,3 +99,17 @@ class BankPaymentLine(models.Model):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'bank.payment.line') or 'New'
|
||||
return super(BankPaymentLine, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def move_line_transfer_account_hashcode(self):
|
||||
"""
|
||||
This method is inherited in the module
|
||||
account_banking_sepa_direct_debit
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.order_id.payment_mode_id.transfer_move_option == 'date':
|
||||
hashcode = self.date
|
||||
else:
|
||||
hashcode = unicode(self.id)
|
||||
return hashcode
|
||||
|
||||
|
||||
55
account_payment_order/views/account_invoice_view.xml
Normal file
55
account_payment_order/views/account_invoice_view.xml
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2016 Akretion (http://www.akretion.com/)
|
||||
@author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
The licence is in the file __openerp__.py
|
||||
-->
|
||||
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="invoice_form" model="ir.ui.view">
|
||||
<field name="name">account_payment_order.invoice_form</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account_payment_partner.invoice_form" />
|
||||
<field name="arch" type="xml">
|
||||
<button name="%(account.action_account_invoice_payment)d" type="action" position="after">
|
||||
<button name="create_account_payment_line" type="object"
|
||||
string="Add to Debit Order"
|
||||
groups="account_payment_order.group_account_payment"
|
||||
attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"/>
|
||||
<!-- For customer refunds:
|
||||
'Add to Direct Debit Order' will deduct the refund from a customer invoice
|
||||
We could also need a button 'Add to Payment Order' to reimburse
|
||||
a customer via wire transfer... but I prefer to keep things
|
||||
simple ; to do that, the user should manually create a payment order
|
||||
and select the move lines -->
|
||||
</button>
|
||||
<field name="payment_mode_id" position="after">
|
||||
<field name="payment_order_ok" invisible="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="invoice_supplier_form" model="ir.ui.view">
|
||||
<field name="name">account_payment_order.invoice_supplier_form</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="inherit_id" ref="account_payment_partner.invoice_supplier_form" />
|
||||
<field name="arch" type="xml">
|
||||
<button name="%(account.action_account_invoice_payment)d" type="action" position="after">
|
||||
<button name="create_account_payment_line" type="object"
|
||||
string="Add to Payment Order"
|
||||
groups="account_payment_order.group_account_payment"
|
||||
attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"/>
|
||||
</button>
|
||||
<field name="payment_mode_id" position="after">
|
||||
<field name="payment_order_ok" invisible="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -19,6 +19,16 @@
|
||||
<field name="default_invoice"/>
|
||||
<field name="default_date_type"/>
|
||||
</group>
|
||||
<group name="trf-move-config" string="Accounting Entries Options">
|
||||
<field name="transfer_move"/>
|
||||
<field name="transfer_account_id"
|
||||
attrs="{'invisible': [('transfer_move', '=', False)], 'required': [('transfer_move', '=', True)]}"
|
||||
context="{'default_internal_type': 'other', 'default_reconcile': True, 'default_company_id': company_id}"/>
|
||||
<field name="transfer_journal_id"
|
||||
attrs="{'invisible': [('transfer_move', '=', False)], 'required': [('transfer_move', '=', True)]}"/>
|
||||
<field name="transfer_move_option"
|
||||
attrs="{'invisible': [('transfer_move', '=', False)], 'required': [('transfer_move', '=', True)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
<field name="model">account.payment.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Payment Orders">
|
||||
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="open" string="Confirmed" domain="[('state', '=', 'open')]"/>
|
||||
<filter name="generated" string="File Generated" domain="[('state', '=', 'generated')]"/>
|
||||
<filter name="uploaded" string="File Uploaded" domain="[('state', '=', 'uploaded')]"/>
|
||||
<filter name="done" string="Done" domain="[('state', '=', 'done')]"/>
|
||||
<group string="Group By" name="groupby">
|
||||
<filter name="payment_mode_groupby" string="Payment Mode" context="{'group_by': 'payment_mode_id'}"/>
|
||||
<filter name="journal_groupby" string="Bank Journal" context="{'group_by': 'journal_id'}"/>
|
||||
@@ -98,10 +103,33 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment_order_graph" model="ir.ui.view">
|
||||
<field name="name">account.payment.order.graph</field>
|
||||
<field name="model">account.payment.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Payment Orders">
|
||||
<field name="date_generated" type="row" interval="month"/>
|
||||
<field name="total_company_currency" type="measure"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="account_payment_order_pivot" model="ir.ui.view">
|
||||
<field name="name">account.payment.order.pivot</field>
|
||||
<field name="model">account.payment.order</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Payment Orders">
|
||||
<field name="date_generated" type="row" interval="month"/>
|
||||
<field name="total_company_currency" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="account_payment_order_outbound_action" model="ir.actions.act_window">
|
||||
<field name="name">Payment Orders</field>
|
||||
<field name="res_model">account.payment.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,form,pivot,graph</field>
|
||||
<field name="domain">[('payment_type', '=', 'outbound')]</field>
|
||||
<field name="context">{'default_payment_type': 'outbound'}</field>
|
||||
</record>
|
||||
@@ -109,7 +137,7 @@
|
||||
<record id="account_payment_order_inbound_action" model="ir.actions.act_window">
|
||||
<field name="name">Debit Orders</field>
|
||||
<field name="res_model">account.payment.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,form,pivot,graph</field>
|
||||
<field name="domain">[('payment_type', '=', 'inbound')]</field>
|
||||
<field name="context">{'default_payment_type': 'inbound'}</field>
|
||||
</record>
|
||||
|
||||
@@ -102,6 +102,13 @@ class AccountPaymentLineCreate(models.TransientModel):
|
||||
('debit', '>', 0),
|
||||
('account_id.internal_type', '=', 'receivable'),
|
||||
]
|
||||
# Exclude lines that are already in a non-cancelled payment order
|
||||
paylines = self.env['account.payment.line'].search([
|
||||
('state', '!=', 'cancel'),
|
||||
('move_line_id', '!=', False)])
|
||||
if paylines:
|
||||
move_lines_ids = [payline.move_line_id.id for payline in paylines]
|
||||
domain += [('id', 'not in', move_lines_ids)]
|
||||
return domain
|
||||
|
||||
@api.multi
|
||||
@@ -127,106 +134,9 @@ class AccountPaymentLineCreate(models.TransientModel):
|
||||
res = {'domain': {'move_line_ids': domain}}
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def filter_lines(self, lines):
|
||||
""" Filter move lines before proposing them for inclusion
|
||||
in the payment order.
|
||||
|
||||
This implementation filters out move lines that are already
|
||||
included in draft or open payment orders. This prevents the
|
||||
user to include the same line in two different open payment
|
||||
orders. When the payment order is sent, it is assumed that
|
||||
the move will be reconciled soon (or immediately with
|
||||
account_banking_payment_transfer), so it will not be
|
||||
proposed anymore for payment.
|
||||
|
||||
See also https://github.com/OCA/bank-payment/issues/93.
|
||||
|
||||
:param lines: recordset of move lines
|
||||
:returns: list of move line ids
|
||||
"""
|
||||
self.ensure_one()
|
||||
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 _prepare_payment_line(self, payment, line):
|
||||
"""This function is designed to be inherited
|
||||
The resulting dict is passed to the create method of payment.line"""
|
||||
self.ensure_one()
|
||||
_today = fields.Date.context_today(self)
|
||||
date_to_pay = False # no payment date => immediate payment
|
||||
if 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 = 'normal'
|
||||
communication = line.ref or '-'
|
||||
if line.invoice:
|
||||
if line.invoice.reference_type == 'structured':
|
||||
state = 'structured'
|
||||
# Fallback to invoice number to keep previous behaviour
|
||||
communication = line.invoice.reference or line.invoice.number
|
||||
else:
|
||||
if line.invoice.type in ('in_invoice', 'in_refund'):
|
||||
communication = (
|
||||
line.invoice.reference or
|
||||
line.invoice.supplier_invoice_number or line.ref)
|
||||
else:
|
||||
# Make sure that the communication includes the
|
||||
# customer invoice number (in the case of debit order)
|
||||
communication = line.invoice.number
|
||||
# support debit orders when enabled
|
||||
if line.debit > 0:
|
||||
amount_currency = line.amount_residual_currency * -1
|
||||
else:
|
||||
amount_currency = line.amount_residual_currency
|
||||
if payment.payment_order_type == 'debit':
|
||||
amount_currency *= -1
|
||||
line2bank = line.line2bank(payment.mode.id)
|
||||
# -- end account banking
|
||||
res = {'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': communication,
|
||||
'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)}
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
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,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'payment.order',
|
||||
'res_id': context['active_id'],
|
||||
'type': 'ir.actions.act_window'}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
placeholder="Keep empty for using all journals"/>
|
||||
<field name="payment_mode"/>
|
||||
<field name="invoice"/>
|
||||
<button name="populate" type="object" string="Populate"/>
|
||||
<label string="Click on Add All Move Lines to auto-select the move lines matching the above criteria or click on Add an item to manually select the move lines filtered by the above criteria." colspan="2"/>
|
||||
<button name="populate" type="object" string="Add All Move Lines"/>
|
||||
</group>
|
||||
<group name="move_lines" string="Selected Move Lines to Create Transactions">
|
||||
<field name="move_line_ids" nolabel="1">
|
||||
|
||||
Reference in New Issue
Block a user