mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
On v15+, a new model account.payment.method.line is introduced for fine-graining the outstanding account, being `payment_method_id` a related field referred to this new model, so we need to change the previous approach to select the proper method line only if found. If not found, it will be auto-selected by standard code. TT43278
238 lines
9.1 KiB
Python
238 lines
9.1 KiB
Python
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
|
|
from odoo import _, api, fields, models
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class AccountPaymentLine(models.Model):
|
|
_name = "account.payment.line"
|
|
_description = "Payment Lines"
|
|
_check_company_auto = True
|
|
|
|
name = fields.Char(string="Payment Reference", readonly=True, copy=False)
|
|
order_id = fields.Many2one(
|
|
comodel_name="account.payment.order",
|
|
string="Payment Order",
|
|
ondelete="cascade",
|
|
index=True,
|
|
check_company=True,
|
|
)
|
|
company_id = fields.Many2one(
|
|
related="order_id.company_id", store=True, readonly=True
|
|
)
|
|
company_currency_id = fields.Many2one(
|
|
related="order_id.company_currency_id", store=True, readonly=True
|
|
)
|
|
payment_type = fields.Selection(
|
|
related="order_id.payment_type", store=True, readonly=True
|
|
)
|
|
bank_account_required = fields.Boolean(
|
|
related="order_id.payment_method_id.bank_account_required", readonly=True
|
|
)
|
|
state = fields.Selection(
|
|
related="order_id.state", string="State", readonly=True, store=True
|
|
)
|
|
move_line_id = fields.Many2one(
|
|
comodel_name="account.move.line",
|
|
string="Journal Item",
|
|
ondelete="restrict",
|
|
check_company=True,
|
|
)
|
|
ml_maturity_date = fields.Date(related="move_line_id.date_maturity", readonly=True)
|
|
currency_id = fields.Many2one(
|
|
comodel_name="res.currency",
|
|
string="Currency of the Payment Transaction",
|
|
required=True,
|
|
default=lambda self: self.env.user.company_id.currency_id,
|
|
)
|
|
amount_currency = fields.Monetary(string="Amount", currency_field="currency_id")
|
|
amount_company_currency = fields.Monetary(
|
|
compute="_compute_amount_company_currency",
|
|
string="Amount in Company Currency",
|
|
currency_field="company_currency_id",
|
|
)
|
|
partner_id = fields.Many2one(
|
|
comodel_name="res.partner",
|
|
string="Partner",
|
|
required=True,
|
|
domain=[("parent_id", "=", False)],
|
|
check_company=True,
|
|
)
|
|
partner_bank_id = fields.Many2one(
|
|
comodel_name="res.partner.bank",
|
|
string="Partner Bank Account",
|
|
required=False,
|
|
ondelete="restrict",
|
|
check_company=True,
|
|
)
|
|
date = fields.Date(string="Payment Date")
|
|
# communication field is required=False because we don't want to block
|
|
# the creation of lines from move/invoices when communication is empty
|
|
# This field is required in the form view and there is an error message
|
|
# when going from draft to confirm if the field is empty
|
|
communication = fields.Char(
|
|
required=False, help="Label of the payment that will be seen by the destinee"
|
|
)
|
|
communication_type = fields.Selection(
|
|
selection=[("normal", "Free")], required=True, default="normal"
|
|
)
|
|
payment_ids = fields.Many2many(
|
|
comodel_name="account.payment",
|
|
string="Payment transaction",
|
|
readonly=True,
|
|
)
|
|
|
|
_sql_constraints = [
|
|
(
|
|
"name_company_unique",
|
|
"unique(name, company_id)",
|
|
"A payment line already exists with this reference in the same company!",
|
|
)
|
|
]
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get("name", "New") == "New":
|
|
vals["name"] = (
|
|
self.env["ir.sequence"].next_by_code("account.payment.line")
|
|
or "New"
|
|
)
|
|
return super().create(vals_list)
|
|
|
|
@api.depends("amount_currency", "currency_id", "company_currency_id", "date")
|
|
def _compute_amount_company_currency(self):
|
|
for line in self:
|
|
if line.currency_id and line.company_currency_id:
|
|
line.amount_company_currency = line.currency_id._convert(
|
|
line.amount_currency,
|
|
line.company_currency_id,
|
|
line.company_id,
|
|
line.date or fields.Date.today(),
|
|
)
|
|
else:
|
|
line.amount_company_currency = 0
|
|
|
|
@api.model
|
|
def _get_payment_line_grouping_fields(self):
|
|
"""This list of fields is used o compute the grouping hashcode."""
|
|
return [
|
|
"currency_id",
|
|
"partner_id",
|
|
"partner_bank_id",
|
|
"date",
|
|
"communication_type",
|
|
]
|
|
|
|
def payment_line_hashcode(self):
|
|
self.ensure_one()
|
|
values = []
|
|
for field in self._get_payment_line_grouping_fields():
|
|
values.append(str(self[field]))
|
|
# Don't group the payment lines that are attached to the same supplier
|
|
# but to move lines with different accounts (very unlikely),
|
|
# for easier generation/comprehension of the transfer move
|
|
values.append(str(self.move_line_id.account_id or False))
|
|
# Don't group the payment lines that use a structured communication
|
|
# otherwise it would break the structured communication system !
|
|
if self.communication_type != "normal":
|
|
values.append(str(self.id))
|
|
return "-".join(values)
|
|
|
|
@api.onchange("partner_id")
|
|
def partner_id_change(self):
|
|
partner_bank = False
|
|
if self.partner_id.bank_ids:
|
|
partner_bank = self.partner_id.bank_ids[0]
|
|
self.partner_bank_id = partner_bank
|
|
|
|
@api.onchange("move_line_id")
|
|
def move_line_id_change(self):
|
|
if self.move_line_id:
|
|
vals = self.move_line_id._prepare_payment_line_vals(self.order_id)
|
|
vals.pop("order_id")
|
|
for field, value in vals.items():
|
|
self[field] = value
|
|
else:
|
|
self.partner_id = False
|
|
self.partner_bank_id = False
|
|
self.amount_currency = 0.0
|
|
self.currency_id = self.env.user.company_id.currency_id
|
|
self.communication = False
|
|
|
|
def invoice_reference_type2communication_type(self):
|
|
"""This method is designed to be inherited by
|
|
localization modules"""
|
|
# key = value of 'reference_type' field on account_invoice
|
|
# value = value of 'communication_type' field on account_payment_line
|
|
res = {"none": "normal", "structured": "structured"}
|
|
return res
|
|
|
|
def draft2open_payment_line_check(self):
|
|
self.ensure_one()
|
|
if self.bank_account_required and not self.partner_bank_id:
|
|
raise UserError(
|
|
_("Missing Partner Bank Account on payment line %s") % self.name
|
|
)
|
|
if not self.communication:
|
|
raise UserError(_("Communication is empty on payment line %s.") % self.name)
|
|
|
|
def _prepare_account_payment_vals(self):
|
|
"""Prepare the dictionary to create an account payment record from a set of
|
|
payment lines.
|
|
"""
|
|
journal = self.order_id.journal_id
|
|
vals = {
|
|
"payment_type": self.order_id.payment_type,
|
|
"partner_id": self.partner_id.id,
|
|
"destination_account_id": self.move_line_id.account_id.id,
|
|
"company_id": self.order_id.company_id.id,
|
|
"amount": sum(self.mapped("amount_currency")),
|
|
"date": self[:1].date,
|
|
"currency_id": self.currency_id.id,
|
|
"ref": self.order_id.name,
|
|
# Put the name as the wildcard for forcing a unique name. If not, Odoo gets
|
|
# the sequence for all the payment at the same time
|
|
"name": "/",
|
|
"payment_reference": "-".join([line.communication for line in self]),
|
|
"journal_id": journal.id,
|
|
"partner_bank_id": self.partner_bank_id.id,
|
|
"payment_order_id": self.order_id.id,
|
|
"payment_line_ids": [(6, 0, self.ids)],
|
|
}
|
|
# Determine payment method line according payment method and journal
|
|
line = self.env["account.payment.method.line"].search(
|
|
[
|
|
(
|
|
"payment_method_id",
|
|
"=",
|
|
self.order_id.payment_mode_id.payment_method_id.id,
|
|
),
|
|
("journal_id", "=", journal.id),
|
|
],
|
|
limit=1,
|
|
)
|
|
if line:
|
|
vals["payment_method_line_id"] = line.id
|
|
# Determine partner_type
|
|
move_type = self[:1].move_line_id.move_id.move_type
|
|
if move_type in {"out_invoice", "out_refund"}:
|
|
vals["partner_type"] = "customer"
|
|
elif move_type in {"in_invoice", "in_refund"}:
|
|
vals["partner_type"] = "supplier"
|
|
else:
|
|
p_type = "customer" if vals["payment_type"] == "inbound" else "supplier"
|
|
vals["partner_type"] = p_type
|
|
# Fill destination account if manual payment line with no linked journal item
|
|
if not vals["destination_account_id"]:
|
|
if vals["partner_type"] == "customer":
|
|
vals[
|
|
"destination_account_id"
|
|
] = self.partner_id.property_account_receivable_id.id
|
|
else:
|
|
vals[
|
|
"destination_account_id"
|
|
] = self.partner_id.property_account_payable_id.id
|
|
return vals
|