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:
Alexis de Lattre
2016-05-06 01:16:20 +02:00
parent 3c8c2e9e70
commit abb052d894
28 changed files with 446 additions and 330 deletions

View File

@@ -16,7 +16,6 @@ class AccountMoveLine(models.Model):
def _prepare_payment_line_vals(self, payment_order): def _prepare_payment_line_vals(self, payment_order):
vals = super(AccountMoveLine, self)._prepare_payment_line_vals( vals = super(AccountMoveLine, self)._prepare_payment_line_vals(
payment_order) payment_order)
# TODO : test on the view field "mandate required ?"
if payment_order.payment_type == 'inbound' and self.mandate_id: if payment_order.payment_type == 'inbound' and self.mandate_id:
vals['mandate_id'] = self.mandate_id.id or False vals['mandate_id'] = self.mandate_id.id or False
vals['partner_bank_id'] = self.mandate_id.partner_bank_id.id or False vals['partner_bank_id'] = self.mandate_id.partner_bank_id.id or False

View File

@@ -16,7 +16,8 @@ Installation
============ ============
This module depends on : This module depends on :
- account_banking_payment_export
- account_payment_order
This module is part of the OCA/bank-payment suite. This module is part of the OCA/bank-payment suite.
@@ -30,11 +31,6 @@ Usage
See 'readme' files of the OCA/bank-payment suite. See 'readme' files of the OCA/bank-payment suite.
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@@ -46,7 +42,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. 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. 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 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_pain_base%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_pain_base%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits Credits
======= =======
@@ -54,7 +50,7 @@ Credits
Contributors Contributors
------------ ------------
* Alexis de Lattre * Alexis de Lattre <alexis.delattre@akretion.com>
* Pedro M. Baeza * Pedro M. Baeza
* Stéphane Bidoul <stephane.bidoul@acsone.eu> * Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Ignacio Ibeas - Acysos S.L. * Ignacio Ibeas - Acysos S.L.

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# © 2014 ACSONE SA (<http://acsone.eu>).
# © 2014 Akretion (www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, workflow, api
class AccountMoveReconcile(models.Model):
_inherit = 'account.move.reconcile'
@api.multi
def unlink(self):
"""
Workflow triggers upon unreconcile. This should go into the core.
"""
line_ids = []
for reconcile in self:
for move_line in reconcile.line_id:
line_ids.append(move_line.id)
res = super(AccountMoveReconcile, self).unlink()
for line_id in line_ids:
workflow.trg_trigger(
self._uid, 'account.move.line', line_id, self._cr)
return res

View File

@@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
# © 2009 EduSense BV (<http://www.edusense.nl>)
# © 2011-2013 Therp BV (<http://therp.nl>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api
class PaymentLine(models.Model):
'''
Add some 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'
msg = fields.Char('Message', required=False, readonly=True, default='')
date_done = fields.Date('Date Confirmed', select=True, readonly=True)
@api.multi
def payment_line_hashcode(self):
"""
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
"""
res = super(PaymentLine, self).payment_line_hashcode()
res += '-' + unicode(
self.move_line_id and self.move_line_id.account_id or False)
return res

View File

@@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# © 2009 EduSense BV (<http://www.edusense.nl>)
# © 2011-2013 Therp BV (<http://therp.nl>)
# © 2014 Akretion (www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields
class PaymentMode(models.Model):
_inherit = "payment.mode"
transfer_account_id = fields.Many2one(
'account.account', string='Transfer account',
domain=[('type', '=', 'other'), ('reconcile', '=', True)],
help='Pay off lines in sent 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 '
'a debit order 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')

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!--
Add the payment mode transfer account settings
-->
<record id="view_payment_mode_form_inherit" model="ir.ui.view">
<field name="name">payment.mode.form.inherit</field>
<field name="model">payment.mode</field>
<field name="inherit_id" ref="account_banking_payment_export.view_payment_mode_form_inherit"/>
<field name="arch" type="xml">
<xpath expr="/form/group[@col='4']" position="inside">
<group name="trf-move-config" string="Transfer move settings" colspan="2">
<field name="transfer_account_id"
domain="[('type', '=', 'other'),
('reconcile', '=', True),
('company_id', '=', company_id)]"
context="{
'default_type': 'other',
'default_reconcile': True,
'default_company_id': company_id}"
/>
<field name="transfer_journal_id"
domain="[('company_id', '=', company_id)]"
/>
<field name="transfer_move_option"/>
</group>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -39,10 +39,6 @@ Usage
* You need to choose first an SEPA export type on a payment mode. * You need to choose first an SEPA export type on a payment mode.
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@@ -54,7 +50,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. 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. 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 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_sepa_credit_transfer%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_sepa_credit_transfer%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits Credits
======= =======
@@ -62,7 +58,7 @@ Credits
Contributors Contributors
------------ ------------
* Alexis de Lattre * Alexis de Lattre <alexis.delattre@akretion.com>
* Pedro M. Baeza * Pedro M. Baeza
* Stéphane Bidoul <stephane.bidoul@acsone.eu> * Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Stefan Rijnhart * Stefan Rijnhart

View File

@@ -23,8 +23,9 @@ Installation
============ ============
This module depends on : This module depends on :
* account_direct_debit * account_direct_debit
* account_banking_pain_base', * account_banking_pain_base
* account_banking_mandate * account_banking_mandate
This module is part of the OCA/bank-payment suite. This module is part of the OCA/bank-payment suite.
@@ -39,11 +40,7 @@ To configure this module, you need to:
Usage Usage
===== =====
To use this module, you must select this payment mode on a direct debit order (Menu :Accounting > Payment > Direct Debit orders) To use this module, you must select this payment mode on a direct debit order (Menu :Accounting > Payment > Debit Orders)
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@@ -56,7 +53,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. 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. 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 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_sepa_direct_debit%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_sepa_direct_debit%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits Credits
======= =======
@@ -64,7 +61,7 @@ Credits
Contributors Contributors
------------ ------------
* Alexis de Lattre * Alexis de Lattre <alexis.delattre@akretion.com>
* Pedro M. Baeza * Pedro M. Baeza
* Stéphane Bidoul <stephane.bidoul@acsone.eu> * Stéphane Bidoul <stephane.bidoul@acsone.eu>
* Alexandre Fayolle * Alexandre Fayolle

View File

@@ -319,11 +319,6 @@ msgstr ""
msgid "SEPA Direct Debit Files" msgid "SEPA Direct Debit Files"
msgstr "" msgstr ""
#. module: account_banking_sepa_direct_debit
#: model:ir.actions.act_window,name:account_banking_sepa_direct_debit.mandate_action
msgid "SEPA Direct Debit Mandates"
msgstr ""
#. module: account_banking_sepa_direct_debit #. module: account_banking_sepa_direct_debit
#: view:banking.export.sdd.wizard:account_banking_sepa_direct_debit.banking_export_sdd_wizard_view #: view:banking.export.sdd.wizard:account_banking_sepa_direct_debit.banking_export_sdd_wizard_view
msgid "SEPA Direct Debit XML file generation" msgid "SEPA Direct Debit XML file generation"

View File

@@ -402,11 +402,6 @@ msgstr "Mandats SEPA"
msgid "SEPA Creditor Identifier" msgid "SEPA Creditor Identifier"
msgstr "Identifiant créancier SEPA" msgstr "Identifiant créancier SEPA"
#. module: account_banking_sepa_direct_debit
#: model:ir.actions.act_window,name:account_banking_sepa_direct_debit.mandate_action
msgid "SEPA Direct Debit Mandates"
msgstr "Mandats de prélèvement SEPA"
#. module: account_banking_sepa_direct_debit #. module: account_banking_sepa_direct_debit
#: view:banking.export.sdd.wizard:account_banking_sepa_direct_debit.banking_export_sdd_wizard_view #: view:banking.export.sdd.wizard:account_banking_sepa_direct_debit.banking_export_sdd_wizard_view
msgid "SEPA Direct Debit XML file generation" msgid "SEPA Direct Debit XML file generation"

View File

@@ -57,7 +57,7 @@
</record> </record>
<record id="account_payment_mode_action" model="ir.actions.act_window"> <record id="account_payment_mode_action" model="ir.actions.act_window">
<field name="name">Payment Mode</field> <field name="name">Payment Modes</field>
<field name="res_model">account.payment.mode</field> <field name="res_model">account.payment.mode</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
</record> </record>

View File

@@ -2,7 +2,8 @@
<openerp> <openerp>
<data> <data>
<!-- Show acc_type on res.partner.bank in order to be able to
detect wrong IBANs -->
<record id="view_partner_bank_form" model="ir.ui.view"> <record id="view_partner_bank_form" model="ir.ui.view">
<field name="name">account_payment_mode.res_partner_bank_form</field> <field name="name">account_payment_mode.res_partner_bank_form</field>
<field name="model">res.partner.bank</field> <field name="model">res.partner.bank</field>

View File

@@ -28,7 +28,7 @@ Installation
This module depends on: This module depends on:
* account_payment * account_payment_partner
* base_iban * base_iban
This modules is part of the OCA/bank-payment suite. 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 Configuration
============= =============
No configuration required. This module adds several options on Payment Modes, cf Accounting > Configuration > Management > Payment Modes.
Usage 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 Known issues / Roadmap
====================== ======================
@@ -58,7 +58,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. 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. 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 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 Credits

View File

@@ -32,7 +32,7 @@
'views/bank_payment_line.xml', 'views/bank_payment_line.xml',
'views/account_move_line.xml', 'views/account_move_line.xml',
'views/ir_attachment.xml', 'views/ir_attachment.xml',
#'views/res_partner_bank.xml', 'views/account_invoice_view.xml',
'data/payment_seq.xml', 'data/payment_seq.xml',
], ],
'demo': ['demo/payment_demo.xml'], 'demo': ['demo/payment_demo.xml'],

View File

@@ -3,50 +3,22 @@
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza # © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, models, _ from openerp import models, fields, api, _
from lxml import etree from openerp.exceptions import UserError
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = 'account.invoice'
payment_order_ok = fields.Boolean(
related='payment_mode_id.payment_order_ok', readonly=True)
@api.model @api.model
def _get_reference_type(self): def _get_reference_type(self):
rt = super(AccountInvoice, self)._get_reference_type() rt = super(AccountInvoice, self)._get_reference_type()
rt.append(('structured', _('Structured Reference'))) rt.append(('structured', _('Structured Reference')))
return rt 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 @api.model
def line_get_convert(self, line, part): def line_get_convert(self, line, part):
"""Copy supplier bank account from invoice to account move line""" """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'): if invoice.type in ('in_invoice', 'in_refund'):
res['partner_bank_id'] = invoice.partner_bank_id.id or False res['partner_bank_id'] = invoice.partner_bank_id.id or False
return res 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

View File

@@ -45,17 +45,22 @@ class AccountMoveLine(models.Model):
self.ensure_one() self.ensure_one()
assert payment_order, 'Missing payment order' assert payment_order, 'Missing payment order'
aplo = self.env['account.payment.line'] aplo = self.env['account.payment.line']
# default values for communication_type and communication
communication_type = 'normal' communication_type = 'normal'
communication = self.move_id.name or '-' communication = self.move_id.name or '-'
ref2comm_type = aplo.invoice_reference_type2communication_type() # change these default values if move line is linked to an invoice
if ( if self.invoice_id:
self.invoice_id and if self.invoice_id.reference_type != 'none':
self.invoice_id.type in ('in_invoice', 'in_refund') and communication = self.invoice_id.reference
self.invoice_id.reference): ref2comm_type =\
communication = self.invoice_id.reference aplo.invoice_reference_type2communication_type()
if self.invoice_id.reference_type:
communication_type =\ communication_type =\
ref2comm_type[self.invoice_id.reference_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: if self.currency_id:
currency_id = self.currency_id.id currency_id = self.currency_id.id
amount_currency = self.amount_residual_currency amount_currency = self.amount_residual_currency
@@ -66,7 +71,6 @@ class AccountMoveLine(models.Model):
precision = self.env['decimal.precision'].precision_get('Account') precision = self.env['decimal.precision'].precision_get('Account')
if payment_order.payment_type == 'outbound': if payment_order.payment_type == 'outbound':
amount_currency *= -1 amount_currency *= -1
# TODO : inherit for mandate
vals = { vals = {
'order_id': payment_order.id, 'order_id': payment_order.id,
'partner_bank_id': self.partner_bank_id.id, 'partner_bank_id': self.partner_bank_id.id,

View File

@@ -20,6 +20,9 @@ class AccountPaymentLine(models.Model):
related='order_id.company_currency_id', store=True, readonly=True) related='order_id.company_currency_id', store=True, readonly=True)
payment_type = fields.Selection( payment_type = fields.Selection(
related='order_id.payment_type', store=True, readonly=True) 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( move_line_id = fields.Many2one(
'account.move.line', string='Journal Item') 'account.move.line', string='Journal Item')
ml_maturity_date = fields.Date( ml_maturity_date = fields.Date(
@@ -83,6 +86,11 @@ class AccountPaymentLine(models.Model):
values = [] values = []
for field in bplo.same_fields_payment_line_and_bank_payment_line(): for field in bplo.same_fields_payment_line_and_bank_payment_line():
values.append(unicode(self[field])) 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) hashcode = '-'.join(values)
return hashcode return hashcode

View File

@@ -5,7 +5,8 @@
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # 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): class AccountPaymentMode(models.Model):
@@ -42,6 +43,38 @@ class AccountPaymentMode(models.Model):
"* Payment Date\n" "* Payment Date\n"
"(other modules can set additional fields to restrict the " "(other modules can set additional fields to restrict the "
"grouping.)") "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') @api.onchange('payment_method_id')
def payment_method_id_change(self): def payment_method_id_change(self):

View File

@@ -35,7 +35,9 @@ class AccountPaymentOrder(models.Model):
related='payment_mode_id.bank_account_link', readonly=True) related='payment_mode_id.bank_account_link', readonly=True)
journal_id = fields.Many2one( journal_id = fields.Many2one(
'account.journal', string='Bank Journal', '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( company_partner_bank_id = fields.Many2one(
related='journal_id.bank_account_id', string='Company Bank Account', related='journal_id.bank_account_id', string='Company Bank Account',
readonly=True) readonly=True)
@@ -174,6 +176,9 @@ class AccountPaymentOrder(models.Model):
bplo = self.env['bank.payment.line'] bplo = self.env['bank.payment.line']
today = fields.Date.context_today(self) today = fields.Date.context_today(self)
for order in 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 # Delete existing bank payment lines
order.bank_line_ids.unlink() order.bank_line_ids.unlink()
# Create the bank payment lines from the payment lines # Create the bank payment lines from the payment lines
@@ -257,5 +262,144 @@ class AccountPaymentOrder(models.Model):
@api.multi @api.multi
def generated2uploaded(self): def generated2uploaded(self):
for order in self:
if order.payment_mode_id.transfer_move:
order.generate_transfer_move()
self.write({'state': 'uploaded'}) self.write({'state': 'uploaded'})
return True 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()

View File

@@ -29,6 +29,7 @@ class BankPaymentLine(models.Model):
readonly=True) readonly=True)
# Function Float fields are sometimes badly displayed in tree view, # Function Float fields are sometimes badly displayed in tree view,
# see bug report https://github.com/odoo/odoo/issues/8632 # see bug report https://github.com/odoo/odoo/issues/8632
# But is it still true in v9 ?
amount_currency = fields.Monetary( amount_currency = fields.Monetary(
string='Amount', currency_field='currency_id', string='Amount', currency_field='currency_id',
compute='_compute_amount', store=True, readonly=True) compute='_compute_amount', store=True, readonly=True)
@@ -48,6 +49,28 @@ class BankPaymentLine(models.Model):
company_id = fields.Many2one( company_id = fields.Many2one(
related='order_id.payment_mode_id.company_id', store=True, related='order_id.payment_mode_id.company_id', store=True,
readonly=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 @api.model
def same_fields_payment_line_and_bank_payment_line(self): 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( vals['name'] = self.env['ir.sequence'].next_by_code(
'bank.payment.line') or 'New' 'bank.payment.line') or 'New'
return super(BankPaymentLine, self).create(vals) 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

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

View File

@@ -19,6 +19,16 @@
<field name="default_invoice"/> <field name="default_invoice"/>
<field name="default_date_type"/> <field name="default_date_type"/>
</group> </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> </group>
</field> </field>
</record> </record>

View File

@@ -88,6 +88,11 @@
<field name="model">account.payment.order</field> <field name="model">account.payment.order</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Payment Orders"> <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"> <group string="Group By" name="groupby">
<filter name="payment_mode_groupby" string="Payment Mode" context="{'group_by': 'payment_mode_id'}"/> <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'}"/> <filter name="journal_groupby" string="Bank Journal" context="{'group_by': 'journal_id'}"/>
@@ -98,10 +103,33 @@
</field> </field>
</record> </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"> <record id="account_payment_order_outbound_action" model="ir.actions.act_window">
<field name="name">Payment Orders</field> <field name="name">Payment Orders</field>
<field name="res_model">account.payment.order</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="domain">[('payment_type', '=', 'outbound')]</field>
<field name="context">{'default_payment_type': 'outbound'}</field> <field name="context">{'default_payment_type': 'outbound'}</field>
</record> </record>
@@ -109,7 +137,7 @@
<record id="account_payment_order_inbound_action" model="ir.actions.act_window"> <record id="account_payment_order_inbound_action" model="ir.actions.act_window">
<field name="name">Debit Orders</field> <field name="name">Debit Orders</field>
<field name="res_model">account.payment.order</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="domain">[('payment_type', '=', 'inbound')]</field>
<field name="context">{'default_payment_type': 'inbound'}</field> <field name="context">{'default_payment_type': 'inbound'}</field>
</record> </record>

View File

@@ -102,6 +102,13 @@ class AccountPaymentLineCreate(models.TransientModel):
('debit', '>', 0), ('debit', '>', 0),
('account_id.internal_type', '=', 'receivable'), ('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 return domain
@api.multi @api.multi
@@ -127,106 +134,9 @@ class AccountPaymentLineCreate(models.TransientModel):
res = {'domain': {'move_line_ids': domain}} res = {'domain': {'move_line_ids': domain}}
return res 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 @api.multi
def create_payment_lines(self): def create_payment_lines(self):
if self.move_line_ids: if self.move_line_ids:
self.move_line_ids.create_payment_line_from_move_line( self.move_line_ids.create_payment_line_from_move_line(
self.order_id) self.order_id)
return True 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'}

View File

@@ -22,7 +22,8 @@
placeholder="Keep empty for using all journals"/> placeholder="Keep empty for using all journals"/>
<field name="payment_mode"/> <field name="payment_mode"/>
<field name="invoice"/> <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>
<group name="move_lines" string="Selected Move Lines to Create Transactions"> <group name="move_lines" string="Selected Move Lines to Create Transactions">
<field name="move_line_ids" nolabel="1"> <field name="move_line_ids" nolabel="1">

View File

@@ -17,7 +17,8 @@ Installation
============ ============
This module depends on : This module depends on :
* account_banking_payment_export
* account_payment_mode
This module is part of the OCA/bank-payment suite. This module is part of the OCA/bank-payment suite.
@@ -34,10 +35,6 @@ This payment mode is automatically associated to the invoice related to the part
When you create an payment order, only invoices related to chosen payment mode are displayed. When you create an payment order, only invoices related to chosen payment mode are displayed.
Invoices without any payment mode are displayed to. Invoices without any payment mode are displayed to.
For further information, please visit:
* https://www.odoo.com/forum/help-1
Known issues / Roadmap Known issues / Roadmap
====================== ======================
@@ -49,7 +46,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-payment/issues>`_. 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. 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 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_payment_partner%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_payment_partner%0Aversion:%209.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits Credits
======= =======
@@ -58,7 +55,7 @@ Contributors
------------ ------------
* Pedro M. Baeza * Pedro M. Baeza
* Alexis de Lattre * Alexis de Lattre <alexis.delattre@akretion.com>
* Raphaël Valyi * Raphaël Valyi
* Stefan Rijnhart (Therp) * Stefan Rijnhart (Therp)
* Alexandre Fayolle * Alexandre Fayolle

View File

@@ -1,25 +1,10 @@
# -*- encoding: utf-8 -*- # -*- coding: utf-8 -*-
############################################################################## # © 2014-2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Account Payment Purchase module for OpenERP
# Copyright (C) 2014 Akretion (http://www.akretion.com).
# @author Alexis de Lattre <alexis.delattre@akretion.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
# TODO : With the new workflow for supplier invoices where the user
# creates the supplier invoice then pulls the purchase orders,
# I think we should drop this module in v9... shoulnd't we ?
{ {
'name': 'Account Payment Purchase', 'name': 'Account Payment Purchase',
'version': '8.0.1.0.0', 'version': '8.0.1.0.0',

View File

@@ -55,7 +55,7 @@ Contributors
------------ ------------
* Pedro M. Baeza * Pedro M. Baeza
* Alexis de Lattre * Alexis de Lattre <alexis.delattre@akretion.com>
* Alexandre Fayolle * Alexandre Fayolle
* Danimar Ribeiro * Danimar Ribeiro
* Raphaël Valyi * Raphaël Valyi