Skip to content

Commit

Permalink
[IMP] account_invoice_overdue_warn: filter by delay lines
Browse files Browse the repository at this point in the history
  • Loading branch information
CristianoMafraJunior committed Apr 1, 2024
1 parent edf1a0c commit e9f3859
Show file tree
Hide file tree
Showing 3 changed files with 344 additions and 17 deletions.
51 changes: 34 additions & 17 deletions account_invoice_overdue_warn/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright 2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <[email protected]>
# Copyright 2024 Engenere.one
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models
Expand Down Expand Up @@ -32,43 +33,59 @@ def _compute_overdue_invoice_count_amount(self):
partner.overdue_invoice_count = count
partner.overdue_invoice_amount = amount_company_currency

def _get_overdue_move_lines(self, company_id):
domain = self._prepare_overdue_move_lines_domain(company_id)
overdue_move_lines = self.env["account.move.line"].search(domain)
return overdue_move_lines

def _prepare_overdue_invoice_count_amount(self, company_id):
# This method is also called by the module
# account_invoice_overdue_warn_sale where the company_id arg is used
self.ensure_one()
domain = self._prepare_overdue_invoice_domain(company_id)
# amount_residual_signed is in company currency
rg_res = self.env["account.move"].read_group(
domain, ["amount_residual_signed"], []
# amount_residual is in company currency
overdue_move_lines = self._get_overdue_move_lines(company_id)
overdue_invoice_amount = self._compute_overdue_move_lines_total(
overdue_move_lines
)
count = 0
overdue_invoice_amount = 0.0
if rg_res:
count = rg_res[0]["__count"]
overdue_invoice_amount = rg_res[0]["amount_residual_signed"]
count = self._count_unique_invoices(overdue_move_lines)
return (count, overdue_invoice_amount)

def _prepare_overdue_invoice_domain(self, company_id):
def _prepare_overdue_move_lines_domain(self, company_id):
# The use of commercial_partner_id is in this method
self.ensure_one()
today = fields.Date.context_today(self)
if company_id is None:
company_id = self.env.company.id
domain = [
("move_type", "=", "out_invoice"),
("company_id", "=", company_id),
("commercial_partner_id", "=", self.commercial_partner_id.id),
("invoice_date_due", "<", today),
("state", "=", "posted"),
("payment_state", "in", ("not_paid", "partial")),
("move_id.company_id", "=", company_id),
("move_id.commercial_partner_id", "=", self.commercial_partner_id.id),
("date_maturity", "<", today),
("move_id.state", "=", "posted"),
("reconciled", "=", False),
("account_internal_type", "=", "receivable"),
]
return domain

def _compute_overdue_move_lines_total(self, overdue_move_lines):
return sum(overdue_move_lines.mapped("amount_residual"))

def _get_unique_invoices(self, overdue_move_lines):
return overdue_move_lines.mapped("move_id").ids

def _count_unique_invoices(self, overdue_move_lines):
unique_invoices = self._get_unique_invoices(overdue_move_lines)
return len(unique_invoices)

def _prepare_invoice_domain(self, invoice_ids):
return [("id", "in", invoice_ids)]

def _prepare_jump_to_overdue_invoices(self, company_id):
action = self.env["ir.actions.actions"]._for_xml_id(
"account.action_move_out_invoice_type"
)
action["domain"] = self._prepare_overdue_invoice_domain(company_id)
overdue_move_lines = self._get_overdue_move_lines(company_id)
unique_invoice_ids = self._get_unique_invoices(overdue_move_lines)
action["domain"] = self._prepare_invoice_domain(unique_invoice_ids)
action["context"] = {
"journal_type": "sale",
"move_type": "out_invoice",
Expand Down
1 change: 1 addition & 0 deletions account_invoice_overdue_warn/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from . import test_overdue_warn
from . import test_overdue_warn_installment
309 changes: 309 additions & 0 deletions account_invoice_overdue_warn/tests/test_overdue_warn_installment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
# Copyright 2024 Engenere.one
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import datetime, timedelta

from odoo.tests import Form, tagged
from odoo.tests.common import TransactionCase


@tagged("post_install", "-at_install")
class TestOverdueWarn(TransactionCase):
def setUp(self):
super().setUp()
self.company = self.env.ref("base.main_company")
self.partner = self.env["res.partner"].create(
{
"name": "Test Partner",
"country_id": self.env.ref("base.br").id,
"company_id": self.company.id,
}
)
self.today = datetime.now().date()
self.revenue_acc = self.env["account.account"].search(
[
("company_id", "=", self.company.id),
(
"user_type_id",
"=",
self.env.ref("account.data_account_type_revenue").id,
),
],
limit=1,
)

self.payment_term = self.env["account.payment.term"].create(
{
"name": "Immediate payment",
"line_ids": [
(
0,
0,
{
"value": "balance",
"days": 0,
},
),
],
}
)

self.payment_term_installments_a = self.env["account.payment.term"].create(
{
"name": "Pay in 3 installments",
"line_ids": [
(
0,
0,
{
"value": "percent",
"value_amount": 33.33,
"days": 0,
},
),
(
0,
0,
{
"value": "percent",
"value_amount": 33.33,
"days": 0,
},
),
(
0,
0,
{
"value": "balance",
"days": 0,
},
),
],
}
)

self.payment_term_installments_b = self.env["account.payment.term"].create(
{
"name": "Pay in 3 installments",
"line_ids": [
(
0,
0,
{
"value": "percent",
"value_amount": 33.33,
"days": 0,
},
),
(
0,
0,
{
"value": "percent",
"value_amount": 33.33,
"days": 0,
},
),
(
0,
0,
{
"value": "balance",
"days": 14,
},
),
],
}
)

def test_out_invoice_draft(self):
out_invoice_draft = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "out_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today - timedelta(days=9),
"invoice_payment_term_id": self.payment_term.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 500,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
)
],
}
)
self.assertEqual(
out_invoice_draft.invoice_date_due,
out_invoice_draft.line_ids[1].date_maturity,
)
self.assertEqual(out_invoice_draft.state, "draft")
self.assertEqual(self.partner.overdue_invoice_count, 0)
self.assertEqual(self.partner.overdue_invoice_amount, 0.0)

def test_confirmed_supplier_invoice(self):
out_invoice_supplier = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "in_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today - timedelta(days=9),
"invoice_payment_term_id": self.payment_term.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 500,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
)
],
}
)
out_invoice_supplier.action_post()
self.assertEqual(
out_invoice_supplier.invoice_date_due,
out_invoice_supplier.line_ids[1].date_maturity,
)
self.assertEqual(self.partner.overdue_invoice_count, 0)
self.assertEqual(self.partner.overdue_invoice_amount, 0.0)

def test_mixed_case_with_two_invoices(self):

out_invoice_a = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "out_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today - timedelta(days=10),
"invoice_payment_term_id": self.payment_term_installments_a.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 900,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
),
],
}
)
out_invoice_a.action_post()

out_invoice_b = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "out_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today - timedelta(days=10),
"invoice_payment_term_id": self.payment_term_installments_b.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 900,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
),
],
}
)
out_invoice_b.action_post()

action_data_a = out_invoice_a.action_register_payment()
wizard_a = Form(
self.env["account.payment.register"].with_context(action_data_a["context"])
).save()
wizard_a.amount = 450.0
wizard_a.action_create_payments()

self.assertEqual(
out_invoice_b.invoice_date_due,
out_invoice_b.line_ids[3].date_maturity,
)
self.assertEqual(self.partner.overdue_invoice_count, 2)
self.assertEqual(self.partner.overdue_invoice_amount, 1049.94)

def test_confirmed_invoice_with_past_date(self):
out_invoice_past_paid = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "out_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today - timedelta(days=5),
"invoice_payment_term_id": self.payment_term.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 500.0,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
)
],
}
)
out_invoice_past_paid.action_post()
action_data = out_invoice_past_paid.action_register_payment()
wizard = Form(
self.env["account.payment.register"].with_context(action_data["context"])
).save()
wizard.action_create_payments()
self.assertEqual(
out_invoice_past_paid.invoice_date_due,
out_invoice_past_paid.line_ids[1].date_maturity,
)
self.assertEqual(self.partner.overdue_invoice_count, 0)
self.assertEqual(self.partner.overdue_invoice_amount, 0)

def test_confirmed_invoice_with_future_date_unpaid(self):
out_invoice_future = self.env["account.move"].create(
{
"partner_id": self.partner.id,
"move_type": "out_invoice",
"company_id": self.company.id,
"currency_id": self.company.currency_id.id,
"invoice_date": self.today + timedelta(days=5),
"invoice_payment_term_id": self.payment_term.id,
"invoice_line_ids": [
(
0,
0,
{
"name": "Product Test",
"price_unit": 500,
"quantity": 1,
"account_id": self.revenue_acc.id,
},
)
],
}
)
out_invoice_future.action_post()
self.assertEqual(
out_invoice_future.invoice_date_due,
out_invoice_future.line_ids[1].date_maturity,
)
self.assertEqual(self.partner.overdue_invoice_count, 0)
self.assertEqual(self.partner.overdue_invoice_amount, 0)

0 comments on commit e9f3859

Please sign in to comment.