[IMP]pms: Improvemente relation amount pending folio and payments with invoices linked

This commit is contained in:
Darío Lodeiros
2022-04-15 18:55:27 +02:00
parent ed9bdf4da2
commit e111302f9f
5 changed files with 156 additions and 72 deletions

View File

@@ -9,7 +9,6 @@ class AccountPayment(models.Model):
folio_ids = fields.Many2many(
string="Folios",
comodel_name="pms.folio",
ondelete="cascade",
compute="_compute_folio_ids",
store=True,
readonly=False,
@@ -68,15 +67,15 @@ class AccountPayment(models.Model):
"line_ids.folio_line_ids.folio_id.id"
)
folio_ids = list(set(inv_folio_ids + bill_folio_ids))
if folio_ids:
# If the payment was already assigned to a specific page of the invoice,
# we do not want it to be associated with others
if folio_ids and len(set(rec.folio_ids.ids) & set(folio_ids)) == 0:
folios = self.env["pms.folio"].browse(folio_ids)
# If the payment is in a new invoice, we want it to be associated with all
# folios of the invoice that don't are paid yet
folio_ids = folios.filtered(lambda f: f.pending_amount > 0).ids
rec.write({"folio_ids": [(6, 0, folio_ids)]})
elif (
not rec.reconciled_invoice_ids
and not rec.reconciled_bill_ids
and rec.folio_ids
):
rec.folio_ids = rec.folio_ids
else:
elif not rec.folio_ids:
rec.folio_ids = False
def _prepare_move_line_default_vals(self, write_off_line_vals=None):

View File

@@ -265,6 +265,8 @@ class PmsFolio(models.Model):
("not_paid", "Not Paid"),
("paid", "Paid"),
("partial", "Partially Paid"),
("overpayment", "Overpayment"),
("nothing_to_pay", "Nothing to pay"),
],
compute="_compute_amount",
tracking=True,
@@ -400,6 +402,13 @@ class PmsFolio(models.Model):
compute="_compute_amount",
tracking=True,
)
payment_multi = fields.Boolean(
string="Folio paid with payments assigned to other folios",
help="Technical field for manage payments with multiple folios assigned",
readonly=True,
store=True,
compute="_compute_amount",
)
amount_untaxed = fields.Monetary(
string="Untaxed Amount",
help="The price without taxes on a folio",
@@ -1103,72 +1112,126 @@ class PmsFolio(models.Model):
"payment_ids.move_id.line_ids.credit",
"payment_ids.move_id.line_ids.currency_id",
"payment_ids.move_id.line_ids.amount_currency",
"move_ids.amount_residual",
)
def _compute_amount(self):
for record in self:
if record.reservation_type in ("staff", "out"):
record.amount_total = 0
vals = {
"payment_state": False,
"payment_state": "nothing_to_pay",
"pending_amount": 0,
"invoices_paid": 0,
}
record.update(vals)
else:
mls = record.payment_ids.mapped("move_id.line_ids").filtered(
# first attempt compute amount search payments refs with only one folio
mls_one_folio = (
record.payment_ids.filtered(lambda pay: len(pay.folio_ids) == 1)
.mapped("move_id.line_ids")
.filtered(
lambda x: x.account_id.internal_type == "receivable"
and x.parent_state == "posted"
)
)
advance_amount = record._get_advance_amount(mls_one_folio)
# Compute 'payment_state'.
vals = record._get_amount_vals(mls_one_folio, advance_amount)
# If folio its not paid, search payments refs with more than one folio
folio_ids = record.payment_ids.mapped("folio_ids.id")
if vals["pending_amount"] > 0 and len(folio_ids) > 1:
folios = self.env["pms.folio"].browse(folio_ids)
mls_multi_folio = folios.payment_ids.mapped(
"move_id.line_ids"
).filtered(
lambda x: x.account_id.internal_type == "receivable"
and x.parent_state == "posted"
)
if mls_multi_folio:
advance_amount = record._get_advance_amount(mls_multi_folio)
vals = record._get_amount_vals(
mls_multi_folio, advance_amount, folio_ids
)
record.update(vals)
def _get_advance_amount(self, mls):
self.ensure_one()
advance_amount = 0.0
for line in mls:
line_currency = line.currency_id or line.company_id.currency_id
line_amount = line.amount_currency if line.currency_id else line.balance
line_amount *= -1
if line_currency != self.currency_id:
advance_amount += line.currency_id._convert(
line_amount,
self.currency_id,
self.company_id,
line.date or fields.Date.today(),
)
else:
advance_amount += line_amount
return advance_amount
def _get_amount_vals(self, mls, advance_amount, folio_ids=False):
self.ensure_one()
folios = self
if folio_ids:
folios = self.env["pms.folio"].browse(folio_ids)
mls_one_folio = (
self.payment_ids.filtered(lambda pay: len(pay.folio_ids) == 1)
.mapped("move_id.line_ids")
.filtered(
lambda x: x.account_id.internal_type == "receivable"
and x.parent_state == "posted"
)
advance_amount = 0.0
for line in mls:
line_currency = line.currency_id or line.company_id.currency_id
line_amount = (
line.amount_currency if line.currency_id else line.balance
)
line_amount *= -1
if line_currency != record.currency_id:
advance_amount += line.currency_id._convert(
line_amount,
record.currency_id,
record.company_id,
line.date or fields.Date.today(),
)
else:
advance_amount += line_amount
amount_residual = record.amount_total - advance_amount
)
amount_folio_residual = self.amount_total - self._get_advance_amount(
mls_one_folio
)
amount_total_residual = sum(folios.mapped("amount_total")) - advance_amount
else:
amount_folio_residual = amount_total_residual = (
sum(folios.mapped("amount_total")) - advance_amount
)
total = sum(folios.mapped("amount_total"))
total = record.amount_total
# REVIEW: Must We ignored services in cancelled folios
# pending amount?
if record.state == "cancel":
total = total - sum(record.service_ids.mapped("price_total"))
# Compute 'payment_state'.
payment_state = "not_paid"
if (
mls
and float_compare(
amount_residual,
total,
precision_rounding=record.currency_id.rounding,
)
!= 0
):
has_due_amount = float_compare(
amount_residual,
0.0,
precision_rounding=record.currency_id.rounding,
)
if has_due_amount <= 0:
payment_state = "paid"
elif has_due_amount > 0:
payment_state = "partial"
# REVIEW: Must We ignored services in cancelled folios
# pending amount?
for folio in folios:
if folio.state == "cancel":
total = total - sum(folio.service_ids.mapped("price_total"))
payment_state = "not_paid"
if (
mls
and float_compare(
amount_total_residual,
total,
precision_rounding=self.currency_id.rounding,
)
!= 0
):
has_due_amount = float_compare(
amount_total_residual,
0.0,
precision_rounding=self.currency_id.rounding,
)
if has_due_amount == 0:
payment_state = "paid"
elif has_due_amount > 0:
payment_state = "partial"
elif has_due_amount < 0:
payment_state = "overpayment"
elif total == 0:
payment_state = "nothing_to_pay"
vals = {
"pending_amount": amount_residual,
"invoices_paid": advance_amount,
"payment_state": payment_state,
}
record.update(vals)
vals = {
"payment_multi": len(folios) > 1,
"pending_amount": min(amount_total_residual, amount_folio_residual),
"invoices_paid": advance_amount,
"payment_state": payment_state,
}
return vals
@api.depends("reservation_ids", "reservation_ids.priority")
def _compute_max_reservation_priority(self):
@@ -1236,12 +1299,11 @@ class PmsFolio(models.Model):
if operator == "in" and value:
self.env.cr.execute(
"""
SELECT array_agg(so.id)
FROM pms_folio so
JOIN folio_sale_line sol ON sol.folio_id = so.id
JOIN folio_sale_line_invoice_rel soli_rel ON \
soli_rel.sale_line_ids = sol.id
JOIN account_move_line aml ON aml.id = soli_rel.invoice_line_id
SELECT array_agg(fo.id)
FROM pms_folio fo
JOIN folio_sale_line fol ON fol.folio_id = fo.id
JOIN folio_sale_line_invoice_rel foli_rel ON foli_rel.sale_line_id = fol.id
JOIN account_move_line aml ON aml.id = foli_rel.invoice_line_id
JOIN account_move am ON am.id = aml.move_id
WHERE
am.move_type in ('out_invoice', 'out_refund', 'in_receipt') AND
@@ -1811,7 +1873,6 @@ class PmsFolio(models.Model):
"invoice_origin": self.name,
"invoice_payment_term_id": self.payment_term_id.id,
"transaction_ids": [(6, 0, self.transaction_ids.ids)],
"folio_ids": [(6, 0, [self.id])],
"invoice_line_ids": [],
"company_id": self.company_id.id,
"payment_reference": self.external_reference or self.reference,

View File

@@ -157,13 +157,13 @@
<i class="fa fa-fw fa-arrow-circle-right" /> Pay Now
</a>
<div
t-if="tx_ids and not pending_manual_txs and folio.payment_state not in ('paid', 'in_payment')"
t-if="tx_ids and not pending_manual_txs and folio.payment_state in ('not_paid', 'partial')"
class="alert alert-info py-1 mb-2"
>
<i class="fa fa-fw fa-check-circle" /> Pending
</div>
<div
t-if="folio.payment_state in ('paid', 'in_payment')"
t-if="folio.payment_state in ('paid', 'overpayment')"
class="alert alert-success py-1 mb-2"
>
<i class="fa fa-fw fa-check-circle" /> Paid

View File

@@ -55,6 +55,17 @@
/>
</bold>
</div>
<div
class="alert alert-warning"
role="alert"
style="margin-bottom:0px;"
attrs="{'invisible': [('payment_multi','=',False)]}"
>
This folio has payments assigned to multiple folios (through an invoice or directly).
The Folio will only be considered paid if all the folios with the same associated
payment are paid, or if a specific payment is assigned to this folio.
<field name="payment_multi" invisible="1" />
</div>
<div
class="alert alert-warning"
role="alert"
@@ -209,6 +220,12 @@
bg_color="bg-warning"
attrs="{'invisible': [('payment_state', '!=', 'partial')]}"
/>
<widget
name="web_ribbon"
title="Overpayment!"
bg_color="bg-info"
attrs="{'invisible': [('payment_state', '!=', 'overpayment')]}"
/>
<widget
name="web_ribbon"
title="Staff"
@@ -549,7 +566,13 @@
<field name="payment_type" />
<field name="amount" />
<field name="partner_id" invisible="1" />
<field name="state" invisible="1" />
<field
name="state"
decoration-success="state == 'posted'"
decoration-danger="state == 'cancel'"
decoration-warning="state == 'draft'"
widget="badge"
/>
</tree>
</field>
<!-- REVIEW: transations has a payment related -->
@@ -659,9 +682,9 @@
/>
<field
name="payment_state"
decoration-success="payment_state == 'paid'"
decoration-danger="payment_state == 'not_paid' and state in ['cancel','onboard','done','arrival_delayed','departure_delayed']"
decoration-info="payment_state == 'not_paid' and state in ['draft','confirm',]"
decoration-success="payment_state in ['paid', 'nothing_to_pay']"
decoration-danger="payment_state == 'not_paid'"
decoration-info="payment_state == 'overpayment'"
decoration-warning="payment_state == 'partial'"
widget="badge"
optional="show"

View File

@@ -162,6 +162,7 @@ class FolioAdvancePaymentInv(models.TransientModel):
if self.partner_invoice_id
else order.partner_invoice_id.id,
"currency_id": order.pricelist_id.currency_id.id,
"folio_ids": [(6, 0, order.ids)],
"payment_reference": order.reference,
"invoice_payment_term_id": order.payment_term_id.id,
"partner_bank_id": order.company_id.partner_id.bank_ids[:1].id,