[IMP] account_payment_order: black, isort

This commit is contained in:
Raf Ven
2020-03-12 19:46:51 +01:00
committed by Carlos Roca
parent b360637997
commit 001bd7e976
37 changed files with 2169 additions and 1719 deletions

View File

@@ -7,37 +7,34 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Account Payment Order', "name": "Account Payment Order",
'version': '12.0.1.4.0', "version": "12.0.1.4.0",
'license': 'AGPL-3', "license": "AGPL-3",
'author': "ACSONE SA/NV, " "author": "ACSONE SA/NV, "
"Therp BV, " "Therp BV, "
"Tecnativa, " "Tecnativa, "
"Akretion, " "Akretion, "
"Odoo Community Association (OCA)", "Odoo Community Association (OCA)",
'website': 'https://github.com/OCA/bank-payment', "website": "https://github.com/OCA/bank-payment",
'category': 'Banking addons', "category": "Banking addons",
'depends': [ "depends": ["account_payment_partner", "base_iban",], # for manual_bank_tranfer
'account_payment_partner', "data": [
'base_iban', # for manual_bank_tranfer "views/account_payment_method.xml",
"security/payment_security.xml",
"security/ir.model.access.csv",
"wizard/account_payment_line_create_view.xml",
"wizard/account_invoice_payment_line_multi_view.xml",
"views/account_payment_mode.xml",
"views/account_payment_order.xml",
"views/account_payment_line.xml",
"views/bank_payment_line.xml",
"views/account_move_line.xml",
"views/ir_attachment.xml",
"views/account_invoice_view.xml",
"data/payment_seq.xml",
"report/print_account_payment_order.xml",
"report/account_payment_order.xml",
], ],
'data': [ "demo": ["demo/payment_demo.xml"],
'views/account_payment_method.xml', "installable": True,
'security/payment_security.xml',
'security/ir.model.access.csv',
'wizard/account_payment_line_create_view.xml',
'wizard/account_invoice_payment_line_multi_view.xml',
'views/account_payment_mode.xml',
'views/account_payment_order.xml',
'views/account_payment_line.xml',
'views/bank_payment_line.xml',
'views/account_move_line.xml',
'views/ir_attachment.xml',
'views/account_invoice_view.xml',
'data/payment_seq.xml',
'report/print_account_payment_order.xml',
'report/account_payment_order.xml',
],
'demo': ['demo/payment_demo.xml'],
'installable': True,
} }

View File

@@ -5,9 +5,7 @@
Copyright 2019 Tecnativa - Pedro M. Baeza Copyright 2019 Tecnativa - Pedro M. Baeza
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo noupdate="1"> <odoo noupdate="1">
<record id="bank_payment_line_seq" model="ir.sequence"> <record id="bank_payment_line_seq" model="ir.sequence">
<field name="name">Bank Payment Line</field> <field name="name">Bank Payment Line</field>
<field name="code">bank.payment.line</field> <field name="code">bank.payment.line</field>
@@ -15,7 +13,6 @@
<field name="padding">5</field> <field name="padding">5</field>
<field name="company_id" eval="False" /> <field name="company_id" eval="False" />
</record> </record>
<record id="account_payment_line_seq" model="ir.sequence"> <record id="account_payment_line_seq" model="ir.sequence">
<field name="name">Payment Line</field> <field name="name">Payment Line</field>
<field name="code">account.payment.line</field> <field name="code">account.payment.line</field>
@@ -23,7 +20,6 @@
<field name="padding">5</field> <field name="padding">5</field>
<field name="company_id" eval="False" /> <field name="company_id" eval="False" />
</record> </record>
<record id="account_payment_order_seq" model="ir.sequence"> <record id="account_payment_order_seq" model="ir.sequence">
<field name="name">Payment Order</field> <field name="name">Payment Order</field>
<field name="code">account.payment.order</field> <field name="code">account.payment.order</field>
@@ -31,5 +27,4 @@
<field name="padding">4</field> <field name="padding">4</field>
<field name="company_id" eval="False" /> <field name="company_id" eval="False" />
</record> </record>
</odoo> </odoo>

View File

@@ -1,32 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1"> <odoo noupdate="1">
<record
id="account_payment_mode.payment_mode_outbound_dd1"
<record id="account_payment_mode.payment_mode_outbound_dd1" model="account.payment.mode"> model="account.payment.mode"
>
<field name="payment_order_ok" eval="False" /> <field name="payment_order_ok" eval="False" />
</record> </record>
<record
<record id="account_payment_mode.payment_mode_outbound_dd2" model="account.payment.mode"> id="account_payment_mode.payment_mode_outbound_dd2"
model="account.payment.mode"
>
<field name="payment_order_ok" eval="False" /> <field name="payment_order_ok" eval="False" />
</record> </record>
<record
<record id="account_payment_mode.payment_mode_inbound_ct1" model="account.payment.mode"> id="account_payment_mode.payment_mode_inbound_ct1"
model="account.payment.mode"
>
<field name="payment_order_ok" eval="False" /> <field name="payment_order_ok" eval="False" />
</record> </record>
<record
<record id="account_payment_mode.payment_mode_inbound_ct2" model="account.payment.mode"> id="account_payment_mode.payment_mode_inbound_ct2"
model="account.payment.mode"
>
<field name="payment_order_ok" eval="False" /> <field name="payment_order_ok" eval="False" />
</record> </record>
<record
<record id="account_payment_mode.payment_mode_outbound_ct1" model="account.payment.mode"> id="account_payment_mode.payment_mode_outbound_ct1"
model="account.payment.mode"
>
<!-- Credit Transfer to Suppliers --> <!-- Credit Transfer to Suppliers -->
<field name="default_journal_ids" search="[('type', 'in', ('purchase', 'purchase_refund'))]"/> <field
name="default_journal_ids"
search="[('type', 'in', ('purchase', 'purchase_refund'))]"
/>
</record> </record>
<record
<record id="account_payment_mode.payment_mode_inbound_dd1" model="account.payment.mode"> id="account_payment_mode.payment_mode_inbound_dd1"
model="account.payment.mode"
>
<!-- Direct Debit of customers --> <!-- Direct Debit of customers -->
<field name="default_journal_ids" search="[('type', 'in', ('sale', 'sale_refund'))]"/> <field
name="default_journal_ids"
search="[('type', 'in', ('sale', 'sale_refund'))]"
/>
</record> </record>
</odoo> </odoo>

View File

@@ -7,9 +7,12 @@ from openupgradelib import openupgrade
@openupgrade.migrate() @openupgrade.migrate()
def migrate(env, version): def migrate(env, version):
openupgrade.set_xml_ids_noupdate_value( openupgrade.set_xml_ids_noupdate_value(
env, 'account_payment_order', [ env,
'bank_payment_line_seq', "account_payment_order",
'account_payment_line_seq', [
'account_payment_order_seq', "bank_payment_line_seq",
], True, "account_payment_line_seq",
"account_payment_order_seq",
],
True,
) )

View File

@@ -3,40 +3,37 @@
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
class AccountInvoice(models.Model): class AccountInvoice(models.Model):
_inherit = 'account.invoice' _inherit = "account.invoice"
payment_order_ok = fields.Boolean( payment_order_ok = fields.Boolean(compute="_compute_payment_order_ok",)
compute="_compute_payment_order_ok",
)
# we restore this field from <=v11 for now for preserving behavior # we restore this field from <=v11 for now for preserving behavior
# TODO: Check if we can remove it and base everything in something at # TODO: Check if we can remove it and base everything in something at
# payment mode or company level # payment mode or company level
reference_type = fields.Selection( reference_type = fields.Selection(
selection=[ selection=[("none", "Free Reference"), ("structured", "Structured Reference"),],
('none', 'Free Reference'), string="Payment Reference",
('structured', 'Structured Reference'),
],
string='Payment Reference',
required=True, required=True,
readonly=True, readonly=True,
states={'draft': [('readonly', False)]}, states={"draft": [("readonly", False)]},
default='none', default="none",
) )
@api.depends('payment_mode_id', 'move_id', 'move_id.line_ids', @api.depends(
'move_id.line_ids.payment_mode_id') "payment_mode_id",
"move_id",
"move_id.line_ids",
"move_id.line_ids.payment_mode_id",
)
def _compute_payment_order_ok(self): def _compute_payment_order_ok(self):
for invoice in self: for invoice in self:
payment_mode = ( payment_mode = invoice.move_id.line_ids.filtered(
invoice.move_id.line_ids.filtered(
lambda x: not x.reconciled lambda x: not x.reconciled
).mapped('payment_mode_id')[:1] ).mapped("payment_mode_id")[:1]
)
if not payment_mode: if not payment_mode:
payment_mode = invoice.payment_mode_id payment_mode = invoice.payment_mode_id
invoice.payment_order_ok = payment_mode.payment_order_ok invoice.payment_order_ok = payment_mode.payment_order_ok
@@ -45,19 +42,19 @@ class AccountInvoice(models.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"""
res = super(AccountInvoice, self).line_get_convert(line, part) res = super(AccountInvoice, self).line_get_convert(line, part)
if line.get('type') == 'dest' and line.get('invoice_id'): if line.get("type") == "dest" and line.get("invoice_id"):
invoice = self.browse(line['invoice_id']) invoice = self.browse(line["invoice_id"])
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 @api.multi
def _prepare_new_payment_order(self, payment_mode=None): def _prepare_new_payment_order(self, payment_mode=None):
self.ensure_one() self.ensure_one()
if payment_mode is None: if payment_mode is None:
payment_mode = self.env['account.payment.mode'] payment_mode = self.env["account.payment.mode"]
vals = { vals = {
'payment_mode_id': payment_mode.id or self.payment_mode_id.id, "payment_mode_id": payment_mode.id or self.payment_mode_id.id,
} }
# other important fields are set by the inherit of create # other important fields are set by the inherit of create
# in account_payment_order.py # in account_payment_order.py
@@ -65,43 +62,48 @@ class AccountInvoice(models.Model):
@api.multi @api.multi
def create_account_payment_line(self): def create_account_payment_line(self):
apoo = self.env['account.payment.order'] apoo = self.env["account.payment.order"]
result_payorder_ids = [] result_payorder_ids = []
action_payment_type = 'debit' action_payment_type = "debit"
for inv in self: for inv in self:
if inv.state != 'open': if inv.state != "open":
raise UserError(_( raise UserError(_("The invoice %s is not in Open state") % inv.number)
"The invoice %s is not in Open state") % inv.number)
if not inv.move_id: if not inv.move_id:
raise UserError(_( raise UserError(_("No Journal Entry on invoice %s") % inv.number)
"No Journal Entry on invoice %s") % inv.number)
applicable_lines = inv.move_id.line_ids.filtered( applicable_lines = inv.move_id.line_ids.filtered(
lambda x: ( lambda x: (
not x.reconciled and x.payment_mode_id.payment_order_ok and not x.reconciled
x.account_id.internal_type in ('receivable', 'payable') and and x.payment_mode_id.payment_order_ok
not any(p_state in ('draft', 'open', 'generated') and x.account_id.internal_type in ("receivable", "payable")
for p_state in x.payment_line_ids.mapped('state')) and not any(
p_state in ("draft", "open", "generated")
for p_state in x.payment_line_ids.mapped("state")
)
) )
) )
if not applicable_lines: if not applicable_lines:
raise UserError(_( raise UserError(
'No Payment Line created for invoice %s because ' _(
'it already exists or because this invoice is ' "No Payment Line created for invoice %s because "
'already paid.') % inv.number) "it already exists or because this invoice is "
payment_modes = applicable_lines.mapped('payment_mode_id') "already paid."
)
% inv.number
)
payment_modes = applicable_lines.mapped("payment_mode_id")
if not payment_modes: if not payment_modes:
raise UserError(_( raise UserError(_("No Payment Mode on invoice %s") % inv.number)
"No Payment Mode on invoice %s") % inv.number)
for payment_mode in payment_modes: for payment_mode in payment_modes:
payorder = apoo.search([ payorder = apoo.search(
('payment_mode_id', '=', payment_mode.id), [
('state', '=', 'draft') ("payment_mode_id", "=", payment_mode.id),
], limit=1) ("state", "=", "draft"),
],
limit=1,
)
new_payorder = False new_payorder = False
if not payorder: if not payorder:
payorder = apoo.create(inv._prepare_new_payment_order( payorder = apoo.create(inv._prepare_new_payment_order(payment_mode))
payment_mode
))
new_payorder = True new_payorder = True
result_payorder_ids.append(payorder.id) result_payorder_ids.append(payorder.id)
action_payment_type = payorder.payment_type action_payment_type = payorder.payment_type
@@ -112,28 +114,39 @@ class AccountInvoice(models.Model):
line.create_payment_line_from_move_line(payorder) line.create_payment_line_from_move_line(payorder)
count += 1 count += 1
if new_payorder: if new_payorder:
inv.message_post(body=_( inv.message_post(
'%d payment lines added to the new draft payment ' body=_(
'order %s which has been automatically created.') "%d payment lines added to the new draft payment "
% (count, payorder.name)) "order %s which has been automatically created."
)
% (count, payorder.name)
)
else: else:
inv.message_post(body=_( inv.message_post(
'%d payment lines added to the existing draft ' body=_(
'payment order %s.') "%d payment lines added to the existing draft "
% (count, payorder.name)) "payment order %s."
action = self.env['ir.actions.act_window'].for_xml_id( )
'account_payment_order', % (count, payorder.name)
'account_payment_order_%s_action' % action_payment_type) )
action = self.env["ir.actions.act_window"].for_xml_id(
"account_payment_order",
"account_payment_order_%s_action" % action_payment_type,
)
if len(result_payorder_ids) == 1: if len(result_payorder_ids) == 1:
action.update({ action.update(
'view_mode': 'form,tree,pivot,graph', {
'res_id': payorder.id, "view_mode": "form,tree,pivot,graph",
'views': False, "res_id": payorder.id,
}) "views": False,
}
)
else: else:
action.update({ action.update(
'view_mode': 'tree,form,pivot,graph', {
'domain': "[('id', 'in', %s)]" % result_payorder_ids, "view_mode": "tree,form,pivot,graph",
'views': False, "domain": "[('id', 'in', %s)]" % result_payorder_ids,
}) "views": False,
}
)
return action return action

View File

@@ -5,29 +5,27 @@ from odoo import api, fields, models
class AccountJournal(models.Model): class AccountJournal(models.Model):
_inherit = 'account.journal' _inherit = "account.journal"
inbound_payment_order_only = fields.Boolean( inbound_payment_order_only = fields.Boolean(
compute='_compute_inbound_payment_order_only', compute="_compute_inbound_payment_order_only", readonly=True, store=True,
readonly=True,
store=True,
) )
outbound_payment_order_only = fields.Boolean( outbound_payment_order_only = fields.Boolean(
compute='_compute_outbound_payment_order_only', compute="_compute_outbound_payment_order_only", readonly=True, store=True,
readonly=True,
store=True,
) )
@api.multi @api.multi
@api.depends('inbound_payment_method_ids.payment_order_only') @api.depends("inbound_payment_method_ids.payment_order_only")
def _compute_inbound_payment_order_only(self): def _compute_inbound_payment_order_only(self):
for rec in self: for rec in self:
rec.inbound_payment_order_only = all( rec.inbound_payment_order_only = all(
p.payment_order_only for p in rec.inbound_payment_method_ids) p.payment_order_only for p in rec.inbound_payment_method_ids
)
@api.multi @api.multi
@api.depends('outbound_payment_method_ids.payment_order_only') @api.depends("outbound_payment_method_ids.payment_order_only")
def _compute_outbound_payment_order_only(self): def _compute_outbound_payment_order_only(self):
for rec in self: for rec in self:
rec.outbound_payment_order_only = all( rec.outbound_payment_order_only = all(
p.payment_order_only for p in rec.outbound_payment_method_ids) p.payment_order_only for p in rec.outbound_payment_method_ids
)

View File

@@ -1,12 +1,12 @@
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields from odoo import fields, models
class AccountMove(models.Model): class AccountMove(models.Model):
_inherit = 'account.move' _inherit = "account.move"
payment_order_id = fields.Many2one( payment_order_id = fields.Many2one(
'account.payment.order', string='Payment Order', copy=False, "account.payment.order", string="Payment Order", copy=False, readonly=True
readonly=True) )

View File

@@ -3,50 +3,50 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from lxml import etree from lxml import etree
from odoo import api, fields, models from odoo import api, fields, models
from odoo.fields import first from odoo.fields import first
from odoo.osv import orm from odoo.osv import orm
class AccountMoveLine(models.Model): class AccountMoveLine(models.Model):
_inherit = 'account.move.line' _inherit = "account.move.line"
partner_bank_id = fields.Many2one( partner_bank_id = fields.Many2one(
'res.partner.bank', string='Partner Bank Account', "res.partner.bank",
help='Bank account on which we should pay the supplier') string="Partner Bank Account",
help="Bank account on which we should pay the supplier",
)
bank_payment_line_id = fields.Many2one( bank_payment_line_id = fields.Many2one(
'bank.payment.line', string='Bank Payment Line', "bank.payment.line", string="Bank Payment Line", readonly=True, index=True,
readonly=True,
index=True,
) )
payment_line_ids = fields.One2many( payment_line_ids = fields.One2many(
comodel_name='account.payment.line', comodel_name="account.payment.line",
inverse_name='move_line_id', inverse_name="move_line_id",
string="Payment lines", string="Payment lines",
) )
@api.multi @api.multi
def _prepare_payment_line_vals(self, payment_order): def _prepare_payment_line_vals(self, payment_order):
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 # default values for communication_type and communication
communication_type = 'normal' communication_type = "normal"
communication = self.move_id.ref or self.move_id.name communication = self.move_id.ref or self.move_id.name
# change these default values if move line is linked to an invoice # change these default values if move line is linked to an invoice
if self.invoice_id: if self.invoice_id:
if self.invoice_id.reference_type != 'none': if self.invoice_id.reference_type != "none":
communication = self.invoice_id.reference communication = self.invoice_id.reference
ref2comm_type =\ ref2comm_type = aplo.invoice_reference_type2communication_type()
aplo.invoice_reference_type2communication_type() communication_type = ref2comm_type[self.invoice_id.reference_type]
communication_type =\
ref2comm_type[self.invoice_id.reference_type]
else: else:
if ( if (
self.invoice_id.type in ('in_invoice', 'in_refund') and self.invoice_id.type in ("in_invoice", "in_refund")
self.invoice_id.reference): and self.invoice_id.reference
):
communication = self.invoice_id.reference communication = self.invoice_id.reference
elif 'out' in self.invoice_id.type: elif "out" in self.invoice_id.type:
# Force to only put invoice number here # Force to only put invoice number here
communication = self.invoice_id.number communication = self.invoice_id.number
if self.currency_id: if self.currency_id:
@@ -57,19 +57,18 @@ class AccountMoveLine(models.Model):
amount_currency = self.amount_residual amount_currency = self.amount_residual
# TODO : check that self.amount_residual_currency is 0 # TODO : check that self.amount_residual_currency is 0
# in this case # in this case
if payment_order.payment_type == 'outbound': if payment_order.payment_type == "outbound":
amount_currency *= -1 amount_currency *= -1
partner_bank_id = self.partner_bank_id.id or first( partner_bank_id = self.partner_bank_id.id or first(self.partner_id.bank_ids).id
self.partner_id.bank_ids).id
vals = { vals = {
'order_id': payment_order.id, "order_id": payment_order.id,
'partner_bank_id': partner_bank_id, "partner_bank_id": partner_bank_id,
'partner_id': self.partner_id.id, "partner_id": self.partner_id.id,
'move_line_id': self.id, "move_line_id": self.id,
'communication': communication, "communication": communication,
'communication_type': communication_type, "communication_type": communication_type,
'currency_id': currency_id, "currency_id": currency_id,
'amount_currency': amount_currency, "amount_currency": amount_currency,
# date is set when the user confirms the payment order # date is set when the user confirms the payment order
} }
return vals return vals
@@ -79,52 +78,44 @@ class AccountMoveLine(models.Model):
vals_list = [] vals_list = []
for mline in self: for mline in self:
vals_list.append(mline._prepare_payment_line_vals(payment_order)) vals_list.append(mline._prepare_payment_line_vals(payment_order))
return self.env['account.payment.line'].create(vals_list) return self.env["account.payment.line"].create(vals_list)
@api.model @api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, def fields_view_get(
submenu=False): self, view_id=None, view_type="form", toolbar=False, submenu=False
):
# When the user looks for open payables or receivables, in the # When the user looks for open payables or receivables, in the
# context of payment orders, she should focus primarily on amount that # context of payment orders, she should focus primarily on amount that
# is due to be paid, and secondarily on the total amount. In this # is due to be paid, and secondarily on the total amount. In this
# method we are forcing to display both the amount due in company and # method we are forcing to display both the amount due in company and
# in the invoice currency. # in the invoice currency.
# We then hide the fields debit and credit, because they add no value. # We then hide the fields debit and credit, because they add no value.
result = super(AccountMoveLine, self).fields_view_get(view_id, result = super(AccountMoveLine, self).fields_view_get(
view_type, view_id, view_type, toolbar=toolbar, submenu=submenu
toolbar=toolbar, )
submenu=submenu)
doc = etree.XML(result['arch']) doc = etree.XML(result["arch"])
if view_type == 'tree' and self._module == 'account_payment_order': if view_type == "tree" and self._module == "account_payment_order":
if not doc.xpath("//field[@name='balance']"): if not doc.xpath("//field[@name='balance']"):
for placeholder in doc.xpath( for placeholder in doc.xpath("//field[@name='amount_currency']"):
"//field[@name='amount_currency']"):
elem = etree.Element( elem = etree.Element(
'field', { "field", {"name": "balance", "readonly": "True"}
'name': 'balance', )
'readonly': 'True'
})
orm.setup_modifiers(elem) orm.setup_modifiers(elem)
placeholder.addprevious(elem) placeholder.addprevious(elem)
if not doc.xpath("//field[@name='amount_residual_currency']"): if not doc.xpath("//field[@name='amount_residual_currency']"):
for placeholder in doc.xpath( for placeholder in doc.xpath("//field[@name='amount_currency']"):
"//field[@name='amount_currency']"):
elem = etree.Element( elem = etree.Element(
'field', { "field",
'name': 'amount_residual_currency', {"name": "amount_residual_currency", "readonly": "True"},
'readonly': 'True' )
})
orm.setup_modifiers(elem) orm.setup_modifiers(elem)
placeholder.addnext(elem) placeholder.addnext(elem)
if not doc.xpath("//field[@name='amount_residual']"): if not doc.xpath("//field[@name='amount_residual']"):
for placeholder in doc.xpath( for placeholder in doc.xpath("//field[@name='amount_currency']"):
"//field[@name='amount_currency']"):
elem = etree.Element( elem = etree.Element(
'field', { "field", {"name": "amount_residual", "readonly": "True"}
'name': 'amount_residual', )
'readonly': 'True'
})
orm.setup_modifiers(elem) orm.setup_modifiers(elem)
placeholder.addnext(elem) placeholder.addnext(elem)
# Remove credit and debit data - which is irrelevant in this case # Remove credit and debit data - which is irrelevant in this case
@@ -132,5 +123,5 @@ class AccountMoveLine(models.Model):
doc.remove(elem) doc.remove(elem)
for elem in doc.xpath("//field[@name='credit']"): for elem in doc.xpath("//field[@name='credit']"):
doc.remove(elem) doc.remove(elem)
result['arch'] = etree.tostring(doc) result["arch"] = etree.tostring(doc)
return result return result

View File

@@ -5,26 +5,25 @@ from odoo import api, models
class AccountPayment(models.Model): class AccountPayment(models.Model):
_inherit = 'account.payment' _inherit = "account.payment"
def _compute_journal_domain_and_types(self): def _compute_journal_domain_and_types(self):
res = super(AccountPayment, self)._compute_journal_domain_and_types() res = super(AccountPayment, self)._compute_journal_domain_and_types()
journal_domain = res.get('domain', []) journal_domain = res.get("domain", [])
if self.payment_type == 'inbound': if self.payment_type == "inbound":
journal_domain.append(('inbound_payment_order_only', '=', False)) journal_domain.append(("inbound_payment_order_only", "=", False))
else: else:
journal_domain.append(('outbound_payment_order_only', '=', False)) journal_domain.append(("outbound_payment_order_only", "=", False))
res['domain'] = journal_domain res["domain"] = journal_domain
return res return res
@api.multi @api.multi
@api.onchange('journal_id') @api.onchange("journal_id")
def _onchange_journal(self): def _onchange_journal(self):
res = super(AccountPayment, self)._onchange_journal() res = super(AccountPayment, self)._onchange_journal()
domains = res.get('domain') domains = res.get("domain")
if not domains: if not domains:
return res return res
if domains.get('payment_method_id'): if domains.get("payment_method_id"):
domains['payment_method_id'].append( domains["payment_method_id"].append(("payment_order_only", "!=", True))
('payment_order_only', '!=', True))
return res return res

View File

@@ -1,94 +1,112 @@
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com> # © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
class AccountPaymentLine(models.Model): class AccountPaymentLine(models.Model):
_name = 'account.payment.line' _name = "account.payment.line"
_description = 'Payment Lines' _description = "Payment Lines"
name = fields.Char(string='Payment Reference', readonly=True, copy=False) name = fields.Char(string="Payment Reference", readonly=True, copy=False)
order_id = fields.Many2one( order_id = fields.Many2one(
'account.payment.order', string='Payment Order', "account.payment.order", string="Payment Order", ondelete="cascade", index=True
ondelete='cascade', index=True) )
company_id = fields.Many2one( company_id = fields.Many2one(
related='order_id.company_id', store=True, readonly=True) related="order_id.company_id", store=True, readonly=True
)
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
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
)
bank_account_required = fields.Boolean( bank_account_required = fields.Boolean(
related='order_id.payment_method_id.bank_account_required', related="order_id.payment_method_id.bank_account_required", readonly=True
readonly=True) )
state = fields.Selection( state = fields.Selection(
related='order_id.state', string='State', related="order_id.state", string="State", readonly=True, store=True
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", ondelete="restrict"
ondelete='restrict') )
ml_maturity_date = fields.Date( ml_maturity_date = fields.Date(related="move_line_id.date_maturity", readonly=True)
related='move_line_id.date_maturity', readonly=True)
currency_id = fields.Many2one( currency_id = fields.Many2one(
'res.currency', string='Currency of the Payment Transaction', "res.currency",
string="Currency of the Payment Transaction",
required=True, required=True,
default=lambda self: self.env.user.company_id.currency_id) default=lambda self: self.env.user.company_id.currency_id,
)
# v8 field : currency # v8 field : currency
amount_currency = fields.Monetary( amount_currency = fields.Monetary(string="Amount", currency_field="currency_id")
string="Amount", currency_field='currency_id')
amount_company_currency = fields.Monetary( amount_company_currency = fields.Monetary(
compute='_compute_amount_company_currency', compute="_compute_amount_company_currency",
string='Amount in Company Currency', readonly=True, string="Amount in Company Currency",
currency_field='company_currency_id') # v8 field : amount readonly=True,
currency_field="company_currency_id",
) # v8 field : amount
partner_id = fields.Many2one( partner_id = fields.Many2one(
'res.partner', string='Partner', required=True, "res.partner",
domain=[('parent_id', '=', False)]) string="Partner",
required=True,
domain=[("parent_id", "=", False)],
)
partner_bank_id = fields.Many2one( partner_bank_id = fields.Many2one(
'res.partner.bank', string='Partner Bank Account', required=False, "res.partner.bank",
ondelete='restrict') # v8 field : bank_id string="Partner Bank Account",
date = fields.Date(string='Payment Date') required=False,
ondelete="restrict",
) # v8 field : bank_id
date = fields.Date(string="Payment Date")
communication = fields.Char( communication = fields.Char(
string='Communication', required=True, string="Communication",
help="Label of the payment that will be seen by the destinee") required=True,
communication_type = fields.Selection([ help="Label of the payment that will be seen by the destinee",
('normal', 'Free'), )
], string='Communication Type', required=True, default='normal') communication_type = fields.Selection(
[("normal", "Free"),],
string="Communication Type",
required=True,
default="normal",
)
# v8 field : state # v8 field : state
bank_line_id = fields.Many2one( bank_line_id = fields.Many2one(
'bank.payment.line', string='Bank Payment Line', readonly=True, "bank.payment.line", string="Bank Payment Line", readonly=True, index=True,
index=True,
) )
_sql_constraints = [( _sql_constraints = [
'name_company_unique', (
'unique(name, company_id)', "name_company_unique",
'A payment line already exists with this reference ' "unique(name, company_id)",
'in the same company!' "A payment line already exists with this reference " "in the same company!",
)] )
]
@api.model @api.model
def create(self, vals): def create(self, vals):
if vals.get('name', 'New') == 'New': if vals.get("name", "New") == "New":
vals['name'] = self.env['ir.sequence'].next_by_code( vals["name"] = (
'account.payment.line') or 'New' self.env["ir.sequence"].next_by_code("account.payment.line") or "New"
)
return super(AccountPaymentLine, self).create(vals) return super(AccountPaymentLine, self).create(vals)
@api.multi @api.multi
@api.depends( @api.depends("amount_currency", "currency_id", "company_currency_id", "date")
'amount_currency', 'currency_id', 'company_currency_id', 'date')
def _compute_amount_company_currency(self): def _compute_amount_company_currency(self):
for line in self: for line in self:
if line.currency_id and line.company_currency_id: if line.currency_id and line.company_currency_id:
line.amount_company_currency = line.currency_id._convert( line.amount_company_currency = line.currency_id._convert(
line.amount_currency, line.company_currency_id, line.amount_currency,
line.company_id, line.date or fields.Date.today(), line.company_currency_id,
line.company_id,
line.date or fields.Date.today(),
) )
@api.multi @api.multi
def payment_line_hashcode(self): def payment_line_hashcode(self):
self.ensure_one() self.ensure_one()
bplo = self.env['bank.payment.line'] bplo = self.env["bank.payment.line"]
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(str(self[field])) values.append(str(self[field]))
@@ -98,23 +116,23 @@ class AccountPaymentLine(models.Model):
values.append(str(self.move_line_id.account_id or False)) values.append(str(self.move_line_id.account_id or False))
# Don't group the payment lines that use a structured communication # Don't group the payment lines that use a structured communication
# otherwise it would break the structured communication system ! # otherwise it would break the structured communication system !
if self.communication_type != 'normal': if self.communication_type != "normal":
values.append(str(self.id)) values.append(str(self.id))
hashcode = '-'.join(values) hashcode = "-".join(values)
return hashcode return hashcode
@api.onchange('partner_id') @api.onchange("partner_id")
def partner_id_change(self): def partner_id_change(self):
partner_bank = False partner_bank = False
if self.partner_id.bank_ids: if self.partner_id.bank_ids:
partner_bank = self.partner_id.bank_ids[0] partner_bank = self.partner_id.bank_ids[0]
self.partner_bank_id = partner_bank self.partner_bank_id = partner_bank
@api.onchange('move_line_id') @api.onchange("move_line_id")
def move_line_id_change(self): def move_line_id_change(self):
if self.move_line_id: if self.move_line_id:
vals = self.move_line_id._prepare_payment_line_vals(self.order_id) vals = self.move_line_id._prepare_payment_line_vals(self.order_id)
vals.pop('order_id') vals.pop("order_id")
for field, value in vals.items(): for field, value in vals.items():
self[field] = value self[field] = value
else: else:
@@ -129,12 +147,13 @@ class AccountPaymentLine(models.Model):
localization modules""" localization modules"""
# key = value of 'reference_type' field on account_invoice # key = value of 'reference_type' field on account_invoice
# value = value of 'communication_type' field on account_payment_line # value = value of 'communication_type' field on account_payment_line
res = {'none': 'normal', 'structured': 'structured'} res = {"none": "normal", "structured": "structured"}
return res return res
@api.multi @api.multi
def draft2open_payment_line_check(self): def draft2open_payment_line_check(self):
self.ensure_one() self.ensure_one()
if self.bank_account_required and not self.partner_bank_id: if self.bank_account_required and not self.partner_bank_id:
raise UserError(_( raise UserError(
'Missing Partner Bank Account on payment line %s') % self.name) _("Missing Partner Bank Account on payment line %s") % self.name
)

View File

@@ -5,7 +5,7 @@ from odoo import fields, models
class AccountPaymentMethod(models.Model): class AccountPaymentMethod(models.Model):
_inherit = 'account.payment.method' _inherit = "account.payment.method"
payment_order_only = fields.Boolean( payment_order_only = fields.Boolean(
string="Only for payment orders", string="Only for payment orders",

View File

@@ -4,52 +4,56 @@
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) # © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
class AccountPaymentMode(models.Model): class AccountPaymentMode(models.Model):
"""This corresponds to the object payment.mode of v8 with some """This corresponds to the object payment.mode of v8 with some
important changes""" important changes"""
_inherit = "account.payment.mode" _inherit = "account.payment.mode"
payment_order_ok = fields.Boolean( payment_order_ok = fields.Boolean(
string='Selectable in Payment Orders', default=True) string="Selectable in Payment Orders", default=True
)
no_debit_before_maturity = fields.Boolean( no_debit_before_maturity = fields.Boolean(
string="Disallow Debit Before Maturity Date", string="Disallow Debit Before Maturity Date",
help="If you activate this option on an Inbound payment mode, " help="If you activate this option on an Inbound payment mode, "
"you will have an error message when you confirm a debit order " "you will have an error message when you confirm a debit order "
"that has a payment line with a payment date before the maturity " "that has a payment line with a payment date before the maturity "
"date.") "date.",
)
# Default options for the "payment.order.create" wizard # Default options for the "payment.order.create" wizard
default_payment_mode = fields.Selection([ default_payment_mode = fields.Selection(
('same', 'Same'), [("same", "Same"), ("same_or_null", "Same or empty"), ("any", "Any"),],
('same_or_null', 'Same or empty'), string="Payment Mode on Invoice",
('any', 'Any'), default="same",
], string='Payment Mode on Invoice', default='same') )
default_journal_ids = fields.Many2many( default_journal_ids = fields.Many2many(
'account.journal', "account.journal",
string="Journals Filter", string="Journals Filter",
domain="[('company_id', '=', company_id)]" domain="[('company_id', '=', company_id)]",
) )
default_invoice = fields.Boolean( default_invoice = fields.Boolean(
string='Linked to an Invoice or Refund', default=False) string="Linked to an Invoice or Refund", default=False
default_target_move = fields.Selection([ )
('posted', 'All Posted Entries'), default_target_move = fields.Selection(
('all', 'All Entries'), [("posted", "All Posted Entries"), ("all", "All Entries"),],
], string='Target Moves', default='posted') string="Target Moves",
default_date_type = fields.Selection([ default="posted",
('due', 'Due'), )
('move', 'Move'), default_date_type = fields.Selection(
], default='due', string="Type of Date Filter") [("due", "Due"), ("move", "Move"),], default="due", string="Type of Date Filter"
)
# default option for account.payment.order # default option for account.payment.order
default_date_prefered = fields.Selection([ default_date_prefered = fields.Selection(
('now', 'Immediately'), [("now", "Immediately"), ("due", "Due Date"), ("fixed", "Fixed Date"),],
('due', 'Due Date'), string="Default Payment Execution Date",
('fixed', 'Fixed Date'), )
], string='Default Payment Execution Date')
group_lines = fields.Boolean( group_lines = fields.Boolean(
string="Group Transactions in Payment Orders", default=True, string="Group Transactions in Payment Orders",
default=True,
help="If this mark is checked, the transaction lines of the " help="If this mark is checked, the transaction lines of the "
"payment order will be grouped upon confirmation of the payment " "payment order will be grouped upon confirmation of the payment "
"order.The grouping will be done only if the following " "order.The grouping will be done only if the following "
@@ -60,89 +64,118 @@ class AccountPaymentMode(models.Model):
"* Payment Date\n" "* Payment Date\n"
"and if the 'Communication Type' is 'Free'\n" "and if the 'Communication Type' is 'Free'\n"
"(other modules can set additional fields to restrict the " "(other modules can set additional fields to restrict the "
"grouping.)") "grouping.)",
)
generate_move = fields.Boolean( generate_move = fields.Boolean(
string='Generate Accounting Entries On File Upload', default=True) string="Generate Accounting Entries On File Upload", default=True
offsetting_account = fields.Selection([ )
('bank_account', 'Bank Account'), offsetting_account = fields.Selection(
('transfer_account', 'Transfer Account'), [("bank_account", "Bank Account"), ("transfer_account", "Transfer Account"),],
], string='Offsetting Account', default='bank_account') string="Offsetting Account",
default="bank_account",
)
transfer_account_id = fields.Many2one( transfer_account_id = fields.Many2one(
'account.account', string='Transfer Account', "account.account",
domain=[('reconcile', '=', True)], string="Transfer Account",
domain=[("reconcile", "=", True)],
help="Pay off lines in 'file uploaded' payment orders with a move on " help="Pay off lines in 'file uploaded' payment orders with a move on "
"this account. You can only select accounts " "this account. You can only select accounts "
"that are marked for reconciliation") "that are marked for reconciliation",
)
transfer_journal_id = fields.Many2one( transfer_journal_id = fields.Many2one(
'account.journal', string='Transfer Journal', "account.journal",
help='Journal to write payment entries when confirming ' string="Transfer Journal",
'payment/debit orders of this mode') help="Journal to write payment entries when confirming "
move_option = fields.Selection([ "payment/debit orders of this mode",
('date', 'One move per payment date'), )
('line', 'One move per payment line'), move_option = fields.Selection(
], string='Move Option', default='date') [("date", "One move per payment date"), ("line", "One move per payment line"),],
post_move = fields.Boolean(string='Post Move', default=True) string="Move Option",
default="date",
)
post_move = fields.Boolean(string="Post Move", default=True)
@api.multi @api.multi
@api.constrains( @api.constrains(
'generate_move', 'offsetting_account', "generate_move",
'transfer_account_id', 'transfer_journal_id', 'move_option') "offsetting_account",
"transfer_account_id",
"transfer_journal_id",
"move_option",
)
def transfer_move_constrains(self): def transfer_move_constrains(self):
for mode in self: for mode in self:
if mode.generate_move: if mode.generate_move:
if not mode.offsetting_account: if not mode.offsetting_account:
raise ValidationError(_( raise ValidationError(
_(
"On the payment mode '%s', you must select an " "On the payment mode '%s', you must select an "
"option for the 'Offsetting Account' parameter") "option for the 'Offsetting Account' parameter"
% mode.name) )
elif mode.offsetting_account == 'transfer_account': % mode.name
)
elif mode.offsetting_account == "transfer_account":
if not mode.transfer_account_id: if not mode.transfer_account_id:
raise ValidationError(_( raise ValidationError(
_(
"On the payment mode '%s', you must " "On the payment mode '%s', you must "
"select a value for the 'Transfer Account'.") "select a value for the 'Transfer Account'."
% mode.name) )
% mode.name
)
if not mode.transfer_journal_id: if not mode.transfer_journal_id:
raise ValidationError(_( raise ValidationError(
_(
"On the payment mode '%s', you must " "On the payment mode '%s', you must "
"select a value for the 'Transfer Journal'.") "select a value for the 'Transfer Journal'."
% mode.name) )
% mode.name
)
if not mode.move_option: if not mode.move_option:
raise ValidationError(_( raise ValidationError(
_(
"On the payment mode '%s', you must " "On the payment mode '%s', you must "
"choose an option for the 'Move Option' " "choose an option for the 'Move Option' "
"parameter.") % mode.name) "parameter."
)
% mode.name
)
@api.onchange('payment_method_id') @api.onchange("payment_method_id")
def payment_method_id_change(self): def payment_method_id_change(self):
if self.payment_method_id: if self.payment_method_id:
ajo = self.env['account.journal'] ajo = self.env["account.journal"]
aj_ids = [] aj_ids = []
if self.payment_method_id.payment_type == 'outbound': if self.payment_method_id.payment_type == "outbound":
aj_ids = ajo.search([ aj_ids = ajo.search(
('type', 'in', ('purchase_refund', 'purchase')), [
('company_id', '=', self.company_id.id) ("type", "in", ("purchase_refund", "purchase")),
]).ids ("company_id", "=", self.company_id.id),
elif self.payment_method_id.payment_type == 'inbound': ]
aj_ids = ajo.search([ ).ids
('type', 'in', ('sale_refund', 'sale')), elif self.payment_method_id.payment_type == "inbound":
('company_id', '=', self.company_id.id) aj_ids = ajo.search(
]).ids [
("type", "in", ("sale_refund", "sale")),
("company_id", "=", self.company_id.id),
]
).ids
self.default_journal_ids = [(6, 0, aj_ids)] self.default_journal_ids = [(6, 0, aj_ids)]
@api.onchange('generate_move') @api.onchange("generate_move")
def generate_move_change(self): def generate_move_change(self):
if self.generate_move: if self.generate_move:
# default values # default values
self.offsetting_account = 'bank_account' self.offsetting_account = "bank_account"
self.move_option = 'date' self.move_option = "date"
else: else:
self.offsetting_account = False self.offsetting_account = False
self.transfer_account_id = False self.transfer_account_id = False
self.transfer_journal_id = False self.transfer_journal_id = False
self.move_option = False self.move_option = False
@api.onchange('offsetting_account') @api.onchange("offsetting_account")
def offsetting_account_change(self): def offsetting_account_change(self):
if self.offsetting_account == 'bank_account': if self.offsetting_account == "bank_account":
self.transfer_account_id = False self.transfer_account_id = False
self.transfer_journal_id = False self.transfer_journal_id = False

View File

@@ -5,179 +5,227 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import base64 import base64
from odoo import models, fields, api, _
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
class AccountPaymentOrder(models.Model): class AccountPaymentOrder(models.Model):
_name = 'account.payment.order' _name = "account.payment.order"
_description = 'Payment Order' _description = "Payment Order"
_inherit = ['mail.thread'] _inherit = ["mail.thread"]
_order = 'id desc' _order = "id desc"
name = fields.Char( name = fields.Char(string="Number", readonly=True, copy=False) # v8 field : name
string='Number', readonly=True, copy=False) # v8 field : name
payment_mode_id = fields.Many2one( payment_mode_id = fields.Many2one(
'account.payment.mode', 'Payment Mode', required=True, "account.payment.mode",
ondelete='restrict', track_visibility='onchange', "Payment Mode",
readonly=True, states={'draft': [('readonly', False)]}) required=True,
payment_type = fields.Selection([ ondelete="restrict",
('inbound', 'Inbound'), track_visibility="onchange",
('outbound', 'Outbound'), readonly=True,
], string='Payment Type', readonly=True, required=True) states={"draft": [("readonly", False)]},
)
payment_type = fields.Selection(
[("inbound", "Inbound"), ("outbound", "Outbound"),],
string="Payment Type",
readonly=True,
required=True,
)
payment_method_id = fields.Many2one( payment_method_id = fields.Many2one(
'account.payment.method', related='payment_mode_id.payment_method_id', "account.payment.method",
readonly=True, store=True) related="payment_mode_id.payment_method_id",
readonly=True,
store=True,
)
company_id = fields.Many2one( company_id = fields.Many2one(
related='payment_mode_id.company_id', store=True, readonly=True) related="payment_mode_id.company_id", store=True, readonly=True
)
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
related='payment_mode_id.company_id.currency_id', store=True, related="payment_mode_id.company_id.currency_id", store=True, readonly=True
readonly=True) )
bank_account_link = fields.Selection( bank_account_link = fields.Selection(
related='payment_mode_id.bank_account_link', readonly=True) related="payment_mode_id.bank_account_link", readonly=True
)
allowed_journal_ids = fields.Many2many( allowed_journal_ids = fields.Many2many(
comodel_name='account.journal', comodel_name="account.journal",
compute="_compute_allowed_journal_ids", compute="_compute_allowed_journal_ids",
string="Allowed journals", string="Allowed journals",
) )
journal_id = fields.Many2one( journal_id = fields.Many2one(
'account.journal', string='Bank Journal', ondelete='restrict', "account.journal",
readonly=True, states={'draft': [('readonly', False)]}, string="Bank Journal",
track_visibility='onchange') ondelete="restrict",
readonly=True,
states={"draft": [("readonly", False)]},
track_visibility="onchange",
)
# The journal_id field is only required at confirm step, to # The journal_id field is only required at confirm step, to
# allow auto-creation of payment order from invoice # 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",
readonly=True) string="Company Bank Account",
readonly=True,
)
state = fields.Selection( state = fields.Selection(
[ [
('draft', 'Draft'), ("draft", "Draft"),
('open', 'Confirmed'), ("open", "Confirmed"),
('generated', 'File Generated'), ("generated", "File Generated"),
('uploaded', 'File Uploaded'), ("uploaded", "File Uploaded"),
('done', 'Done'), ("done", "Done"),
('cancel', 'Cancel'), ("cancel", "Cancel"),
], string='Status', readonly=True, copy=False, default='draft', ],
track_visibility='onchange') string="Status",
date_prefered = fields.Selection([ readonly=True,
('now', 'Immediately'), copy=False,
('due', 'Due Date'), default="draft",
('fixed', 'Fixed Date'), track_visibility="onchange",
], string='Payment Execution Date Type', required=True, default='due', )
track_visibility='onchange', readonly=True, date_prefered = fields.Selection(
states={'draft': [('readonly', False)]}) [("now", "Immediately"), ("due", "Due Date"), ("fixed", "Fixed Date"),],
string="Payment Execution Date Type",
required=True,
default="due",
track_visibility="onchange",
readonly=True,
states={"draft": [("readonly", False)]},
)
date_scheduled = fields.Date( date_scheduled = fields.Date(
string='Payment Execution Date', readonly=True, string="Payment Execution Date",
states={'draft': [('readonly', False)]}, track_visibility='onchange', readonly=True,
states={"draft": [("readonly", False)]},
track_visibility="onchange",
help="Select a requested date of execution if you selected 'Due Date' " help="Select a requested date of execution if you selected 'Due Date' "
"as the Payment Execution Date Type.") "as the Payment Execution Date Type.",
date_generated = fields.Date(string='File Generation Date', readonly=True) )
date_uploaded = fields.Date(string='File Upload Date', readonly=True) date_generated = fields.Date(string="File Generation Date", readonly=True)
date_done = fields.Date(string='Done Date', readonly=True) date_uploaded = fields.Date(string="File Upload Date", readonly=True)
date_done = fields.Date(string="Done Date", readonly=True)
generated_user_id = fields.Many2one( generated_user_id = fields.Many2one(
'res.users', string='Generated by', readonly=True, ondelete='restrict', "res.users",
copy=False) string="Generated by",
readonly=True,
ondelete="restrict",
copy=False,
)
payment_line_ids = fields.One2many( payment_line_ids = fields.One2many(
'account.payment.line', 'order_id', string='Transaction Lines', "account.payment.line",
readonly=True, states={'draft': [('readonly', False)]}) "order_id",
string="Transaction Lines",
readonly=True,
states={"draft": [("readonly", False)]},
)
# v8 field : line_ids # v8 field : line_ids
bank_line_ids = fields.One2many( bank_line_ids = fields.One2many(
'bank.payment.line', 'order_id', string="Bank Payment Lines", "bank.payment.line",
"order_id",
string="Bank Payment Lines",
readonly=True, readonly=True,
help="The bank payment lines are used to generate the payment file. " help="The bank payment lines are used to generate the payment file. "
"They are automatically created from transaction lines upon " "They are automatically created from transaction lines upon "
"confirmation of the payment order: one bank payment line can " "confirmation of the payment order: one bank payment line can "
"group several transaction lines if the option " "group several transaction lines if the option "
"'Group Transactions in Payment Orders' is active on the payment " "'Group Transactions in Payment Orders' is active on the payment "
"mode.") "mode.",
)
total_company_currency = fields.Monetary( total_company_currency = fields.Monetary(
compute='_compute_total', store=True, readonly=True, compute="_compute_total",
currency_field='company_currency_id') store=True,
readonly=True,
currency_field="company_currency_id",
)
bank_line_count = fields.Integer( bank_line_count = fields.Integer(
compute='_compute_bank_line_count', string='Number of Bank Lines', compute="_compute_bank_line_count", string="Number of Bank Lines", readonly=True
readonly=True) )
move_ids = fields.One2many( move_ids = fields.One2many(
'account.move', 'payment_order_id', string='Journal Entries', "account.move", "payment_order_id", string="Journal Entries", readonly=True
readonly=True) )
description = fields.Char() description = fields.Char()
@api.depends('payment_mode_id') @api.depends("payment_mode_id")
def _compute_allowed_journal_ids(self): def _compute_allowed_journal_ids(self):
for record in self: for record in self:
if record.payment_mode_id.bank_account_link == 'fixed': if record.payment_mode_id.bank_account_link == "fixed":
record.allowed_journal_ids = ( record.allowed_journal_ids = record.payment_mode_id.fixed_journal_id
record.payment_mode_id.fixed_journal_id) elif record.payment_mode_id.bank_account_link == "variable":
elif record.payment_mode_id.bank_account_link == 'variable': record.allowed_journal_ids = record.payment_mode_id.variable_journal_ids
record.allowed_journal_ids = (
record.payment_mode_id.variable_journal_ids)
@api.multi @api.multi
def unlink(self): def unlink(self):
for order in self: for order in self:
if order.state == 'uploaded': if order.state == "uploaded":
raise UserError(_( raise UserError(
_(
"You cannot delete an uploaded payment order. You can " "You cannot delete an uploaded payment order. You can "
"cancel it in order to do so.")) "cancel it in order to do so."
)
)
return super(AccountPaymentOrder, self).unlink() return super(AccountPaymentOrder, self).unlink()
@api.multi @api.multi
@api.constrains('payment_type', 'payment_mode_id') @api.constrains("payment_type", "payment_mode_id")
def payment_order_constraints(self): def payment_order_constraints(self):
for order in self: for order in self:
if ( if (
order.payment_mode_id.payment_type and order.payment_mode_id.payment_type
order.payment_mode_id.payment_type != order.payment_type): and order.payment_mode_id.payment_type != order.payment_type
raise ValidationError(_( ):
raise ValidationError(
_(
"The payment type (%s) is not the same as the payment " "The payment type (%s) is not the same as the payment "
"type of the payment mode (%s)") % ( "type of the payment mode (%s)"
order.payment_type, )
order.payment_mode_id.payment_type)) % (order.payment_type, order.payment_mode_id.payment_type)
)
@api.multi @api.multi
@api.constrains('date_scheduled') @api.constrains("date_scheduled")
def check_date_scheduled(self): def check_date_scheduled(self):
today = fields.Date.context_today(self) today = fields.Date.context_today(self)
for order in self: for order in self:
if order.date_scheduled: if order.date_scheduled:
if order.date_scheduled < today: if order.date_scheduled < today:
raise ValidationError(_( raise ValidationError(
_(
"On payment order %s, the Payment Execution Date " "On payment order %s, the Payment Execution Date "
"is in the past (%s).") "is in the past (%s)."
% (order.name, order.date_scheduled)) )
% (order.name, order.date_scheduled)
)
@api.multi @api.multi
@api.depends( @api.depends("payment_line_ids", "payment_line_ids.amount_company_currency")
'payment_line_ids', 'payment_line_ids.amount_company_currency')
def _compute_total(self): def _compute_total(self):
for rec in self: for rec in self:
rec.total_company_currency = sum( rec.total_company_currency = sum(
rec.mapped('payment_line_ids.amount_company_currency') or rec.mapped("payment_line_ids.amount_company_currency") or [0.0]
[0.0]) )
@api.multi @api.multi
@api.depends('bank_line_ids') @api.depends("bank_line_ids")
def _compute_bank_line_count(self): def _compute_bank_line_count(self):
for order in self: for order in self:
order.bank_line_count = len(order.bank_line_ids) order.bank_line_count = len(order.bank_line_ids)
@api.model @api.model
def create(self, vals): def create(self, vals):
if vals.get('name', 'New') == 'New': if vals.get("name", "New") == "New":
vals['name'] = self.env['ir.sequence'].next_by_code( vals["name"] = (
'account.payment.order') or 'New' self.env["ir.sequence"].next_by_code("account.payment.order") or "New"
if vals.get('payment_mode_id'): )
payment_mode = self.env['account.payment.mode'].browse( if vals.get("payment_mode_id"):
vals['payment_mode_id']) payment_mode = self.env["account.payment.mode"].browse(
vals['payment_type'] = payment_mode.payment_type vals["payment_mode_id"]
if payment_mode.bank_account_link == 'fixed': )
vals['journal_id'] = payment_mode.fixed_journal_id.id vals["payment_type"] = payment_mode.payment_type
if ( if payment_mode.bank_account_link == "fixed":
not vals.get('date_prefered') and vals["journal_id"] = payment_mode.fixed_journal_id.id
payment_mode.default_date_prefered): if not vals.get("date_prefered") and payment_mode.default_date_prefered:
vals['date_prefered'] = payment_mode.default_date_prefered vals["date_prefered"] = payment_mode.default_date_prefered
return super(AccountPaymentOrder, self).create(vals) return super(AccountPaymentOrder, self).create(vals)
@api.onchange('payment_mode_id') @api.onchange("payment_mode_id")
def payment_mode_id_change(self): def payment_mode_id_change(self):
if len(self.allowed_journal_ids) == 1: if len(self.allowed_journal_ids) == 1:
self.journal_id = self.allowed_journal_ids self.journal_id = self.allowed_journal_ids
@@ -186,10 +234,9 @@ class AccountPaymentOrder(models.Model):
@api.multi @api.multi
def action_done(self): def action_done(self):
self.write({ self.write(
'date_done': fields.Date.context_today(self), {"date_done": fields.Date.context_today(self), "state": "done",}
'state': 'done', )
})
return True return True
@api.multi @api.multi
@@ -204,23 +251,22 @@ class AccountPaymentOrder(models.Model):
@api.multi @api.multi
def cancel2draft(self): def cancel2draft(self):
self.write({'state': 'draft'}) self.write({"state": "draft"})
return True return True
@api.multi @api.multi
def action_cancel(self): def action_cancel(self):
for order in self: for order in self:
order.write({'state': 'cancel'}) order.write({"state": "cancel"})
order.bank_line_ids.unlink() order.bank_line_ids.unlink()
return True return True
@api.model @api.model
def _prepare_bank_payment_line(self, paylines): def _prepare_bank_payment_line(self, paylines):
return { return {
'order_id': paylines[0].order_id.id, "order_id": paylines[0].order_id.id,
'payment_line_ids': [(6, 0, paylines.ids)], "payment_line_ids": [(6, 0, paylines.ids)],
'communication': '-'.join( "communication": "-".join([line.communication for line in paylines]),
[line.communication for line in paylines]),
} }
@api.multi @api.multi
@@ -231,22 +277,25 @@ class AccountPaymentOrder(models.Model):
setting of the payment.order setting of the payment.order
Re-generate the bank payment lines Re-generate the bank payment lines
""" """
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: if not order.journal_id:
raise UserError(_( raise UserError(
'Missing Bank Journal on payment order %s.') % order.name) _("Missing Bank Journal on payment order %s.") % order.name
)
if ( if (
order.payment_method_id.bank_account_required and order.payment_method_id.bank_account_required
not order.journal_id.bank_account_id): and not order.journal_id.bank_account_id
raise UserError(_( ):
"Missing bank account on bank journal '%s'.") raise UserError(
% order.journal_id.display_name) _("Missing bank account on bank journal '%s'.")
% order.journal_id.display_name
)
if not order.payment_line_ids: if not order.payment_line_ids:
raise UserError(_( raise UserError(
'There are no transactions on payment order %s.') _("There are no transactions on payment order %s.") % order.name
% 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
@@ -254,9 +303,9 @@ class AccountPaymentOrder(models.Model):
for payline in order.payment_line_ids: for payline in order.payment_line_ids:
payline.draft2open_payment_line_check() payline.draft2open_payment_line_check()
# Compute requested payment date # Compute requested payment date
if order.date_prefered == 'due': if order.date_prefered == "due":
requested_date = payline.ml_maturity_date or today requested_date = payline.ml_maturity_date or today
elif order.date_prefered == 'fixed': elif order.date_prefered == "fixed":
requested_date = order.date_scheduled or today requested_date = order.date_scheduled or today
else: else:
requested_date = today requested_date = today
@@ -265,19 +314,25 @@ class AccountPaymentOrder(models.Model):
requested_date = today requested_date = today
# inbound: check option no_debit_before_maturity # inbound: check option no_debit_before_maturity
if ( if (
order.payment_type == 'inbound' and order.payment_type == "inbound"
order.payment_mode_id.no_debit_before_maturity and and order.payment_mode_id.no_debit_before_maturity
payline.ml_maturity_date and and payline.ml_maturity_date
requested_date < payline.ml_maturity_date): and requested_date < payline.ml_maturity_date
raise UserError(_( ):
raise UserError(
_(
"The payment mode '%s' has the option " "The payment mode '%s' has the option "
"'Disallow Debit Before Maturity Date'. The " "'Disallow Debit Before Maturity Date'. The "
"payment line %s has a maturity date %s " "payment line %s has a maturity date %s "
"which is after the computed payment date %s.") % ( "which is after the computed payment date %s."
)
% (
order.payment_mode_id.name, order.payment_mode_id.name,
payline.name, payline.name,
payline.ml_maturity_date, payline.ml_maturity_date,
requested_date)) requested_date,
)
)
# Write requested_date on 'date' field of payment line # Write requested_date on 'date' field of payment line
# norecompute is for avoiding a chained recomputation # norecompute is for avoiding a chained recomputation
# payment_line_ids.date # payment_line_ids.date
@@ -292,39 +347,40 @@ class AccountPaymentOrder(models.Model):
# Use line ID as hascode, which actually means no grouping # Use line ID as hascode, which actually means no grouping
hashcode = payline.id hashcode = payline.id
if hashcode in group_paylines: if hashcode in group_paylines:
group_paylines[hashcode]['paylines'] += payline group_paylines[hashcode]["paylines"] += payline
group_paylines[hashcode]['total'] +=\ group_paylines[hashcode]["total"] += payline.amount_currency
payline.amount_currency
else: else:
group_paylines[hashcode] = { group_paylines[hashcode] = {
'paylines': payline, "paylines": payline,
'total': payline.amount_currency, "total": payline.amount_currency,
} }
order.recompute() order.recompute()
# Create bank payment lines # Create bank payment lines
for paydict in list(group_paylines.values()): for paydict in list(group_paylines.values()):
# Block if a bank payment line is <= 0 # Block if a bank payment line is <= 0
if paydict['total'] <= 0: if paydict["total"] <= 0:
raise UserError(_( raise UserError(
"The amount for Partner '%s' is negative " _("The amount for Partner '%s' is negative " "or null (%.2f) !")
"or null (%.2f) !") % (paydict["paylines"][0].partner_id.name, paydict["total"])
% (paydict['paylines'][0].partner_id.name, )
paydict['total'])) vals = self._prepare_bank_payment_line(paydict["paylines"])
vals = self._prepare_bank_payment_line(paydict['paylines'])
bplo.create(vals) bplo.create(vals)
self.write({'state': 'open'}) self.write({"state": "open"})
return True return True
@api.multi @api.multi
def generate_payment_file(self): def generate_payment_file(self):
"""Returns (payment file as string, filename)""" """Returns (payment file as string, filename)"""
self.ensure_one() self.ensure_one()
if self.payment_method_id.code == 'manual': if self.payment_method_id.code == "manual":
return (False, False) return (False, False)
else: else:
raise UserError(_( raise UserError(
_(
"No handler for this payment method. Maybe you haven't " "No handler for this payment method. Maybe you haven't "
"installed the related Odoo module.")) "installed the related Odoo module."
)
)
@api.multi @api.multi
def open2generated(self): def open2generated(self):
@@ -332,29 +388,34 @@ class AccountPaymentOrder(models.Model):
payment_file_str, filename = self.generate_payment_file() payment_file_str, filename = self.generate_payment_file()
action = {} action = {}
if payment_file_str and filename: if payment_file_str and filename:
attachment = self.env['ir.attachment'].create({ attachment = self.env["ir.attachment"].create(
'res_model': 'account.payment.order', {
'res_id': self.id, "res_model": "account.payment.order",
'name': filename, "res_id": self.id,
'datas': base64.b64encode(payment_file_str), "name": filename,
'datas_fname': filename, "datas": base64.b64encode(payment_file_str),
}) "datas_fname": filename,
simplified_form_view = self.env.ref(
'account_payment_order.view_attachment_simplified_form')
action = {
'name': _('Payment File'),
'view_mode': 'form',
'view_id': simplified_form_view.id,
'res_model': 'ir.attachment',
'type': 'ir.actions.act_window',
'target': 'current',
'res_id': attachment.id,
} }
self.write({ )
'date_generated': fields.Date.context_today(self), simplified_form_view = self.env.ref(
'state': 'generated', "account_payment_order.view_attachment_simplified_form"
'generated_user_id': self._uid, )
}) action = {
"name": _("Payment File"),
"view_mode": "form",
"view_id": simplified_form_view.id,
"res_model": "ir.attachment",
"type": "ir.actions.act_window",
"target": "current",
"res_id": attachment.id,
}
self.write(
{
"date_generated": fields.Date.context_today(self),
"state": "generated",
"generated_user_id": self._uid,
}
)
return action return action
@api.multi @api.multi
@@ -362,58 +423,58 @@ class AccountPaymentOrder(models.Model):
for order in self: for order in self:
if order.payment_mode_id.generate_move: if order.payment_mode_id.generate_move:
order.generate_move() order.generate_move()
self.write({ self.write(
'state': 'uploaded', {"state": "uploaded", "date_uploaded": fields.Date.context_today(self),}
'date_uploaded': fields.Date.context_today(self), )
})
return True return True
@api.multi @api.multi
def _prepare_move(self, bank_lines=None): def _prepare_move(self, bank_lines=None):
if self.payment_type == 'outbound': if self.payment_type == "outbound":
ref = _('Payment order %s') % self.name ref = _("Payment order %s") % self.name
else: else:
ref = _('Debit order %s') % self.name ref = _("Debit order %s") % self.name
if bank_lines and len(bank_lines) == 1: if bank_lines and len(bank_lines) == 1:
ref += " - " + bank_lines.name ref += " - " + bank_lines.name
if self.payment_mode_id.offsetting_account == 'bank_account': if self.payment_mode_id.offsetting_account == "bank_account":
journal_id = self.journal_id.id journal_id = self.journal_id.id
elif self.payment_mode_id.offsetting_account == 'transfer_account': elif self.payment_mode_id.offsetting_account == "transfer_account":
journal_id = self.payment_mode_id.transfer_journal_id.id journal_id = self.payment_mode_id.transfer_journal_id.id
vals = { vals = {
'journal_id': journal_id, "journal_id": journal_id,
'ref': ref, "ref": ref,
'payment_order_id': self.id, "payment_order_id": self.id,
'line_ids': [], "line_ids": [],
} }
total_company_currency = total_payment_currency = 0 total_company_currency = total_payment_currency = 0
for bline in bank_lines: for bline in bank_lines:
total_company_currency += bline.amount_company_currency total_company_currency += bline.amount_company_currency
total_payment_currency += bline.amount_currency total_payment_currency += bline.amount_currency
partner_ml_vals = self._prepare_move_line_partner_account(bline) partner_ml_vals = self._prepare_move_line_partner_account(bline)
vals['line_ids'].append((0, 0, partner_ml_vals)) vals["line_ids"].append((0, 0, partner_ml_vals))
trf_ml_vals = self._prepare_move_line_offsetting_account( trf_ml_vals = self._prepare_move_line_offsetting_account(
total_company_currency, total_payment_currency, bank_lines) total_company_currency, total_payment_currency, bank_lines
vals['line_ids'].append((0, 0, trf_ml_vals)) )
vals["line_ids"].append((0, 0, trf_ml_vals))
return vals return vals
@api.multi @api.multi
def _prepare_move_line_offsetting_account( def _prepare_move_line_offsetting_account(
self, amount_company_currency, amount_payment_currency, self, amount_company_currency, amount_payment_currency, bank_lines
bank_lines): ):
vals = {} vals = {}
if self.payment_type == 'outbound': if self.payment_type == "outbound":
name = _('Payment order %s') % self.name name = _("Payment order %s") % self.name
else: else:
name = _('Debit order %s') % self.name name = _("Debit order %s") % self.name
if self.payment_mode_id.offsetting_account == 'bank_account': if self.payment_mode_id.offsetting_account == "bank_account":
vals.update({'date': bank_lines[0].date}) vals.update({"date": bank_lines[0].date})
else: else:
vals.update({'date_maturity': bank_lines[0].date}) vals.update({"date_maturity": bank_lines[0].date})
if self.payment_mode_id.offsetting_account == 'bank_account': if self.payment_mode_id.offsetting_account == "bank_account":
account_id = self.journal_id.default_debit_account_id.id account_id = self.journal_id.default_debit_account_id.id
elif self.payment_mode_id.offsetting_account == 'transfer_account': elif self.payment_mode_id.offsetting_account == "transfer_account":
account_id = self.payment_mode_id.transfer_account_id.id account_id = self.payment_mode_id.transfer_account_id.id
partner_id = False partner_id = False
for index, bank_line in enumerate(bank_lines): for index, bank_line in enumerate(bank_lines):
@@ -423,63 +484,74 @@ class AccountPaymentOrder(models.Model):
# we have different partners in the grouped move # we have different partners in the grouped move
partner_id = False partner_id = False
break break
vals.update({ vals.update(
'name': name, {
'partner_id': partner_id, "name": name,
'account_id': account_id, "partner_id": partner_id,
'credit': (self.payment_type == 'outbound' and "account_id": account_id,
amount_company_currency or 0.0), "credit": (
'debit': (self.payment_type == 'inbound' and self.payment_type == "outbound" and amount_company_currency or 0.0
amount_company_currency or 0.0), ),
}) "debit": (
self.payment_type == "inbound" and amount_company_currency or 0.0
),
}
)
if bank_lines[0].currency_id != bank_lines[0].company_currency_id: if bank_lines[0].currency_id != bank_lines[0].company_currency_id:
sign = self.payment_type == 'outbound' and -1 or 1 sign = self.payment_type == "outbound" and -1 or 1
vals.update({ vals.update(
'currency_id': bank_lines[0].currency_id.id, {
'amount_currency': amount_payment_currency * sign, "currency_id": bank_lines[0].currency_id.id,
}) "amount_currency": amount_payment_currency * sign,
}
)
return vals return vals
@api.multi @api.multi
def _prepare_move_line_partner_account(self, bank_line): def _prepare_move_line_partner_account(self, bank_line):
if bank_line.payment_line_ids[0].move_line_id: if bank_line.payment_line_ids[0].move_line_id:
account_id =\ account_id = bank_line.payment_line_ids[0].move_line_id.account_id.id
bank_line.payment_line_ids[0].move_line_id.account_id.id
else: else:
if self.payment_type == 'inbound': if self.payment_type == "inbound":
account_id =\ account_id = bank_line.partner_id.property_account_receivable_id.id
bank_line.partner_id.property_account_receivable_id.id
else: else:
account_id =\ account_id = bank_line.partner_id.property_account_payable_id.id
bank_line.partner_id.property_account_payable_id.id if self.payment_type == "outbound":
if self.payment_type == 'outbound': name = _("Payment bank line %s") % bank_line.name
name = _('Payment bank line %s') % bank_line.name
else: else:
name = _('Debit bank line %s') % bank_line.name name = _("Debit bank line %s") % bank_line.name
vals = { vals = {
'name': name, "name": name,
'bank_payment_line_id': bank_line.id, "bank_payment_line_id": bank_line.id,
'partner_id': bank_line.partner_id.id, "partner_id": bank_line.partner_id.id,
'account_id': account_id, "account_id": account_id,
'credit': (self.payment_type == 'inbound' and "credit": (
bank_line.amount_company_currency or 0.0), self.payment_type == "inbound"
'debit': (self.payment_type == 'outbound' and and bank_line.amount_company_currency
bank_line.amount_company_currency or 0.0), or 0.0
),
"debit": (
self.payment_type == "outbound"
and bank_line.amount_company_currency
or 0.0
),
} }
if bank_line.currency_id != bank_line.company_currency_id: if bank_line.currency_id != bank_line.company_currency_id:
sign = self.payment_type == 'inbound' and -1 or 1 sign = self.payment_type == "inbound" and -1 or 1
vals.update({ vals.update(
'currency_id': bank_line.currency_id.id, {
'amount_currency': bank_line.amount_currency * sign, "currency_id": bank_line.currency_id.id,
}) "amount_currency": bank_line.amount_currency * sign,
}
)
return vals return vals
@api.multi @api.multi
def _create_reconcile_move(self, hashcode, blines): def _create_reconcile_move(self, hashcode, blines):
self.ensure_one() self.ensure_one()
post_move = self.payment_mode_id.post_move post_move = self.payment_mode_id.post_move
am_obj = self.env['account.move'] am_obj = self.env["account.move"]
mvals = self._prepare_move(blines) mvals = self._prepare_move(blines)
move = am_obj.create(mvals) move = am_obj.create(mvals)
blines.reconcile_payment_lines() blines.reconcile_payment_lines()

View File

@@ -2,63 +2,83 @@
# Copyright 2018 Tecnativa - Pedro M. Baeza # Copyright 2018 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
from odoo.exceptions import UserError from odoo.exceptions import UserError
class BankPaymentLine(models.Model): class BankPaymentLine(models.Model):
_name = 'bank.payment.line' _name = "bank.payment.line"
_description = 'Bank Payment Lines' _description = "Bank Payment Lines"
name = fields.Char( name = fields.Char(string="Bank Payment Line Ref", required=True, readonly=True)
string='Bank Payment Line Ref', required=True,
readonly=True)
order_id = fields.Many2one( order_id = fields.Many2one(
'account.payment.order', string='Order', ondelete='cascade', "account.payment.order",
index=True, readonly=True) string="Order",
ondelete="cascade",
index=True,
readonly=True,
)
payment_type = fields.Selection( payment_type = fields.Selection(
related='order_id.payment_type', string="Payment Type", related="order_id.payment_type",
readonly=True, store=True) string="Payment Type",
readonly=True,
store=True,
)
state = fields.Selection( state = fields.Selection(
related='order_id.state', string='State', related="order_id.state", string="State", readonly=True, store=True
readonly=True, store=True) )
payment_line_ids = fields.One2many( payment_line_ids = fields.One2many(
'account.payment.line', 'bank_line_id', string='Payment Lines', "account.payment.line", "bank_line_id", string="Payment Lines", readonly=True
readonly=True) )
partner_id = fields.Many2one( partner_id = fields.Many2one(
'res.partner', related='payment_line_ids.partner_id', "res.partner", related="payment_line_ids.partner_id", readonly=True, store=True
readonly=True, store=True) # store=True for groupby ) # store=True for groupby
# 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 ? # But is it still true in v9 ?
amount_currency = fields.Monetary( amount_currency = fields.Monetary(
string='Amount', currency_field='currency_id', string="Amount",
compute='_compute_amount', store=True, readonly=True) currency_field="currency_id",
compute="_compute_amount",
store=True,
readonly=True,
)
amount_company_currency = fields.Monetary( amount_company_currency = fields.Monetary(
string='Amount in Company Currency', string="Amount in Company Currency",
currency_field='company_currency_id', currency_field="company_currency_id",
compute='_compute_amount', store=True, readonly=True) compute="_compute_amount",
store=True,
readonly=True,
)
currency_id = fields.Many2one( currency_id = fields.Many2one(
'res.currency', required=True, readonly=True, "res.currency",
related='payment_line_ids.currency_id') # v8 field: currency required=True,
readonly=True,
related="payment_line_ids.currency_id",
) # v8 field: currency
partner_bank_id = fields.Many2one( partner_bank_id = fields.Many2one(
'res.partner.bank', string='Bank Account', readonly=True, "res.partner.bank",
related='payment_line_ids.partner_bank_id') # v8 field: bank_id string="Bank Account",
date = fields.Date( readonly=True,
related='payment_line_ids.date', readonly=True) related="payment_line_ids.partner_bank_id",
) # v8 field: bank_id
date = fields.Date(related="payment_line_ids.date", readonly=True)
communication_type = fields.Selection( communication_type = fields.Selection(
related='payment_line_ids.communication_type', readonly=True) related="payment_line_ids.communication_type", readonly=True
communication = fields.Char( )
string='Communication', required=True, communication = fields.Char(string="Communication", required=True, readonly=True)
readonly=True)
company_id = fields.Many2one( company_id = fields.Many2one(
'res.company', "res.company",
related='order_id.payment_mode_id.company_id', store=True, related="order_id.payment_mode_id.company_id",
readonly=True) store=True,
readonly=True,
)
company_currency_id = fields.Many2one( company_currency_id = fields.Many2one(
'res.currency', "res.currency",
related='order_id.payment_mode_id.company_id.currency_id', related="order_id.payment_mode_id.company_id.currency_id",
readonly=True, store=True) readonly=True,
store=True,
)
@api.model @api.model
def same_fields_payment_line_and_bank_payment_line(self): def same_fields_payment_line_and_bank_payment_line(self):
@@ -69,29 +89,35 @@ class BankPaymentLine(models.Model):
The fields must have the same name on the 2 objects The fields must have the same name on the 2 objects
""" """
same_fields = [ same_fields = [
'currency_id', 'partner_id', "currency_id",
'partner_bank_id', 'date', 'communication_type'] "partner_id",
"partner_bank_id",
"date",
"communication_type",
]
return same_fields return same_fields
@api.multi @api.multi
@api.depends('payment_line_ids', 'payment_line_ids.amount_currency') @api.depends("payment_line_ids", "payment_line_ids.amount_currency")
def _compute_amount(self): def _compute_amount(self):
for bline in self: for bline in self:
amount_currency = sum( amount_currency = sum(bline.mapped("payment_line_ids.amount_currency"))
bline.mapped('payment_line_ids.amount_currency'))
amount_company_currency = bline.currency_id._convert( amount_company_currency = bline.currency_id._convert(
amount_currency, bline.company_currency_id, bline.company_id, amount_currency,
bline.company_currency_id,
bline.company_id,
bline.date or fields.Date.today(), bline.date or fields.Date.today(),
) )
bline.amount_currency = amount_currency bline.amount_currency = amount_currency
bline.amount_company_currency = amount_company_currency bline.amount_company_currency = amount_company_currency
@api.model @api.model
@api.returns('self') @api.returns("self")
def create(self, vals): def create(self, vals):
if vals.get('name', 'New') == 'New': if vals.get("name", "New") == "New":
vals['name'] = self.env['ir.sequence'].next_by_code( vals["name"] = (
'bank.payment.line') or 'New' self.env["ir.sequence"].next_by_code("bank.payment.line") or "New"
)
return super(BankPaymentLine, self).create(vals) return super(BankPaymentLine, self).create(vals)
@api.multi @api.multi
@@ -101,7 +127,7 @@ class BankPaymentLine(models.Model):
account_banking_sepa_direct_debit account_banking_sepa_direct_debit
""" """
self.ensure_one() self.ensure_one()
if self.order_id.payment_mode_id.move_option == 'date': if self.order_id.payment_mode_id.move_option == "date":
hashcode = fields.Date.to_string(self.date) hashcode = fields.Date.to_string(self.date)
else: else:
hashcode = str(self.id) hashcode = str(self.id)
@@ -123,37 +149,40 @@ class BankPaymentLine(models.Model):
@api.multi @api.multi
def reconcile(self): def reconcile(self):
self.ensure_one() self.ensure_one()
amlo = self.env['account.move.line'] amlo = self.env["account.move.line"]
transit_mlines = amlo.search([('bank_payment_line_id', '=', self.id)]) transit_mlines = amlo.search([("bank_payment_line_id", "=", self.id)])
assert len(transit_mlines) == 1, 'We should have only 1 move' assert len(transit_mlines) == 1, "We should have only 1 move"
transit_mline = transit_mlines[0] transit_mline = transit_mlines[0]
assert not transit_mline.reconciled,\ assert not transit_mline.reconciled, "Transit move should not be reconciled"
'Transit move should not be reconciled'
lines_to_rec = transit_mline lines_to_rec = transit_mline
for payment_line in self.payment_line_ids: for payment_line in self.payment_line_ids:
if not payment_line.move_line_id: if not payment_line.move_line_id:
raise UserError(_( raise UserError(
_(
"Can not reconcile: no move line for " "Can not reconcile: no move line for "
"payment line %s of partner '%s'.") % ( "payment line %s of partner '%s'."
payment_line.name, )
payment_line.partner_id.name)) % (payment_line.name, payment_line.partner_id.name)
)
if payment_line.move_line_id.reconciled: if payment_line.move_line_id.reconciled:
raise UserError(_( raise UserError(
"Move line '%s' of partner '%s' has already " _("Move line '%s' of partner '%s' has already " "been reconciled")
"been reconciled") % ( % (payment_line.move_line_id.name, payment_line.partner_id.name)
payment_line.move_line_id.name, )
payment_line.partner_id.name)) if payment_line.move_line_id.account_id != transit_mline.account_id:
if ( raise UserError(
payment_line.move_line_id.account_id != _(
transit_mline.account_id):
raise UserError(_(
"For partner '%s', the account of the account " "For partner '%s', the account of the account "
"move line to pay (%s) is different from the " "move line to pay (%s) is different from the "
"account of of the transit move line (%s).") % ( "account of of the transit move line (%s)."
)
% (
payment_line.move_line_id.partner_id.name, payment_line.move_line_id.partner_id.name,
payment_line.move_line_id.account_id.code, payment_line.move_line_id.account_id.code,
transit_mline.account_id.code)) transit_mline.account_id.code,
)
)
lines_to_rec += payment_line.move_line_id lines_to_rec += payment_line.move_line_id
@@ -163,9 +192,12 @@ class BankPaymentLine(models.Model):
def unlink(self): def unlink(self):
for line in self: for line in self:
order_state = line.order_id.state order_state = line.order_id.state
if order_state == 'uploaded': if order_state == "uploaded":
raise UserError(_( raise UserError(
'Cannot delete a payment order line whose payment order is' _(
' in state \'%s\'. You need to cancel it first.') "Cannot delete a payment order line whose payment order is"
% order_state) " in state '%s'. You need to cancel it first."
)
% order_state
)
return super(BankPaymentLine, self).unlink() return super(BankPaymentLine, self).unlink()

View File

@@ -1,21 +1,25 @@
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com> # © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, api, _ from odoo import _, api, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
class ResBank(models.Model): class ResBank(models.Model):
_inherit = 'res.bank' _inherit = "res.bank"
@api.multi @api.multi
@api.constrains('bic') @api.constrains("bic")
def check_bic_length(self): def check_bic_length(self):
for bank in self: for bank in self:
if bank.bic and len(bank.bic) not in (8, 11): if bank.bic and len(bank.bic) not in (8, 11):
raise ValidationError(_( raise ValidationError(
_(
"A valid BIC contains 8 or 11 characters. The BIC '%s' " "A valid BIC contains 8 or 11 characters. The BIC '%s' "
"contains %d characters, so it is not valid.") "contains %d characters, so it is not valid."
% (bank.bic, len(bank.bic))) )
% (bank.bic, len(bank.bic))
)
# starting from v9, on res.partner.bank bank_bic is a related of bank_id.bic # starting from v9, on res.partner.bank bank_bic is a related of bank_id.bic

View File

@@ -6,22 +6,22 @@ from odoo.tools.misc import formatLang
class AccountPaymentOrderReport(models.AbstractModel): class AccountPaymentOrderReport(models.AbstractModel):
_name = 'report.account_payment_order.print_account_payment_order_main' _name = "report.account_payment_order.print_account_payment_order_main"
_description = 'Technical model for printing payment order' _description = "Technical model for printing payment order"
@api.model @api.model
def _get_report_values(self, docids, data=None): def _get_report_values(self, docids, data=None):
AccountPaymentOrderObj = self.env['account.payment.order'] AccountPaymentOrderObj = self.env["account.payment.order"]
docs = AccountPaymentOrderObj.browse(docids) docs = AccountPaymentOrderObj.browse(docids)
return { return {
'doc_ids': docids, "doc_ids": docids,
'doc_model': 'account.payment.order', "doc_model": "account.payment.order",
'docs': docs, "docs": docs,
'data': data, "data": data,
'env': self.env, "env": self.env,
'get_bank_account_name': self.get_bank_account_name, "get_bank_account_name": self.get_bank_account_name,
'formatLang': formatLang, "formatLang": formatLang,
} }
@api.model @api.model
@@ -32,15 +32,15 @@ class AccountPaymentOrderReport(models.AbstractModel):
:return: :return:
""" """
if partner_bank: if partner_bank:
name = '' name = ""
if partner_bank.bank_name: if partner_bank.bank_name:
name = '%s: ' % partner_bank.bank_id.name name = "%s: " % partner_bank.bank_id.name
if partner_bank.acc_number: if partner_bank.acc_number:
name = '%s %s' % (name, partner_bank.acc_number) name = "{} {}".format(name, partner_bank.acc_number)
if partner_bank.bank_bic: if partner_bank.bank_bic:
name = '%s - ' % (name) name = "%s - " % (name)
if partner_bank.bank_bic: if partner_bank.bank_bic:
name = '%s BIC %s' % (name, partner_bank.bank_bic) name = "{} BIC {}".format(name, partner_bank.bank_bic)
return name return name
else: else:
return False return False

View File

@@ -2,32 +2,45 @@
<!-- Copyright 2017 ACSONE SA/NV <!-- Copyright 2017 ACSONE SA/NV
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<template id="print_account_payment_order_document"> <template id="print_account_payment_order_document">
<t t-set="doc" t-value="doc.with_context({'lang':doc.generated_user_id.lang})" /> <t
t-set="doc"
t-value="doc.with_context({'lang':doc.generated_user_id.lang})"
/>
<t t-call="web.external_layout"> <t t-call="web.external_layout">
<div class="page"> <div class="page">
<div class="oe_structure" /> <div class="oe_structure" />
<div class="row"> <div class="row">
<div class="col-4 offset-8"> <div class="col-4 offset-8">
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.name if doc.journal_id.bank_id.name else ''"/> <span
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.street if doc.journal_id.bank_id.street else ''"/> t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.name if doc.journal_id.bank_id.name else ''"
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.street2 if doc.journal_id.bank_id.street2 else ''"/> />
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.zip if doc.journal_id.bank_id.zip else ''"/> <span
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.city if doc.journal_id.bank_id.city else ''"/> t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.street if doc.journal_id.bank_id.street else ''"
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.state.name if doc.journal_id.bank_id.state.name else ''"/> />
<span t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.country.name if doc.journal_id.bank_id.country.name else ''"/> <span
t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.street2 if doc.journal_id.bank_id.street2 else ''"
/>
<span
t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.zip if doc.journal_id.bank_id.zip else ''"
/>
<span
t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.city if doc.journal_id.bank_id.city else ''"
/>
<span
t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.state.name if doc.journal_id.bank_id.state.name else ''"
/>
<span
t-raw="'%s &lt;br&gt;' % doc.journal_id.bank_id.country.name if doc.journal_id.bank_id.country.name else ''"
/>
</div> </div>
</div> </div>
<t t-if="doc.payment_type == 'inbound'"> <t t-if="doc.payment_type == 'inbound'">
<h2>Debit Order</h2> <h2>Debit Order</h2>
</t> </t>
<t t-else=""> <t t-else="">
<h2>Payment Order</h2> <h2>Payment Order</h2>
</t> </t>
<div class="row mt32 mb32"> <div class="row mt32 mb32">
<div t-if="doc.payment_mode_id.name" class="col-2"> <div t-if="doc.payment_mode_id.name" class="col-2">
<strong>Payment Type:</strong> <strong>Payment Type:</strong>
@@ -40,7 +53,9 @@
<div t-if="doc.company_partner_bank_id.bank_id.id" class="col-2"> <div t-if="doc.company_partner_bank_id.bank_id.id" class="col-2">
<strong>Used Account:</strong> <strong>Used Account:</strong>
<p> <p>
<span t-esc="get_bank_account_name(doc.company_partner_bank_id)"/> <span
t-esc="get_bank_account_name(doc.company_partner_bank_id)"
/>
</p> </p>
</div> </div>
<div t-if="doc.date_prefered" class="col-2"> <div t-if="doc.date_prefered" class="col-2">
@@ -52,7 +67,6 @@
<p t-field="doc.company_id.currency_id.name" /> <p t-field="doc.company_id.currency_id.name" />
</div> </div>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">
<thead> <thead>
<tr> <tr>
@@ -69,23 +83,32 @@
see _get_amount_total v8 see _get_amount_total v8
--> -->
<t t-set="total_amount" t-value="0" /> <t t-set="total_amount" t-value="0" />
<tr t-foreach="doc.payment_line_ids" t-as="line"> <tr t-foreach="doc.payment_line_ids" t-as="line">
<!-- compute total amount --> <!-- compute total amount -->
<t t-set="total_amount" t-value="total_amount+line.amount_currency"/> <t
t-set="total_amount"
t-value="total_amount+line.amount_currency"
/>
<td> <td>
<span t-field="line.partner_id.name" /> <span t-field="line.partner_id.name" />
</td> </td>
<td class="text-center"> <td class="text-center">
<span t-esc="get_bank_account_name(line.partner_bank_id)"/> <span
t-esc="get_bank_account_name(line.partner_bank_id)"
/>
</td> </td>
<td class="text-center"> <td class="text-center">
<t t-if="line.move_line_id.invoice_id and 'in_' in line.move_line_id.invoice_id.type"> <t
<span t-field="line.move_line_id.invoice_id.reference"/> t-if="line.move_line_id.invoice_id and 'in_' in line.move_line_id.invoice_id.type"
>
<span
t-field="line.move_line_id.invoice_id.reference"
/>
</t> </t>
<t t-else=""> <t t-else="">
<span t-esc="line.move_line_id.invoice_id.number or line.move_line_id.move_id.name"/> <span
t-esc="line.move_line_id.invoice_id.number or line.move_line_id.move_id.name"
/>
</t> </t>
</td> </td>
<td class="text-center"> <td class="text-center">
@@ -100,14 +123,17 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="row pull-right"> <div class="row pull-right">
<div class="col-4"> <div class="col-4">
<table class="table table-condensed"> <table class="table table-condensed">
<tr class="border-black"> <tr class="border-black">
<td><strong>Total</strong></td> <td>
<strong>Total</strong>
</td>
<td class="text-right"> <td class="text-right">
<span t-esc="formatLang(env, total_amount, currency_obj=doc.company_currency_id)"/> <span
t-esc="formatLang(env, total_amount, currency_obj=doc.company_currency_id)"
/>
</td> </td>
</tr> </tr>
<tr> <tr>
@@ -119,18 +145,18 @@
</table> </table>
</div> </div>
</div> </div>
<div class="oe_structure" /> <div class="oe_structure" />
</div> </div>
</t> </t>
</template> </template>
<template id="print_account_payment_order_main"> <template id="print_account_payment_order_main">
<t t-call="web.html_container"> <t t-call="web.html_container">
<t t-foreach="docs" t-as="doc"> <t t-foreach="docs" t-as="doc">
<t t-call="account_payment_order.print_account_payment_order_document" t-lang="doc.generated_user_id.lang"/> <t
t-call="account_payment_order.print_account_payment_order_document"
t-lang="doc.generated_user_id.lang"
/>
</t> </t>
</t> </t>
</template> </template>
</odoo> </odoo>

View File

@@ -2,7 +2,6 @@
<!-- Copyright 2017 ACSONE SA/NV <!-- Copyright 2017 ACSONE SA/NV
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<!-- QWeb Report --> <!-- QWeb Report -->
<report <report
id="action_print_payment_order" id="action_print_payment_order"
@@ -12,5 +11,4 @@
name="account_payment_order.print_account_payment_order_main" name="account_payment_order.print_account_payment_order_main"
file="account_payment_order.print_account_payment_order_main" file="account_payment_order.print_account_payment_order_main"
/> />
</odoo> </odoo>

View File

@@ -1,37 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<data noupdate="0"> <data noupdate="0">
<record id="group_account_payment" model="res.groups"> <record id="group_account_payment" model="res.groups">
<field name="name">Accounting / Payments</field> <field name="name">Accounting / Payments</field>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/> <field
name="users"
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
/>
<field name="category_id" ref="base.module_category_extra" /> <field name="category_id" ref="base.module_category_extra" />
</record> </record>
</data> </data>
<data noupdate="1"> <data noupdate="1">
<record id="account_payment_order_company_rule" model="ir.rule"> <record id="account_payment_order_company_rule" model="ir.rule">
<field name="name">Payment order multi-company rule</field> <field name="name">Payment order multi-company rule</field>
<field name="model_id" ref="model_account_payment_order" /> <field name="model_id" ref="model_account_payment_order" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
<record id="account_payment_line_company_rule" model="ir.rule"> <record id="account_payment_line_company_rule" model="ir.rule">
<field name="name">Payment line multi-company rule</field> <field name="name">Payment line multi-company rule</field>
<field name="model_id" ref="model_account_payment_line" /> <field name="model_id" ref="model_account_payment_line" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
<record id="bank_payment_line_company_rule" model="ir.rule"> <record id="bank_payment_line_company_rule" model="ir.rule">
<field name="name">Bank payment line multi-company rule</field> <field name="name">Bank payment line multi-company rule</field>
<field name="model_id" ref="model_bank_payment_line" /> <field name="model_id" ref="model_bank_payment_line" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field> <field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record> </record>
</data> </data>
</odoo> </odoo>

View File

@@ -5,31 +5,34 @@ from odoo.tests.common import SavepointCase
class TestAccountPayment(SavepointCase): class TestAccountPayment(SavepointCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(TestAccountPayment, cls).setUpClass() super(TestAccountPayment, cls).setUpClass()
# MODELS # MODELS
cls.account_payment_model = cls.env['account.payment'] cls.account_payment_model = cls.env["account.payment"]
cls.account_journal_model = cls.env['account.journal'] cls.account_journal_model = cls.env["account.journal"]
cls.payment_method_model = cls.env['account.payment.method'] cls.payment_method_model = cls.env["account.payment.method"]
# INSTANCES # INSTANCES
# Payment methods # Payment methods
cls.inbound_payment_method_01, cls.inbound_payment_method_02 = \ (
cls.payment_method_model.search( cls.inbound_payment_method_01,
[('payment_type', '=', 'inbound')], limit=2) cls.inbound_payment_method_02,
) = cls.payment_method_model.search([("payment_type", "=", "inbound")], limit=2)
cls.outbound_payment_method_01 = cls.payment_method_model.search( cls.outbound_payment_method_01 = cls.payment_method_model.search(
[('payment_type', '=', 'outbound')], limit=1) [("payment_type", "=", "outbound")], limit=1
)
# Journals # Journals
cls.bank_journal = cls.account_journal_model.search( cls.bank_journal = cls.account_journal_model.search(
[('type', '=', 'bank')], limit=1) [("type", "=", "bank")], limit=1
)
cls.bank_journal.inbound_payment_method_ids = [ cls.bank_journal.inbound_payment_method_ids = [
(6, 0, [cls.inbound_payment_method_01.id, (6, 0, [cls.inbound_payment_method_01.id, cls.inbound_payment_method_02.id])
cls.inbound_payment_method_02.id])] ]
cls.bank_journal.outbound_payment_method_ids = [ cls.bank_journal.outbound_payment_method_ids = [
(6, 0, [cls.outbound_payment_method_01.id])] (6, 0, [cls.outbound_payment_method_01.id])
]
def test_account_payment_01(self): def test_account_payment_01(self):
self.assertFalse(self.inbound_payment_method_01.payment_order_only) self.assertFalse(self.inbound_payment_method_01.payment_order_only)
@@ -55,41 +58,43 @@ class TestAccountPayment(SavepointCase):
self.assertFalse(self.inbound_payment_method_01.payment_order_only) self.assertFalse(self.inbound_payment_method_01.payment_order_only)
self.assertFalse(self.inbound_payment_method_02.payment_order_only) self.assertFalse(self.inbound_payment_method_02.payment_order_only)
self.assertFalse(self.bank_journal.inbound_payment_order_only) self.assertFalse(self.bank_journal.inbound_payment_order_only)
new_account_payment = self.account_payment_model.new({ new_account_payment = self.account_payment_model.new(
'journal_id': self.bank_journal.id, {
'payment_type': 'inbound', "journal_id": self.bank_journal.id,
'amount': 1, "payment_type": "inbound",
}) "amount": 1,
}
)
# check journals # check journals
journal_res = new_account_payment._compute_journal_domain_and_types() journal_res = new_account_payment._compute_journal_domain_and_types()
journal_domain = journal_res.get('domain') journal_domain = journal_res.get("domain")
self.assertTrue(journal_domain) self.assertTrue(journal_domain)
journals = self.account_journal_model.search(journal_domain) journals = self.account_journal_model.search(journal_domain)
self.assertIn(self.bank_journal, journals) self.assertIn(self.bank_journal, journals)
# check payment methods # check payment methods
payment_method_res = new_account_payment._onchange_journal() payment_method_res = new_account_payment._onchange_journal()
payment_method_domain = payment_method_res.get('domain', {}).get( payment_method_domain = payment_method_res.get("domain", {}).get(
'payment_method_id') "payment_method_id"
)
self.assertTrue(payment_method_domain) self.assertTrue(payment_method_domain)
payment_methods = self.payment_method_model.search( payment_methods = self.payment_method_model.search(payment_method_domain)
payment_method_domain)
self.assertIn(self.inbound_payment_method_01, payment_methods) self.assertIn(self.inbound_payment_method_01, payment_methods)
self.assertIn(self.inbound_payment_method_02, payment_methods) self.assertIn(self.inbound_payment_method_02, payment_methods)
# Set one payment method of the bank journal 'payment order only' # Set one payment method of the bank journal 'payment order only'
self.inbound_payment_method_01.payment_order_only = True self.inbound_payment_method_01.payment_order_only = True
# check journals # check journals
journal_res = new_account_payment._compute_journal_domain_and_types() journal_res = new_account_payment._compute_journal_domain_and_types()
journal_domain = journal_res.get('domain') journal_domain = journal_res.get("domain")
self.assertTrue(journal_domain) self.assertTrue(journal_domain)
journals = self.account_journal_model.search(journal_domain) journals = self.account_journal_model.search(journal_domain)
self.assertIn(self.bank_journal, journals) self.assertIn(self.bank_journal, journals)
# check payment methods # check payment methods
payment_method_res = new_account_payment._onchange_journal() payment_method_res = new_account_payment._onchange_journal()
payment_method_domain = payment_method_res.get('domain', {}).get( payment_method_domain = payment_method_res.get("domain", {}).get(
'payment_method_id') "payment_method_id"
)
self.assertTrue(payment_method_domain) self.assertTrue(payment_method_domain)
payment_methods = self.payment_method_model.search( payment_methods = self.payment_method_model.search(payment_method_domain)
payment_method_domain)
self.assertNotIn(self.inbound_payment_method_01, payment_methods) self.assertNotIn(self.inbound_payment_method_01, payment_methods)
self.assertIn(self.inbound_payment_method_02, payment_methods) self.assertIn(self.inbound_payment_method_02, payment_methods)
# Set all payment methods of the bank journal 'payment order only' # Set all payment methods of the bank journal 'payment order only'
@@ -99,16 +104,16 @@ class TestAccountPayment(SavepointCase):
self.assertTrue(self.bank_journal.inbound_payment_order_only) self.assertTrue(self.bank_journal.inbound_payment_order_only)
# check journals # check journals
journal_res = new_account_payment._compute_journal_domain_and_types() journal_res = new_account_payment._compute_journal_domain_and_types()
journal_domain = journal_res.get('domain') journal_domain = journal_res.get("domain")
self.assertTrue(journal_domain) self.assertTrue(journal_domain)
journals = self.account_journal_model.search(journal_domain) journals = self.account_journal_model.search(journal_domain)
self.assertNotIn(self.bank_journal, journals) self.assertNotIn(self.bank_journal, journals)
# check payment methods # check payment methods
payment_method_res = new_account_payment._onchange_journal() payment_method_res = new_account_payment._onchange_journal()
payment_method_domain = payment_method_res.get('domain', {}).get( payment_method_domain = payment_method_res.get("domain", {}).get(
'payment_method_id') "payment_method_id"
)
self.assertTrue(payment_method_domain) self.assertTrue(payment_method_domain)
payment_methods = self.payment_method_model.search( payment_methods = self.payment_method_model.search(payment_method_domain)
payment_method_domain)
self.assertNotIn(self.inbound_payment_method_01, payment_methods) self.assertNotIn(self.inbound_payment_method_01, payment_methods)
self.assertNotIn(self.inbound_payment_method_02, payment_methods) self.assertNotIn(self.inbound_payment_method_02, payment_methods)

View File

@@ -1,14 +1,13 @@
# © 2017 Creu Blanca # © 2017 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestBank(TransactionCase): class TestBank(TransactionCase):
def test_bank(self): def test_bank(self):
bank = self.env['res.bank'].search([], limit=1) bank = self.env["res.bank"].search([], limit=1)
self.assertTrue(bank) self.assertTrue(bank)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
bank.bic = "TEST" bank.bic = "TEST"

View File

@@ -1,102 +1,115 @@
# © 2017 Creu Blanca # © 2017 Creu Blanca
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase
class TestPaymentMode(TransactionCase): class TestPaymentMode(TransactionCase):
def setUp(self): def setUp(self):
super(TestPaymentMode, self).setUp() super(TestPaymentMode, self).setUp()
# Company # Company
self.company = self.env.ref('base.main_company') self.company = self.env.ref("base.main_company")
self.journal_c1 = self.env['account.journal'].create({ self.journal_c1 = self.env["account.journal"].create(
'name': 'Journal 1', {
'code': 'J1', "name": "Journal 1",
'type': 'bank', "code": "J1",
'company_id': self.company.id, "type": "bank",
}) "company_id": self.company.id,
}
)
self.account = self.env['account.account'].search([ self.account = self.env["account.account"].search(
('reconcile', '=', True), [("reconcile", "=", True), ("company_id", "=", self.company.id)], limit=1
('company_id', '=', self.company.id) )
], limit=1)
self.manual_out = self.env.ref( self.manual_out = self.env.ref("account.account_payment_method_manual_out")
'account.account_payment_method_manual_out')
self.manual_in = self.env.ref( self.manual_in = self.env.ref("account.account_payment_method_manual_in")
'account.account_payment_method_manual_in')
self.electronic_out = self.env['account.payment.method'].create({ self.electronic_out = self.env["account.payment.method"].create(
'name': 'Electronic Out', {
'code': 'electronic_out', "name": "Electronic Out",
'payment_type': 'outbound', "code": "electronic_out",
}) "payment_type": "outbound",
}
)
self.payment_mode_c1 = self.env['account.payment.mode'].create({ self.payment_mode_c1 = self.env["account.payment.mode"].create(
'name': 'Direct Debit of suppliers from Bank 1', {
'bank_account_link': 'variable', "name": "Direct Debit of suppliers from Bank 1",
'payment_method_id': self.manual_out.id, "bank_account_link": "variable",
'company_id': self.company.id, "payment_method_id": self.manual_out.id,
'fixed_journal_id': self.journal_c1.id, "company_id": self.company.id,
'variable_journal_ids': [(6, 0, [self.journal_c1.id])] "fixed_journal_id": self.journal_c1.id,
}) "variable_journal_ids": [(6, 0, [self.journal_c1.id])],
}
)
def test_constrains(self): def test_constrains(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.payment_mode_c1.write({ self.payment_mode_c1.write(
'generate_move': True, {"generate_move": True, "offsetting_account": False}
'offsetting_account': False )
})
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.payment_mode_c1.write({ self.payment_mode_c1.write(
'generate_move': True, {
'offsetting_account': 'bank_account', "generate_move": True,
'move_option': False "offsetting_account": "bank_account",
}) "move_option": False,
}
)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.payment_mode_c1.write({ self.payment_mode_c1.write(
'generate_move': True, {
'offsetting_account': 'transfer_account', "generate_move": True,
'transfer_account_id': False "offsetting_account": "transfer_account",
}) "transfer_account_id": False,
}
)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.payment_mode_c1.write({ self.payment_mode_c1.write(
'generate_move': True, {
'offsetting_account': 'transfer_account', "generate_move": True,
'transfer_account_id': self.account.id, "offsetting_account": "transfer_account",
'transfer_journal_id': False "transfer_account_id": self.account.id,
}) "transfer_journal_id": False,
}
)
def test_onchange_generate_move(self): def test_onchange_generate_move(self):
self.payment_mode_c1.generate_move = True self.payment_mode_c1.generate_move = True
self.payment_mode_c1.generate_move_change() self.payment_mode_c1.generate_move_change()
self.assertEqual(self.payment_mode_c1.move_option, 'date') self.assertEqual(self.payment_mode_c1.move_option, "date")
self.payment_mode_c1.generate_move = False self.payment_mode_c1.generate_move = False
self.payment_mode_c1.generate_move_change() self.payment_mode_c1.generate_move_change()
self.assertFalse(self.payment_mode_c1.move_option) self.assertFalse(self.payment_mode_c1.move_option)
def test_onchange_offsetting_account(self): def test_onchange_offsetting_account(self):
self.payment_mode_c1.offsetting = 'bank_account' self.payment_mode_c1.offsetting = "bank_account"
self.payment_mode_c1.offsetting_account_change() self.payment_mode_c1.offsetting_account_change()
self.assertFalse(self.payment_mode_c1.transfer_account_id) self.assertFalse(self.payment_mode_c1.transfer_account_id)
def test_onchange_payment_type(self): def test_onchange_payment_type(self):
self.payment_mode_c1.payment_method_id = self.manual_in self.payment_mode_c1.payment_method_id = self.manual_in
self.payment_mode_c1.payment_method_id_change() self.payment_mode_c1.payment_method_id_change()
self.assertTrue(all([ self.assertTrue(
journal.type in [ all(
'sale_refund', 'sale' [
] for journal in self.payment_mode_c1.default_journal_ids journal.type in ["sale_refund", "sale"]
])) for journal in self.payment_mode_c1.default_journal_ids
]
)
)
self.payment_mode_c1.payment_method_id = self.manual_out self.payment_mode_c1.payment_method_id = self.manual_out
self.payment_mode_c1.payment_method_id_change() self.payment_mode_c1.payment_method_id_change()
self.assertTrue(all([ self.assertTrue(
journal.type in [ all(
'purchase_refund', 'purchase' [
] for journal in self.payment_mode_c1.default_journal_ids journal.type in ["purchase_refund", "purchase"]
])) for journal in self.payment_mode_c1.default_journal_ids
]
)
)

View File

@@ -3,10 +3,11 @@
# Copyright 2019 Tecnativa - Pedro M. Baeza # Copyright 2019 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo.tests.common import SavepointCase
from odoo.exceptions import ValidationError, UserError
from datetime import date, timedelta from datetime import date, timedelta
from odoo.exceptions import UserError, ValidationError
from odoo.tests.common import SavepointCase
class TestPaymentOrderInboundBase(SavepointCase): class TestPaymentOrderInboundBase(SavepointCase):
@classmethod @classmethod
@@ -14,85 +15,112 @@ class TestPaymentOrderInboundBase(SavepointCase):
self = cls self = cls
super().setUpClass() super().setUpClass()
self.inbound_mode = self.env.ref( self.inbound_mode = self.env.ref(
'account_payment_mode.payment_mode_inbound_dd1' "account_payment_mode.payment_mode_inbound_dd1"
) )
self.invoice_line_account = self.env['account.account'].search( self.invoice_line_account = (
[('user_type_id', '=', self.env.ref( self.env["account.account"]
'account.data_account_type_revenue').id)], .search(
limit=1).id [
self.journal = self.env['account.journal'].search( (
[('type', '=', 'bank')], limit=1 "user_type_id",
"=",
self.env.ref("account.data_account_type_revenue").id,
)
],
limit=1,
)
.id
)
self.journal = self.env["account.journal"].search(
[("type", "=", "bank")], limit=1
) )
self.inbound_mode.variable_journal_ids = self.journal self.inbound_mode.variable_journal_ids = self.journal
# Make sure no others orders are present # Make sure no others orders are present
self.domain = [ self.domain = [
('state', '=', 'draft'), ("state", "=", "draft"),
('payment_type', '=', 'inbound'), ("payment_type", "=", "inbound"),
] ]
self.payment_order_obj = self.env['account.payment.order'] self.payment_order_obj = self.env["account.payment.order"]
self.payment_order_obj.search(self.domain).unlink() self.payment_order_obj.search(self.domain).unlink()
# Create payment order # Create payment order
self.inbound_order = self.env['account.payment.order'].create({ self.inbound_order = self.env["account.payment.order"].create(
'payment_type': 'inbound', {
'payment_mode_id': self.inbound_mode.id, "payment_type": "inbound",
'journal_id': self.journal.id, "payment_mode_id": self.inbound_mode.id,
}) "journal_id": self.journal.id,
}
)
# Open invoice # Open invoice
self.invoice = self._create_customer_invoice(self) self.invoice = self._create_customer_invoice(self)
self.invoice.action_invoice_open() self.invoice.action_invoice_open()
# Add to payment order using the wizard # Add to payment order using the wizard
self.env['account.invoice.payment.line.multi'].with_context( self.env["account.invoice.payment.line.multi"].with_context(
active_model='account.invoice', active_model="account.invoice", active_ids=self.invoice.ids
active_ids=self.invoice.ids
).create({}).run() ).create({}).run()
def _create_customer_invoice(self): def _create_customer_invoice(self):
invoice_account = self.env['account.account'].search( invoice_account = (
[('user_type_id', '=', self.env.ref( self.env["account.account"]
'account.data_account_type_receivable').id)], .search(
limit=1).id [
invoice = self.env['account.invoice'].create({ (
'partner_id': self.env.ref('base.res_partner_4').id, "user_type_id",
'account_id': invoice_account, "=",
'type': 'out_invoice', self.env.ref("account.data_account_type_receivable").id,
'payment_mode_id': self.inbound_mode.id )
}) ],
self.env['account.invoice.line'].create({ limit=1,
'product_id': self.env.ref('product.product_product_4').id, )
'quantity': 1.0, .id
'price_unit': 100.0, )
'invoice_id': invoice.id, invoice = self.env["account.invoice"].create(
'name': 'product that cost 100', {
'account_id': self.invoice_line_account, "partner_id": self.env.ref("base.res_partner_4").id,
}) "account_id": invoice_account,
"type": "out_invoice",
"payment_mode_id": self.inbound_mode.id,
}
)
self.env["account.invoice.line"].create(
{
"product_id": self.env.ref("product.product_product_4").id,
"quantity": 1.0,
"price_unit": 100.0,
"invoice_id": invoice.id,
"name": "product that cost 100",
"account_id": self.invoice_line_account,
}
)
return invoice return invoice
class TestPaymentOrderInbound(TestPaymentOrderInboundBase): class TestPaymentOrderInbound(TestPaymentOrderInboundBase):
def test_constrains_type(self): def test_constrains_type(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
order = self.env['account.payment.order'].create({ order = self.env["account.payment.order"].create(
'payment_mode_id': self.inbound_mode.id, {
'journal_id': self.journal.id, "payment_mode_id": self.inbound_mode.id,
}) "journal_id": self.journal.id,
order.payment_type = 'outbound' }
)
order.payment_type = "outbound"
def test_constrains_date(self): def test_constrains_date(self):
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
self.inbound_order.date_scheduled = date.today() - timedelta( self.inbound_order.date_scheduled = date.today() - timedelta(days=1)
days=1)
def test_creation(self): def test_creation(self):
payment_order = self.inbound_order payment_order = self.inbound_order
self.assertEqual(len(payment_order.ids), 1) self.assertEqual(len(payment_order.ids), 1)
bank_journal = self.env['account.journal'].search( bank_journal = self.env["account.journal"].search(
[('type', '=', 'bank')], limit=1) [("type", "=", "bank")], limit=1
)
# Set journal to allow cancelling entries # Set journal to allow cancelling entries
bank_journal.update_posted = True bank_journal.update_posted = True
payment_order.write({ payment_order.write(
'journal_id': bank_journal.id, {"journal_id": bank_journal.id,}
}) )
self.assertEqual(len(payment_order.payment_line_ids), 1) self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertEqual(len(payment_order.bank_line_ids), 0) self.assertEqual(len(payment_order.bank_line_ids), 0)
@@ -106,7 +134,7 @@ class TestPaymentOrderInbound(TestPaymentOrderInboundBase):
payment_order.open2generated() payment_order.open2generated()
payment_order.generated2uploaded() payment_order.generated2uploaded()
self.assertEqual(payment_order.state, 'uploaded') self.assertEqual(payment_order.state, "uploaded")
with self.assertRaises(UserError): with self.assertRaises(UserError):
payment_order.unlink() payment_order.unlink()
@@ -115,7 +143,7 @@ class TestPaymentOrderInbound(TestPaymentOrderInboundBase):
with self.assertRaises(UserError): with self.assertRaises(UserError):
bank_line.unlink() bank_line.unlink()
payment_order.action_done_cancel() payment_order.action_done_cancel()
self.assertEqual(payment_order.state, 'cancel') self.assertEqual(payment_order.state, "cancel")
payment_order.cancel2draft() payment_order.cancel2draft()
payment_order.unlink() payment_order.unlink()
self.assertEqual(len(self.payment_order_obj.search(self.domain)), 0) self.assertEqual(len(self.payment_order_obj.search(self.domain)), 0)

View File

@@ -3,96 +3,126 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
class TestPaymentOrderOutbound(TransactionCase): class TestPaymentOrderOutbound(TransactionCase):
def setUp(self): def setUp(self):
super(TestPaymentOrderOutbound, self).setUp() super(TestPaymentOrderOutbound, self).setUp()
self.journal = self.env['account.journal'].search( self.journal = self.env["account.journal"].search(
[('type', '=', 'bank')], limit=1 [("type", "=", "bank")], limit=1
)
self.invoice_line_account = (
self.env["account.account"]
.search(
[
(
"user_type_id",
"=",
self.env.ref("account.data_account_type_expenses").id,
)
],
limit=1,
)
.id
) )
self.invoice_line_account = self.env['account.account'].search(
[('user_type_id', '=', self.env.ref(
'account.data_account_type_expenses').id)],
limit=1).id
self.invoice = self._create_supplier_invoice() self.invoice = self._create_supplier_invoice()
self.invoice_02 = self._create_supplier_invoice() self.invoice_02 = self._create_supplier_invoice()
self.mode = self.env.ref( self.mode = self.env.ref("account_payment_mode.payment_mode_outbound_ct1")
'account_payment_mode.payment_mode_outbound_ct1')
self.creation_mode = self.env.ref( self.creation_mode = self.env.ref(
'account_payment_mode.payment_mode_outbound_dd1') "account_payment_mode.payment_mode_outbound_dd1"
self.bank_journal = self.env['account.journal'].search( )
[('type', '=', 'bank')], limit=1) self.bank_journal = self.env["account.journal"].search(
[("type", "=", "bank")], limit=1
)
# Make sure no other payment orders are in the DB # Make sure no other payment orders are in the DB
self.domain = [ self.domain = [
('state', '=', 'draft'), ("state", "=", "draft"),
('payment_type', '=', 'outbound'), ("payment_type", "=", "outbound"),
] ]
self.env['account.payment.order'].search(self.domain).unlink() self.env["account.payment.order"].search(self.domain).unlink()
def _create_supplier_invoice(self): def _create_supplier_invoice(self):
invoice_account = self.env['account.account'].search( invoice_account = (
[('user_type_id', '=', self.env.ref( self.env["account.account"]
'account.data_account_type_payable').id)], .search(
limit=1).id [
invoice = self.env['account.invoice'].create({ (
'partner_id': self.env.ref('base.res_partner_4').id, "user_type_id",
'account_id': invoice_account, "=",
'type': 'in_invoice', self.env.ref("account.data_account_type_payable").id,
'payment_mode_id': self.env.ref( )
'account_payment_mode.payment_mode_outbound_ct1').id ],
}) limit=1,
)
.id
)
invoice = self.env["account.invoice"].create(
{
"partner_id": self.env.ref("base.res_partner_4").id,
"account_id": invoice_account,
"type": "in_invoice",
"payment_mode_id": self.env.ref(
"account_payment_mode.payment_mode_outbound_ct1"
).id,
}
)
self.env['account.invoice.line'].create({ self.env["account.invoice.line"].create(
'product_id': self.env.ref('product.product_product_4').id, {
'quantity': 1.0, "product_id": self.env.ref("product.product_product_4").id,
'price_unit': 100.0, "quantity": 1.0,
'invoice_id': invoice.id, "price_unit": 100.0,
'name': 'product that cost 100', "invoice_id": invoice.id,
'account_id': self.invoice_line_account, "name": "product that cost 100",
}) "account_id": self.invoice_line_account,
}
)
return invoice return invoice
def test_creation_due_date(self): def test_creation_due_date(self):
self.mode.variable_journal_ids = self.bank_journal self.mode.variable_journal_ids = self.bank_journal
self.mode.group_lines = False self.mode.group_lines = False
self.order_creation('due') self.order_creation("due")
def test_creation_no_date(self): def test_creation_no_date(self):
self.mode.group_lines = True self.mode.group_lines = True
self.creation_mode.write({ self.creation_mode.write(
'group_lines': False, {
'bank_account_link': 'fixed', "group_lines": False,
'default_date_prefered': 'due', "bank_account_link": "fixed",
'fixed_journal_id': self.bank_journal.id, "default_date_prefered": "due",
}) "fixed_journal_id": self.bank_journal.id,
}
)
self.mode.variable_journal_ids = self.bank_journal self.mode.variable_journal_ids = self.bank_journal
self.order_creation(False) self.order_creation(False)
def test_creation_fixed_date(self): def test_creation_fixed_date(self):
self.mode.write({ self.mode.write(
'bank_account_link': 'fixed', {
'default_date_prefered': 'fixed', "bank_account_link": "fixed",
'fixed_journal_id': self.bank_journal.id, "default_date_prefered": "fixed",
}) "fixed_journal_id": self.bank_journal.id,
}
)
self.invoice_02.action_invoice_open() self.invoice_02.action_invoice_open()
self.order_creation('fixed') self.order_creation("fixed")
def order_creation(self, date_prefered): def order_creation(self, date_prefered):
# Open invoice # Open invoice
self.invoice.action_invoice_open() self.invoice.action_invoice_open()
order_vals = { order_vals = {
'payment_type': 'outbound', "payment_type": "outbound",
'payment_mode_id': self.creation_mode.id, "payment_mode_id": self.creation_mode.id,
} }
if date_prefered: if date_prefered:
order_vals['date_prefered'] = date_prefered order_vals["date_prefered"] = date_prefered
order = self.env['account.payment.order'].create(order_vals) order = self.env["account.payment.order"].create(order_vals)
with self.assertRaises(UserError): with self.assertRaises(UserError):
order.draft2open() order.draft2open()
@@ -105,25 +135,20 @@ class TestPaymentOrderOutbound(TransactionCase):
self.assertEqual(order.date_prefered, date_prefered) self.assertEqual(order.date_prefered, date_prefered)
with self.assertRaises(UserError): with self.assertRaises(UserError):
order.draft2open() order.draft2open()
line_create = self.env['account.payment.line.create'].with_context( line_create = (
active_model='account.payment.order', self.env["account.payment.line.create"]
active_id=order.id .with_context(active_model="account.payment.order", active_id=order.id)
).create({ .create({"date_type": "move", "move_date": datetime.now()})
'date_type': 'move', )
'move_date': datetime.now() line_create.payment_mode = "any"
})
line_create.payment_mode = 'any'
line_create.move_line_filters_change() line_create.move_line_filters_change()
line_create.populate() line_create.populate()
line_create.create_payment_lines() line_create.create_payment_lines()
line_created_due = self.env[ line_created_due = (
'account.payment.line.create'].with_context( self.env["account.payment.line.create"]
active_model='account.payment.order', .with_context(active_model="account.payment.order", active_id=order.id)
active_id=order.id .create({"date_type": "due", "due_date": datetime.now()})
).create({ )
'date_type': 'due',
'due_date': datetime.now()
})
line_created_due.populate() line_created_due.populate()
line_created_due.create_payment_lines() line_created_due.create_payment_lines()
self.assertGreater(len(order.payment_line_ids), 0) self.assertGreater(len(order.payment_line_ids), 0)
@@ -131,27 +156,27 @@ class TestPaymentOrderOutbound(TransactionCase):
order.open2generated() order.open2generated()
order.generated2uploaded() order.generated2uploaded()
order.action_done() order.action_done()
self.assertEqual(order.state, 'done') self.assertEqual(order.state, "done")
def test_cancel_payment_order(self): def test_cancel_payment_order(self):
# Open invoice # Open invoice
self.invoice.action_invoice_open() self.invoice.action_invoice_open()
# Add to payment order using the wizard # Add to payment order using the wizard
self.env['account.invoice.payment.line.multi'].with_context( self.env["account.invoice.payment.line.multi"].with_context(
active_model='account.invoice', active_model="account.invoice", active_ids=self.invoice.ids
active_ids=self.invoice.ids
).create({}).run() ).create({}).run()
payment_order = self.env['account.payment.order'].search(self.domain) payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1) self.assertEqual(len(payment_order), 1)
bank_journal = self.env['account.journal'].search( bank_journal = self.env["account.journal"].search(
[('type', '=', 'bank')], limit=1) [("type", "=", "bank")], limit=1
)
# Set journal to allow cancelling entries # Set journal to allow cancelling entries
bank_journal.update_posted = True bank_journal.update_posted = True
payment_order.write({ payment_order.write(
'journal_id': bank_journal.id, {"journal_id": bank_journal.id,}
}) )
self.assertEqual(len(payment_order.payment_line_ids), 1) self.assertEqual(len(payment_order.payment_line_ids), 1)
self.assertEqual(len(payment_order.bank_line_ids), 0) self.assertEqual(len(payment_order.bank_line_ids), 0)
@@ -165,7 +190,7 @@ class TestPaymentOrderOutbound(TransactionCase):
payment_order.open2generated() payment_order.open2generated()
payment_order.generated2uploaded() payment_order.generated2uploaded()
self.assertEqual(payment_order.state, 'uploaded') self.assertEqual(payment_order.state, "uploaded")
with self.assertRaises(UserError): with self.assertRaises(UserError):
payment_order.unlink() payment_order.unlink()
@@ -174,19 +199,20 @@ class TestPaymentOrderOutbound(TransactionCase):
with self.assertRaises(UserError): with self.assertRaises(UserError):
bank_line.unlink() bank_line.unlink()
payment_order.action_done_cancel() payment_order.action_done_cancel()
self.assertEqual(payment_order.state, 'cancel') self.assertEqual(payment_order.state, "cancel")
payment_order.cancel2draft() payment_order.cancel2draft()
payment_order.unlink() payment_order.unlink()
self.assertEqual( self.assertEqual(
len(self.env['account.payment.order'].search(self.domain)), 0, len(self.env["account.payment.order"].search(self.domain)), 0,
) )
def test_constrains(self): def test_constrains(self):
outbound_order = self.env['account.payment.order'].create({ outbound_order = self.env["account.payment.order"].create(
'payment_type': 'outbound', {
'payment_mode_id': self.mode.id, "payment_type": "outbound",
'journal_id': self.journal.id, "payment_mode_id": self.mode.id,
}) "journal_id": self.journal.id,
}
)
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
outbound_order.date_scheduled = date.today() - timedelta( outbound_order.date_scheduled = date.today() - timedelta(days=1)
days=1)

View File

@@ -3,19 +3,24 @@
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record id="invoice_form" model="ir.ui.view"> <record id="invoice_form" model="ir.ui.view">
<field name="name">account_payment_order.invoice_form</field> <field name="name">account_payment_order.invoice_form</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="inherit_id" ref="account_payment_partner.invoice_form" /> <field name="inherit_id" ref="account_payment_partner.invoice_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<button name="%(account.action_account_invoice_payment)d" type="action" position="after"> <button
<button name="create_account_payment_line" type="object" name="%(account.action_account_invoice_payment)d"
type="action"
position="after"
>
<button
name="create_account_payment_line"
type="object"
string="Add to Debit Order" string="Add to Debit Order"
groups="account_payment_order.group_account_payment" groups="account_payment_order.group_account_payment"
attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"/> attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"
/>
<!-- For customer refunds: <!-- For customer refunds:
'Add to Direct Debit Order' will deduct the refund from a customer invoice '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 We could also need a button 'Add to Payment Order' to reimburse
@@ -27,37 +32,46 @@
<field name="payment_order_ok" invisible="1" /> <field name="payment_order_ok" invisible="1" />
</field> </field>
<field name="reference" position="before"> <field name="reference" position="before">
<field name="reference_type" required="1" nolabel="1" attrs="{'readonly':[('state','!=','draft')]}"/> <field
name="reference_type"
required="1"
nolabel="1"
attrs="{'readonly':[('state','!=','draft')]}"
/>
</field> </field>
</field> </field>
</record> </record>
<record id="invoice_supplier_form" model="ir.ui.view"> <record id="invoice_supplier_form" model="ir.ui.view">
<field name="name">account_payment_order.invoice_supplier_form</field> <field name="name">account_payment_order.invoice_supplier_form</field>
<field name="model">account.invoice</field> <field name="model">account.invoice</field>
<field name="inherit_id" ref="account_payment_partner.invoice_supplier_form" /> <field name="inherit_id" ref="account_payment_partner.invoice_supplier_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<button name="%(account.action_account_invoice_payment)d" type="action" position="after"> <button
<button name="create_account_payment_line" type="object" name="%(account.action_account_invoice_payment)d"
type="action"
position="after"
>
<button
name="create_account_payment_line"
type="object"
string="Add to Payment Order" string="Add to Payment Order"
groups="account_payment_order.group_account_payment" groups="account_payment_order.group_account_payment"
attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"/> attrs="{'invisible': ['|', ('payment_order_ok', '=', False), ('state', '!=', 'open')]}"
/>
</button> </button>
<field name="payment_mode_id" position="after"> <field name="payment_mode_id" position="after">
<field name="payment_order_ok" invisible="1" /> <field name="payment_order_ok" invisible="1" />
</field> </field>
</field> </field>
</record> </record>
<act_window
id="account_invoice_create_account_payment_line_action"
<act_window id="account_invoice_create_account_payment_line_action"
multi="True" multi="True"
key2="client_action_multi" key2="client_action_multi"
name="Add to Payment/Debit Order" name="Add to Payment/Debit Order"
res_model="account.invoice.payment.line.multi" res_model="account.invoice.payment.line.multi"
src_model="account.invoice" src_model="account.invoice"
view_mode="form" view_mode="form"
target="new"/> target="new"
/>
</odoo> </odoo>

View File

@@ -4,22 +4,19 @@
@author Alexis de Lattre <alexis.delattre@akretion.com> @author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record id="view_move_line_form" model="ir.ui.view"> <record id="view_move_line_form" model="ir.ui.view">
<field name="name">account_payment_order.move_line_form</field> <field name="name">account_payment_order.move_line_form</field>
<field name="model">account.move.line</field> <field name="model">account.move.line</field>
<field name="inherit_id" ref="account_payment_partner.view_move_line_form" /> <field name="inherit_id" ref="account_payment_partner.view_move_line_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<group name="payments" position="inside"> <group name="payments" position="inside">
<field name="partner_bank_id" <field
domain="[('partner_id', '=', partner_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]"/> name="partner_bank_id"
domain="[('partner_id', '=', partner_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]"
/>
<field name="bank_payment_line_id" /> <field name="bank_payment_line_id" />
</group> </group>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_payment_line_form" model="ir.ui.view"> <record id="account_payment_line_form" model="ir.ui.view">
<field name="name">account.payment.line.form</field> <field name="name">account.payment.line.form</field>
<field name="model">account.payment.line</field> <field name="model">account.payment.line</field>
@@ -9,16 +7,23 @@
<form string="Payment Lines"> <form string="Payment Lines">
<group name="main" col="2"> <group name="main" col="2">
<group name="left"> <group name="left">
<field name="order_id" invisible="not context.get('account_payment_line_main_view')"/> <field
name="order_id"
invisible="not context.get('account_payment_line_main_view')"
/>
<field name="name" /> <field name="name" />
<field name="move_line_id" <field
domain="[('reconciled','=', False), ('account_id.reconcile', '=', True)] "/> <!-- we removed the filter on amount_to_pay, because we want to be able to select refunds --> name="move_line_id"
domain="[('reconciled','=', False), ('account_id.reconcile', '=', True)] "
/>
<!-- we removed the filter on amount_to_pay, because we want to be able to select refunds -->
<field name="date" /> <field name="date" />
<field name="ml_maturity_date" readonly="1" /> <field name="ml_maturity_date" readonly="1" />
<field name="amount_currency" /> <field name="amount_currency" />
<field name="currency_id" /> <field name="currency_id" />
<field name="partner_id" /> <field name="partner_id" />
<field name="partner_bank_id" <field
name="partner_bank_id"
context="{'default_partner_id': partner_id}" context="{'default_partner_id': partner_id}"
domain="[('partner_id', '=', partner_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]" domain="[('partner_id', '=', partner_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]"
attrs="{'required': [('bank_account_required', '=', True)]}" attrs="{'required': [('bank_account_required', '=', True)]}"
@@ -28,7 +33,11 @@
<field name="communication" /> <field name="communication" />
</group> </group>
<group name="right"> <group name="right">
<field name="company_id" widget="selection" groups="base.group_multi_company"/> <field
name="company_id"
widget="selection"
groups="base.group_multi_company"
/>
<field name="amount_company_currency" /> <field name="amount_company_currency" />
<field name="company_currency_id" invisible="1" /> <field name="company_currency_id" invisible="1" />
<field name="bank_line_id" /> <field name="bank_line_id" />
@@ -38,13 +47,15 @@
</form> </form>
</field> </field>
</record> </record>
<record id="account_payment_line_tree" model="ir.ui.view"> <record id="account_payment_line_tree" model="ir.ui.view">
<field name="name">account.payment.line.tree</field> <field name="name">account.payment.line.tree</field>
<field name="model">account.payment.line</field> <field name="model">account.payment.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Payment Lines"> <tree string="Payment Lines">
<field name="order_id" invisible="not context.get('account_payment_line_main_view')"/> <field
name="order_id"
invisible="not context.get('account_payment_line_main_view')"
/>
<field name="partner_id" /> <field name="partner_id" />
<field name="communication" /> <field name="communication" />
<field name="partner_bank_id" /> <field name="partner_bank_id" />
@@ -54,18 +65,19 @@
<field name="amount_currency" string="Amount" /> <field name="amount_currency" string="Amount" />
<field name="currency_id" /> <field name="currency_id" />
<field name="name" /> <field name="name" />
<field name="amount_company_currency" sum="Total in Company Currency" invisible="1"/> <field
name="amount_company_currency"
sum="Total in Company Currency"
invisible="1"
/>
<field name="payment_type" invisible="1" /> <field name="payment_type" invisible="1" />
</tree> </tree>
</field> </field>
</record> </record>
<record id="account_payment_line_action" model="ir.actions.act_window"> <record id="account_payment_line_action" model="ir.actions.act_window">
<field name="name">Payment Lines</field> <field name="name">Payment Lines</field>
<field name="res_model">account.payment.line</field> <field name="res_model">account.payment.line</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="context">{'account_payment_line_main_view': True}</field> <field name="context">{'account_payment_line_main_view': True}</field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,18 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2019 ACSONE SA/NV <!-- Copyright 2019 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo> <odoo>
<record model="ir.ui.view" id="account_payment_method_form_view"> <record model="ir.ui.view" id="account_payment_method_form_view">
<field name="name">account.payment.method.form (in account_payment_order)</field> <field
name="name"
>account.payment.method.form (in account_payment_order)</field>
<field name="model">account.payment.method</field> <field name="model">account.payment.method</field>
<field name="inherit_id" ref="account_payment_mode.account_payment_method_form"/> <field
name="inherit_id"
ref="account_payment_mode.account_payment_method_form"
/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="active" position="before"> <field name="active" position="before">
<field name="payment_order_only" /> <field name="payment_order_only" />
</field> </field>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_payment_mode_form" model="ir.ui.view"> <record id="account_payment_mode_form" model="ir.ui.view">
<field name="name">account_payment_order.account.payment.mode.form</field> <field name="name">account_payment_order.account.payment.mode.form</field>
<field name="model">account.payment.mode</field> <field name="model">account.payment.mode</field>
@@ -11,42 +9,59 @@
<field name="payment_order_ok" /> <field name="payment_order_ok" />
</field> </field>
<group name="main" position="after"> <group name="main" position="after">
<group name="payment_order_options" <group
name="payment_order_options"
string="Options for Payment Orders" string="Options for Payment Orders"
attrs="{'invisible': [('payment_order_ok', '=', False)]}"> attrs="{'invisible': [('payment_order_ok', '=', False)]}"
<field name="no_debit_before_maturity" >
attrs="{'invisible': ['|', ('payment_type', '!=', 'inbound'), ('payment_order_ok', '!=', True)]}"/> <field
name="no_debit_before_maturity"
attrs="{'invisible': ['|', ('payment_type', '!=', 'inbound'), ('payment_order_ok', '!=', True)]}"
/>
<field name="default_date_prefered" /> <field name="default_date_prefered" />
<field name="group_lines" /> <field name="group_lines" />
</group> </group>
<group name="payment_order_create_defaults" <group
name="payment_order_create_defaults"
string="Select Move Lines to Pay - Default Values" string="Select Move Lines to Pay - Default Values"
attrs="{'invisible': [('payment_order_ok', '=', False)]}"> attrs="{'invisible': [('payment_order_ok', '=', False)]}"
>
<field name="default_journal_ids" widget="many2many_tags" /> <field name="default_journal_ids" widget="many2many_tags" />
<field name="default_payment_mode" /> <field name="default_payment_mode" />
<field name="default_target_move" widget="radio" /> <field name="default_target_move" widget="radio" />
<field name="default_invoice" /> <field name="default_invoice" />
<field name="default_date_type" /> <field name="default_date_type" />
</group> </group>
<group name="accounting-config" <group
name="accounting-config"
string="Accounting Entries Options" string="Accounting Entries Options"
attrs="{'invisible': [('payment_order_ok', '=', False)]}"> attrs="{'invisible': [('payment_order_ok', '=', False)]}"
>
<field name="generate_move" /> <field name="generate_move" />
<field name="offsetting_account" widget="radio" <field
attrs="{'required': [('generate_move', '=', True)], 'invisible': [('generate_move', '=', False)]}"/> name="offsetting_account"
<field name="transfer_account_id" widget="radio"
attrs="{'required': [('generate_move', '=', True)], 'invisible': [('generate_move', '=', False)]}"
/>
<field
name="transfer_account_id"
attrs="{'invisible': [('offsetting_account', '!=', 'transfer_account')], 'required': [('offsetting_account', '=', 'transfer_account')]}" attrs="{'invisible': [('offsetting_account', '!=', 'transfer_account')], 'required': [('offsetting_account', '=', 'transfer_account')]}"
context="{'default_reconcile': True, 'default_company_id': company_id}"/> <!-- We can't put a default vue to user_type_id... --> context="{'default_reconcile': True, 'default_company_id': company_id}"
<field name="transfer_journal_id" />
attrs="{'invisible': [('offsetting_account', '!=', 'transfer_account')], 'required': [('offsetting_account', '=', 'transfer_account')]}"/> <!-- We can't put a default vue to user_type_id... -->
<field name="move_option" <field
attrs="{'invisible': [('generate_move', '=', False)], 'required': [('generate_move', '=', True)]}"/> name="transfer_journal_id"
attrs="{'invisible': [('offsetting_account', '!=', 'transfer_account')], 'required': [('offsetting_account', '=', 'transfer_account')]}"
/>
<field
name="move_option"
attrs="{'invisible': [('generate_move', '=', False)], 'required': [('generate_move', '=', True)]}"
/>
<field name="post_move" /> <field name="post_move" />
</group> </group>
</group> </group>
</field> </field>
</record> </record>
<record id="account_payment_mode_tree" model="ir.ui.view"> <record id="account_payment_mode_tree" model="ir.ui.view">
<field name="name">account_payment_order.account.payment.mode.tree</field> <field name="name">account_payment_order.account.payment.mode.tree</field>
<field name="model">account.payment.mode</field> <field name="model">account.payment.mode</field>
@@ -57,19 +72,21 @@
</field> </field>
</field> </field>
</record> </record>
<record id="account_payment_mode_search" model="ir.ui.view"> <record id="account_payment_mode_search" model="ir.ui.view">
<field name="name">account_payment_order.account.payment.mode.search</field> <field name="name">account_payment_order.account.payment.mode.search</field>
<field name="model">account.payment.mode</field> <field name="model">account.payment.mode</field>
<field name="inherit_id" ref="account_payment_mode.account_payment_mode_search"/> <field
name="inherit_id"
ref="account_payment_mode.account_payment_mode_search"
/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<filter name="outbound" position="after"> <filter name="outbound" position="after">
<filter name="payment_order_ok" <filter
name="payment_order_ok"
string="Selectable in Payment Orders" string="Selectable in Payment Orders"
domain="[('payment_order_ok', '=', 1)]"/> domain="[('payment_order_ok', '=', 1)]"
/>
</filter> </filter>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,55 +1,94 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<odoo> <odoo>
<record id="account_payment_order_form" model="ir.ui.view"> <record id="account_payment_order_form" model="ir.ui.view">
<field name="name">account.payment.order.form</field> <field name="name">account.payment.order.form</field>
<field name="model">account.payment.order</field> <field name="model">account.payment.order</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Payment Order"> <form string="Payment Order">
<header> <header>
<button name="%(account_payment_line_create_action)d" type="action" <button
name="%(account_payment_line_create_action)d"
type="action"
string="Create Payment Lines from Journal Items" string="Create Payment Lines from Journal Items"
states="draft" class="oe_highlight" /> states="draft"
<button name="draft2open" type="object" states="draft" class="oe_highlight"
string="Confirm Payments" class="oe_highlight"/> />
<button name="open2generated" type="object" states="open" <button
string="Generate Payment File" class="oe_highlight"/> name="draft2open"
<button name="generated2uploaded" type="object" states="generated" type="object"
string="File Successfully Uploaded" class="oe_highlight"/> states="draft"
<button name="cancel2draft" type="object" states="cancel" string="Confirm Payments"
string="Back to Draft" /> class="oe_highlight"
<button name="action_cancel" type="object" states="draft,open,generated" />
string="Cancel Payments"/> <button
<button name="action_done_cancel" type="object" states="uploaded" name="open2generated"
string="Cancel Payments"/> type="object"
states="open"
string="Generate Payment File"
class="oe_highlight"
/>
<button
name="generated2uploaded"
type="object"
states="generated"
string="File Successfully Uploaded"
class="oe_highlight"
/>
<button
name="cancel2draft"
type="object"
states="cancel"
string="Back to Draft"
/>
<button
name="action_cancel"
type="object"
states="draft,open,generated"
string="Cancel Payments"
/>
<button
name="action_done_cancel"
type="object"
states="uploaded"
string="Cancel Payments"
/>
<field name="state" widget="statusbar" /> <field name="state" widget="statusbar" />
</header> </header>
<sheet> <sheet>
<div class="oe_title"> <div class="oe_title">
<label for="name" class="oe_edit_only" /> <label for="name" class="oe_edit_only" />
<h1><field name="name"/></h1> <h1>
<field name="name" />
</h1>
</div> </div>
<group name="head" col="2"> <group name="head" col="2">
<group name="head-left"> <group name="head-left">
<field name="payment_mode_id" <field
name="payment_mode_id"
domain="[('payment_order_ok', '=', True), ('payment_type', '=', payment_type)]" domain="[('payment_order_ok', '=', True), ('payment_type', '=', payment_type)]"
widget="selection"/> widget="selection"
/>
<field name="allowed_journal_ids" invisible="1" /> <field name="allowed_journal_ids" invisible="1" />
<field name="journal_id" <field
name="journal_id"
widget="selection" widget="selection"
domain="[('id', 'in', allowed_journal_ids)]" domain="[('id', 'in', allowed_journal_ids)]"
/> />
<field name="bank_account_link" invisible="1" /> <field name="bank_account_link" invisible="1" />
<field name="company_partner_bank_id" /> <field name="company_partner_bank_id" />
<field name="company_id" groups="base.group_multi_company"/> <field
name="company_id"
groups="base.group_multi_company"
/>
<field name="payment_type" invisible="0" /> <field name="payment_type" invisible="0" />
<field name="bank_line_count" /> <field name="bank_line_count" />
</group> </group>
<group name="head-right"> <group name="head-right">
<field name="date_prefered" /> <field name="date_prefered" />
<field name="date_scheduled" <field
attrs="{'invisible': [('date_prefered', '!=', 'fixed')], 'required': [('date_prefered', '=', 'fixed')]}"/> name="date_scheduled"
attrs="{'invisible': [('date_prefered', '!=', 'fixed')], 'required': [('date_prefered', '=', 'fixed')]}"
/>
<field name="date_generated" /> <field name="date_generated" />
<field name="generated_user_id" /> <field name="generated_user_id" />
<field name="date_uploaded" /> <field name="date_uploaded" />
@@ -58,12 +97,16 @@
</group> </group>
<notebook> <notebook>
<page name="payment-lines" string="Transactions"> <page name="payment-lines" string="Transactions">
<field name="payment_line_ids" <field
context="{'default_payment_type': payment_type}"/> name="payment_line_ids"
context="{'default_payment_type': payment_type}"
/>
</page> </page>
<page name="bank-payment-lines" string="Bank Payment Lines"> <page name="bank-payment-lines" string="Bank Payment Lines">
<field name="bank_line_ids" <field
context="{'default_payment_type': payment_type}"/> name="bank_line_ids"
context="{'default_payment_type': payment_type}"
/>
</page> </page>
<page name="moves" string="Transfer Journal Entries"> <page name="moves" string="Transfer Journal Entries">
<field name="move_ids" /> <field name="move_ids" />
@@ -77,12 +120,17 @@
</form> </form>
</field> </field>
</record> </record>
<record id="account_payment_order_tree" model="ir.ui.view"> <record id="account_payment_order_tree" model="ir.ui.view">
<field name="name">account.payment.order.tree</field> <field name="name">account.payment.order.tree</field>
<field name="model">account.payment.order</field> <field name="model">account.payment.order</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Payment Orders" decoration-info="state=='draft'" decoration-success="state=='generated'" decoration-danger="state=='open'" decoration-muted="state=='cancel'"> <tree
string="Payment Orders"
decoration-info="state=='draft'"
decoration-success="state=='generated'"
decoration-danger="state=='open'"
decoration-muted="state=='cancel'"
>
<field name="name" /> <field name="name" />
<field name="payment_mode_id" /> <field name="payment_mode_id" />
<field name="journal_id" /> <field name="journal_id" />
@@ -95,29 +143,67 @@
</tree> </tree>
</field> </field>
</record> </record>
<record id="account_payment_order_search" model="ir.ui.view"> <record id="account_payment_order_search" model="ir.ui.view">
<field name="name">account.payment.order.search</field> <field name="name">account.payment.order.search</field>
<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">
<field name="description" filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]" string="Name or Description"/> <field
name="description"
filter_domain="['|', ('name', 'ilike', self), ('description', 'ilike', self)]"
string="Name or Description"
/>
<field name="journal_id" /> <field name="journal_id" />
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/> <filter
<filter name="open" string="Confirmed" domain="[('state', '=', 'open')]"/> name="draft"
<filter name="generated" string="File Generated" domain="[('state', '=', 'generated')]"/> string="Draft"
<filter name="uploaded" string="File Uploaded" domain="[('state', '=', 'uploaded')]"/> 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')]"
/>
<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
<filter name="journal_groupby" string="Bank Journal" context="{'group_by': 'journal_id'}"/> name="payment_mode_groupby"
<filter name="date_generated_groupby" string="File Generation Date" context="{'group_by': 'date_generated'}"/> string="Payment Mode"
<filter name="date_uploaded_groupby" string="File Upload Date" context="{'group_by': 'date_uploaded'}"/> context="{'group_by': 'payment_mode_id'}"
<filter name="state_groupby" string="State" context="{'group_by': 'state'}"/> />
<filter
name="journal_groupby"
string="Bank Journal"
context="{'group_by': 'journal_id'}"
/>
<filter
name="date_generated_groupby"
string="File Generation Date"
context="{'group_by': 'date_generated'}"
/>
<filter
name="date_uploaded_groupby"
string="File Upload Date"
context="{'group_by': 'date_uploaded'}"
/>
<filter
name="state_groupby"
string="State"
context="{'group_by': 'state'}"
/>
</group> </group>
</search> </search>
</field> </field>
</record> </record>
<record id="account_payment_order_graph" model="ir.ui.view"> <record id="account_payment_order_graph" model="ir.ui.view">
<field name="name">account.payment.order.graph</field> <field name="name">account.payment.order.graph</field>
<field name="model">account.payment.order</field> <field name="model">account.payment.order</field>
@@ -128,7 +214,6 @@
</graph> </graph>
</field> </field>
</record> </record>
<record id="account_payment_order_pivot" model="ir.ui.view"> <record id="account_payment_order_pivot" model="ir.ui.view">
<field name="name">account.payment.order.pivot</field> <field name="name">account.payment.order.pivot</field>
<field name="model">account.payment.order</field> <field name="model">account.payment.order</field>
@@ -139,8 +224,6 @@
</pivot> </pivot>
</field> </field>
</record> </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>
@@ -148,7 +231,6 @@
<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>
<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>
@@ -156,15 +238,22 @@
<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>
<menuitem
<menuitem id="payment_root" name="Payments" parent="account.menu_finance" id="payment_root"
sequence="7"/> name="Payments"
parent="account.menu_finance"
<menuitem id="account_payment_order_outbound_menu" action="account_payment_order_outbound_action" sequence="7"
parent="payment_root" sequence="10"/> />
<menuitem
<menuitem id="account_payment_order_inbound_menu" action="account_payment_order_inbound_action" id="account_payment_order_outbound_menu"
parent="payment_root" sequence="20"/> action="account_payment_order_outbound_action"
parent="payment_root"
sequence="10"
/>
<menuitem
id="account_payment_order_inbound_menu"
action="account_payment_order_inbound_action"
parent="payment_root"
sequence="20"
/>
</odoo> </odoo>

View File

@@ -5,18 +5,22 @@
@author: Alexis de Lattre <alexis.delattre@akretion.com> @author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<record id="bank_payment_line_form" model="ir.ui.view"> <record id="bank_payment_line_form" model="ir.ui.view">
<field name="name">bank.payment.line.form</field> <field name="name">bank.payment.line.form</field>
<field name="model">bank.payment.line</field> <field name="model">bank.payment.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Bank Payment Line" create="false"> <form string="Bank Payment Line" create="false">
<group name="main"> <group name="main">
<field name="order_id" <field
invisible="not context.get('bank_payment_line_main_view')"/> name="order_id"
invisible="not context.get('bank_payment_line_main_view')"
/>
<field name="name" /> <field name="name" />
<field name="company_id" groups="base.group_multi_company" <field
invisible="not context.get('bank_payment_line_main_view')"/> name="company_id"
groups="base.group_multi_company"
invisible="not context.get('bank_payment_line_main_view')"
/>
<field name="partner_id" /> <field name="partner_id" />
<field name="date" /> <field name="date" />
<field name="amount_currency" /> <field name="amount_currency" />
@@ -31,14 +35,15 @@
</form> </form>
</field> </field>
</record> </record>
<record id="bank_payment_line_tree" model="ir.ui.view"> <record id="bank_payment_line_tree" model="ir.ui.view">
<field name="name">bank.payment.line.tree</field> <field name="name">bank.payment.line.tree</field>
<field name="model">bank.payment.line</field> <field name="model">bank.payment.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Bank Payment Lines" create="false"> <tree string="Bank Payment Lines" create="false">
<field name="order_id" <field
invisible="not context.get('bank_payment_line_main_view')"/> name="order_id"
invisible="not context.get('bank_payment_line_main_view')"
/>
<field name="partner_id" /> <field name="partner_id" />
<field name="communication" /> <field name="communication" />
<field name="partner_bank_id" /> <field name="partner_bank_id" />
@@ -46,37 +51,56 @@
<field name="amount_currency" sum="Total Amount" /> <field name="amount_currency" sum="Total Amount" />
<field name="currency_id" /> <field name="currency_id" />
<field name="name" /> <field name="name" />
<field name="company_id" groups="base.group_multi_company" <field
invisible="not context.get('bank_payment_line_main_view')"/> name="company_id"
groups="base.group_multi_company"
invisible="not context.get('bank_payment_line_main_view')"
/>
</tree> </tree>
</field> </field>
</record> </record>
<record id="bank_payment_line_search" model="ir.ui.view"> <record id="bank_payment_line_search" model="ir.ui.view">
<field name="name">bank.payment.line.search</field> <field name="name">bank.payment.line.search</field>
<field name="model">bank.payment.line</field> <field name="model">bank.payment.line</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Search Bank Payment Lines"> <search string="Search Bank Payment Lines">
<field name="partner_id" /> <field name="partner_id" />
<filter name="inbound" string="Inbound" domain="[('payment_type', '=', 'inbound')]" /> <filter
<filter name="outbound" string="Outbound" domain="[('payment_type', '=', 'outbound')]" /> name="inbound"
string="Inbound"
domain="[('payment_type', '=', 'inbound')]"
/>
<filter
name="outbound"
string="Outbound"
domain="[('payment_type', '=', 'outbound')]"
/>
<group string="Group By" name="groupby"> <group string="Group By" name="groupby">
<filter name="state_groupby" string="State" context="{'group_by': 'state'}"/> <filter
<filter name="partner_groupby" string="Partner" context="{'group_by': 'partner_id'}"/> name="state_groupby"
string="State"
context="{'group_by': 'state'}"
/>
<filter
name="partner_groupby"
string="Partner"
context="{'group_by': 'partner_id'}"
/>
</group> </group>
</search> </search>
</field> </field>
</record> </record>
<record id="bank_payment_line_action" model="ir.actions.act_window"> <record id="bank_payment_line_action" model="ir.actions.act_window">
<field name="name">Bank Payment Lines</field> <field name="name">Bank Payment Lines</field>
<field name="res_model">bank.payment.line</field> <field name="res_model">bank.payment.line</field>
<field name="view_mode">tree,form</field> <field name="view_mode">tree,form</field>
<field name="context">{'bank_payment_line_main_view': True}</field> <field name="context">{'bank_payment_line_main_view': True}</field>
</record> </record>
<menuitem
<menuitem id="bank_payment_line_menu" action="bank_payment_line_action" id="bank_payment_line_menu"
parent="payment_root" sequence="50" groups="group_account_payment"/> action="bank_payment_line_action"
parent="payment_root"
sequence="50"
groups="group_account_payment"
/>
</odoo> </odoo>

View File

@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<!-- © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) --> <!-- © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) -->
<odoo> <odoo>
<record id="view_attachment_simplified_form" model="ir.ui.view"> <record id="view_attachment_simplified_form" model="ir.ui.view">
<field name="name">ir.attachment.simplified.form</field> <field name="name">ir.attachment.simplified.form</field>
<field name="model">ir.attachment</field> <field name="model">ir.attachment</field>
@@ -14,8 +12,11 @@
<field name="name" /> <field name="name" />
</h1> </h1>
<group name="main"> <group name="main">
<field name="datas" filename="datas_fname" <field
string="Generated File"/> name="datas"
filename="datas_fname"
string="Generated File"
/>
<field name="datas_fname" invisible="1" /> <field name="datas_fname" invisible="1" />
<label for="create_uid" string="Created by" /> <label for="create_uid" string="Created by" />
<div name="creation_div"> <div name="creation_div">
@@ -27,6 +28,4 @@
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,4 +1,2 @@
# -*- coding: utf-8 -*-
from . import account_payment_line_create from . import account_payment_line_create
from . import account_invoice_payment_line_multi from . import account_invoice_payment_line_multi

View File

@@ -1,20 +1,19 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (<https://www.akretion.com>) # © 2016 Akretion (<https://www.akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, api from odoo import api, models
class AccountInvoicePaymentLineMulti(models.TransientModel): class AccountInvoicePaymentLineMulti(models.TransientModel):
_name = 'account.invoice.payment.line.multi' _name = "account.invoice.payment.line.multi"
_description = 'Create payment lines from invoice tree view' _description = "Create payment lines from invoice tree view"
@api.multi @api.multi
def run(self): def run(self):
self.ensure_one() self.ensure_one()
assert self._context['active_model'] == 'account.invoice',\ assert (
'Active model should be account.invoice' self._context["active_model"] == "account.invoice"
invoices = self.env['account.invoice'].browse( ), "Active model should be account.invoice"
self._context['active_ids']) invoices = self.env["account.invoice"].browse(self._context["active_ids"])
action = invoices.create_account_payment_line() action = invoices.create_account_payment_line()
return action return action

View File

@@ -3,9 +3,7 @@
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record id="account_invoice_payment_line_multi_form" model="ir.ui.view"> <record id="account_invoice_payment_line_multi_form" model="ir.ui.view">
<field name="name">account_invoice_payment_line_multi.form</field> <field name="name">account_invoice_payment_line_multi.form</field>
<field name="model">account.invoice.payment.line.multi</field> <field name="model">account.invoice.payment.line.multi</field>
@@ -13,15 +11,21 @@
<form string="Create Payment Lines"> <form string="Create Payment Lines">
<p>This wizard will create payment lines for the selected invoices:</p> <p>This wizard will create payment lines for the selected invoices:</p>
<ul> <ul>
<li>if there are existing draft payment orders for the payment modes of the invoices, the payment lines will be added to those payment orders</li> <li
<li>otherwise, new payment orders will be created (one per payment mode).</li> >if there are existing draft payment orders for the payment modes of the invoices, the payment lines will be added to those payment orders</li>
<li
>otherwise, new payment orders will be created (one per payment mode).</li>
</ul> </ul>
<footer> <footer>
<button type="object" name="run" string="Create" class="oe_highlight"/> <button
type="object"
name="run"
string="Create"
class="oe_highlight"
/>
<button special="cancel" string="Cancel" class="oe_link" /> <button special="cancel" string="Cancel" class="oe_link" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,98 +1,100 @@
# -*- coding: utf-8 -*-
# © 2009 EduSense BV (<http://www.edusense.nl>) # © 2009 EduSense BV (<http://www.edusense.nl>)
# © 2011-2013 Therp BV (<https://therp.nl>) # © 2011-2013 Therp BV (<https://therp.nl>)
# © 2014-2015 ACSONE SA/NV (<https://acsone.eu>) # © 2014-2015 ACSONE SA/NV (<https://acsone.eu>)
# © 2015-2016 Akretion (<https://www.akretion.com>) # © 2015-2016 Akretion (<https://www.akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api, _ from odoo import _, api, fields, models
class AccountPaymentLineCreate(models.TransientModel): class AccountPaymentLineCreate(models.TransientModel):
_name = 'account.payment.line.create' _name = "account.payment.line.create"
_description = 'Wizard to create payment lines' _description = "Wizard to create payment lines"
order_id = fields.Many2one( order_id = fields.Many2one("account.payment.order", string="Payment Order")
'account.payment.order', string='Payment Order') journal_ids = fields.Many2many("account.journal", string="Journals Filter")
journal_ids = fields.Many2many(
'account.journal', string='Journals Filter')
partner_ids = fields.Many2many( partner_ids = fields.Many2many(
'res.partner', string='Partners', domain=[('parent_id', '=', False)]) "res.partner", string="Partners", domain=[("parent_id", "=", False)]
target_move = fields.Selection([ )
('posted', 'All Posted Entries'), target_move = fields.Selection(
('all', 'All Entries'), [("posted", "All Posted Entries"), ("all", "All Entries"),],
], string='Target Moves') string="Target Moves",
allow_blocked = fields.Boolean( )
string='Allow Litigation Move Lines') allow_blocked = fields.Boolean(string="Allow Litigation Move Lines")
invoice = fields.Boolean( invoice = fields.Boolean(string="Linked to an Invoice or Refund")
string='Linked to an Invoice or Refund') date_type = fields.Selection(
date_type = fields.Selection([ [("due", "Due Date"), ("move", "Move Date"),],
('due', 'Due Date'), string="Type of Date Filter",
('move', 'Move Date'), required=True,
], string="Type of Date Filter", required=True) )
due_date = fields.Date(string="Due Date") due_date = fields.Date(string="Due Date")
move_date = fields.Date( move_date = fields.Date(string="Move Date", default=fields.Date.context_today)
string='Move Date', default=fields.Date.context_today) payment_mode = fields.Selection(
payment_mode = fields.Selection([ [("same", "Same"), ("same_or_null", "Same or Empty"), ("any", "Any"),],
('same', 'Same'), string="Payment Mode",
('same_or_null', 'Same or Empty'), )
('any', 'Any'), move_line_ids = fields.Many2many("account.move.line", string="Move Lines")
], string='Payment Mode')
move_line_ids = fields.Many2many(
'account.move.line', string='Move Lines')
@api.model @api.model
def default_get(self, field_list): def default_get(self, field_list):
res = super(AccountPaymentLineCreate, self).default_get(field_list) res = super(AccountPaymentLineCreate, self).default_get(field_list)
context = self.env.context context = self.env.context
assert context.get('active_model') == 'account.payment.order',\ assert (
'active_model should be payment.order' context.get("active_model") == "account.payment.order"
assert context.get('active_id'), 'Missing active_id in context !' ), "active_model should be payment.order"
order = self.env['account.payment.order'].browse(context['active_id']) assert context.get("active_id"), "Missing active_id in context !"
order = self.env["account.payment.order"].browse(context["active_id"])
mode = order.payment_mode_id mode = order.payment_mode_id
res.update({ res.update(
'journal_ids': mode.default_journal_ids.ids or False, {
'target_move': mode.default_target_move, "journal_ids": mode.default_journal_ids.ids or False,
'invoice': mode.default_invoice, "target_move": mode.default_target_move,
'date_type': mode.default_date_type, "invoice": mode.default_invoice,
'payment_mode': mode.default_payment_mode, "date_type": mode.default_date_type,
'order_id': order.id, "payment_mode": mode.default_payment_mode,
}) "order_id": order.id,
}
)
return res return res
@api.multi @api.multi
def _prepare_move_line_domain(self): def _prepare_move_line_domain(self):
self.ensure_one() self.ensure_one()
domain = [('reconciled', '=', False), domain = [
('company_id', '=', self.order_id.company_id.id)] ("reconciled", "=", False),
("company_id", "=", self.order_id.company_id.id),
]
if self.journal_ids: if self.journal_ids:
domain += [('journal_id', 'in', self.journal_ids.ids)] domain += [("journal_id", "in", self.journal_ids.ids)]
if self.partner_ids: if self.partner_ids:
domain += [('partner_id', 'in', self.partner_ids.ids)] domain += [("partner_id", "in", self.partner_ids.ids)]
if self.target_move == 'posted': if self.target_move == "posted":
domain += [('move_id.state', '=', 'posted')] domain += [("move_id.state", "=", "posted")]
if not self.allow_blocked: if not self.allow_blocked:
domain += [('blocked', '!=', True)] domain += [("blocked", "!=", True)]
if self.date_type == 'due': if self.date_type == "due":
domain += [ domain += [
'|', "|",
('date_maturity', '<=', self.due_date), ("date_maturity", "<=", self.due_date),
('date_maturity', '=', False)] ("date_maturity", "=", False),
elif self.date_type == 'move': ]
domain.append(('date', '<=', self.move_date)) elif self.date_type == "move":
domain.append(("date", "<=", self.move_date))
if self.invoice: if self.invoice:
domain.append(('invoice_id', '!=', False)) domain.append(("invoice_id", "!=", False))
if self.payment_mode: if self.payment_mode:
if self.payment_mode == 'same': if self.payment_mode == "same":
domain.append( domain.append(
('payment_mode_id', '=', self.order_id.payment_mode_id.id)) ("payment_mode_id", "=", self.order_id.payment_mode_id.id)
elif self.payment_mode == 'same_or_null': )
elif self.payment_mode == "same_or_null":
domain += [ domain += [
'|', "|",
('payment_mode_id', '=', False), ("payment_mode_id", "=", False),
('payment_mode_id', '=', self.order_id.payment_mode_id.id)] ("payment_mode_id", "=", self.order_id.payment_mode_id.id),
]
if self.order_id.payment_type == 'outbound': if self.order_id.payment_type == "outbound":
# For payables, propose all unreconciled credit lines, # For payables, propose all unreconciled credit lines,
# including partially reconciled ones. # including partially reconciled ones.
# If they are partially reconciled with a supplier refund, # If they are partially reconciled with a supplier refund,
@@ -104,50 +106,62 @@ class AccountPaymentLineCreate(models.TransientModel):
# as they are deducted from a customer invoice, and # as they are deducted from a customer invoice, and
# will not be refunded with a payment. # will not be refunded with a payment.
domain += [ domain += [
('credit', '>', 0), ("credit", ">", 0),
('account_id.internal_type', 'in', ['payable', 'receivable'])] ("account_id.internal_type", "in", ["payable", "receivable"]),
elif self.order_id.payment_type == 'inbound': ]
elif self.order_id.payment_type == "inbound":
domain += [ domain += [
('debit', '>', 0), ("debit", ">", 0),
('account_id.internal_type', 'in', ['receivable', 'payable'])] ("account_id.internal_type", "in", ["receivable", "payable"]),
]
# Exclude lines that are already in a non-cancelled # Exclude lines that are already in a non-cancelled
# and non-uploaded payment order; lines that are in a # and non-uploaded payment order; lines that are in a
# uploaded payment order are proposed if they are not reconciled, # uploaded payment order are proposed if they are not reconciled,
paylines = self.env['account.payment.line'].search([ paylines = self.env["account.payment.line"].search(
('state', 'in', ('draft', 'open', 'generated')), [
('move_line_id', '!=', False)]) ("state", "in", ("draft", "open", "generated")),
("move_line_id", "!=", False),
]
)
if paylines: if paylines:
move_lines_ids = [payline.move_line_id.id for payline in paylines] move_lines_ids = [payline.move_line_id.id for payline in paylines]
domain += [('id', 'not in', move_lines_ids)] domain += [("id", "not in", move_lines_ids)]
return domain return domain
@api.multi @api.multi
def populate(self): def populate(self):
domain = self._prepare_move_line_domain() domain = self._prepare_move_line_domain()
lines = self.env['account.move.line'].search(domain) lines = self.env["account.move.line"].search(domain)
self.move_line_ids = lines self.move_line_ids = lines
action = { action = {
'name': _('Select Move Lines to Create Transactions'), "name": _("Select Move Lines to Create Transactions"),
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'res_model': 'account.payment.line.create', "res_model": "account.payment.line.create",
'view_mode': 'form', "view_mode": "form",
'target': 'new', "target": "new",
'res_id': self.id, "res_id": self.id,
'context': self._context, "context": self._context,
} }
return action return action
@api.onchange( @api.onchange(
'date_type', 'move_date', 'due_date', 'journal_ids', 'invoice', "date_type",
'target_move', 'allow_blocked', 'payment_mode', 'partner_ids') "move_date",
"due_date",
"journal_ids",
"invoice",
"target_move",
"allow_blocked",
"payment_mode",
"partner_ids",
)
def move_line_filters_change(self): def move_line_filters_change(self):
domain = self._prepare_move_line_domain() domain = self._prepare_move_line_domain()
res = {'domain': {'move_line_ids': domain}} res = {"domain": {"move_line_ids": domain}}
return res 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

View File

@@ -5,8 +5,6 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record id="account_payment_line_create_form" model="ir.ui.view"> <record id="account_payment_line_create_form" model="ir.ui.view">
<field name="name">account_payment_line_create.form</field> <field name="name">account_payment_line_create.form</field>
<field name="model">account.payment.line.create</field> <field name="model">account.payment.line.create</field>
@@ -15,22 +13,39 @@
<group name="main"> <group name="main">
<field name="order_id" invisible="1" /> <field name="order_id" invisible="1" />
<field name="date_type" /> <field name="date_type" />
<field name="move_date" attrs="{'required': [('date_type', '=', 'move')], 'invisible': [('date_type', '!=', 'move')]}"/> <field
<field name="due_date" attrs="{'required': [('date_type', '=', 'due')], 'invisible': [('date_type', '!=', 'due')]}"/> name="move_date"
<field name="journal_ids" attrs="{'required': [('date_type', '=', 'move')], 'invisible': [('date_type', '!=', 'move')]}"
/>
<field
name="due_date"
attrs="{'required': [('date_type', '=', 'due')], 'invisible': [('date_type', '!=', 'due')]}"
/>
<field
name="journal_ids"
widget="many2many_tags" widget="many2many_tags"
placeholder="Keep empty for using all journals"/> placeholder="Keep empty for using all journals"
<field name="partner_ids" />
<field
name="partner_ids"
widget="many2many_tags" widget="many2many_tags"
placeholder="Keep empty to use all partners"/> placeholder="Keep empty to use all partners"
/>
<field name="payment_mode" /> <field name="payment_mode" />
<field name="target_move" widget="radio" /> <field name="target_move" widget="radio" />
<field name="invoice" /> <field name="invoice" />
<field name="allow_blocked" /> <field name="allow_blocked" />
<label for="populate" 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"/> <label
for="populate"
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" /> <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">
<tree> <tree>
<field name="date" /> <field name="date" />
@@ -49,20 +64,21 @@
</field> </field>
</group> </group>
<footer> <footer>
<button name="create_payment_lines" type="object" <button
string="Create Transactions" class="oe_highlight"/> name="create_payment_lines"
type="object"
string="Create Transactions"
class="oe_highlight"
/>
<button string="Cancel" special="cancel" class="oe_link" /> <button string="Cancel" special="cancel" class="oe_link" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
<record id="account_payment_line_create_action" model="ir.actions.act_window"> <record id="account_payment_line_create_action" model="ir.actions.act_window">
<field name="name">Create Transactions from Move Lines</field> <field name="name">Create Transactions from Move Lines</field>
<field name="res_model">account.payment.line.create</field> <field name="res_model">account.payment.line.create</field>
<field name="view_mode">form</field> <field name="view_mode">form</field>
<field name="target">new</field> <field name="target">new</field>
</record> </record>
</odoo> </odoo>