2021-03-12 16:21:19 +00:00
|
|
|
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
|
|
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
|
|
|
|
|
|
from flectra import _, api, fields, models
|
|
|
|
from flectra.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")
|
2022-06-29 18:32:58 +00:00
|
|
|
# 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
|
2021-03-12 16:21:19 +00:00
|
|
|
communication = fields.Char(
|
2021-11-07 03:11:01 +00:00
|
|
|
required=False, help="Label of the payment that will be seen by the destinee"
|
2021-03-12 16:21:19 +00:00
|
|
|
)
|
|
|
|
communication_type = fields.Selection(
|
|
|
|
selection=[("normal", "Free")], required=True, default="normal"
|
|
|
|
)
|
2023-05-19 08:19:51 +00:00
|
|
|
payment_ids = fields.Many2many(
|
|
|
|
comodel_name="account.payment",
|
|
|
|
string="Payment transaction",
|
2021-03-12 16:21:19 +00:00
|
|
|
readonly=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
_sql_constraints = [
|
|
|
|
(
|
|
|
|
"name_company_unique",
|
|
|
|
"unique(name, company_id)",
|
2023-05-19 08:19:51 +00:00
|
|
|
"A payment line already exists with this reference in the same company!",
|
2021-03-12 16:21:19 +00:00
|
|
|
)
|
|
|
|
]
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def create(self, vals):
|
|
|
|
if vals.get("name", "New") == "New":
|
|
|
|
vals["name"] = (
|
|
|
|
self.env["ir.sequence"].next_by_code("account.payment.line") or "New"
|
|
|
|
)
|
|
|
|
return super(AccountPaymentLine, self).create(vals)
|
|
|
|
|
|
|
|
@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(),
|
|
|
|
)
|
2021-04-28 14:53:45 +00:00
|
|
|
else:
|
|
|
|
line.amount_company_currency = 0
|
2021-03-12 16:21:19 +00:00
|
|
|
|
2023-05-19 08:19:51 +00:00
|
|
|
@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",
|
|
|
|
]
|
|
|
|
|
2021-03-12 16:21:19 +00:00
|
|
|
def payment_line_hashcode(self):
|
|
|
|
self.ensure_one()
|
|
|
|
values = []
|
2023-05-19 08:19:51 +00:00
|
|
|
for field in self._get_payment_line_grouping_fields():
|
2021-03-12 16:21:19 +00:00
|
|
|
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))
|
2023-05-19 08:19:51 +00:00
|
|
|
return "-".join(values)
|
2021-03-12 16:21:19 +00:00
|
|
|
|
|
|
|
@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
|
|
|
|
)
|
2021-11-07 03:11:01 +00:00
|
|
|
if not self.communication:
|
|
|
|
raise UserError(_("Communication is empty on payment line %s.") % self.name)
|
2023-05-19 08:19:51 +00:00
|
|
|
|
|
|
|
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,
|
|
|
|
"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_method_id": self.order_id.payment_mode_id.payment_method_id.id,
|
|
|
|
"payment_line_ids": [(6, 0, self.ids)],
|
|
|
|
}
|
|
|
|
# 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
|