2021-10-20 13:45:35 +00:00
|
|
|
import frappe
|
|
|
|
from frappe.utils import flt, getdate
|
|
|
|
|
|
|
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
|
|
|
|
get_total_in_party_account_currency,
|
|
|
|
is_overdue,
|
|
|
|
)
|
|
|
|
|
|
|
|
TODAY = getdate()
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
|
2021-10-20 13:45:35 +00:00
|
|
|
def execute():
|
|
|
|
# This fix is not related to Party Specific Item,
|
|
|
|
# but it is needed for code introduced after Party Specific Item was
|
|
|
|
# If your DB doesn't have this doctype yet, you should be fine
|
|
|
|
if not frappe.db.exists("DocType", "Party Specific Item"):
|
|
|
|
return
|
|
|
|
|
|
|
|
for doctype in ("Purchase Invoice", "Sales Invoice"):
|
|
|
|
fields = [
|
|
|
|
"name",
|
|
|
|
"status",
|
|
|
|
"due_date",
|
|
|
|
"outstanding_amount",
|
|
|
|
"grand_total",
|
|
|
|
"base_grand_total",
|
|
|
|
"rounded_total",
|
|
|
|
"base_rounded_total",
|
|
|
|
"disable_rounded_total",
|
|
|
|
]
|
|
|
|
if doctype == "Sales Invoice":
|
|
|
|
fields.append("is_pos")
|
|
|
|
|
|
|
|
invoices_to_update = frappe.get_all(
|
|
|
|
doctype,
|
|
|
|
fields=fields,
|
|
|
|
filters={
|
|
|
|
"docstatus": 1,
|
2022-03-28 13:22:46 +00:00
|
|
|
"status": (
|
|
|
|
"in",
|
|
|
|
("Overdue", "Overdue and Discounted", "Partly Paid", "Partly Paid and Discounted"),
|
|
|
|
),
|
2021-10-20 13:45:35 +00:00
|
|
|
"outstanding_amount": (">", 0),
|
|
|
|
"modified": (">", "2021-01-01")
|
|
|
|
# an assumption is being made that only invoices modified
|
|
|
|
# after 2021 got affected as incorrectly overdue.
|
|
|
|
# required for performance reasons.
|
2022-03-28 13:22:46 +00:00
|
|
|
},
|
2021-10-20 13:45:35 +00:00
|
|
|
)
|
|
|
|
|
2022-03-28 13:22:46 +00:00
|
|
|
invoices_to_update = {invoice.name: invoice for invoice in invoices_to_update}
|
2021-10-20 13:45:35 +00:00
|
|
|
|
|
|
|
payment_schedule_items = frappe.get_all(
|
|
|
|
"Payment Schedule",
|
2022-03-28 13:22:46 +00:00
|
|
|
fields=("due_date", "payment_amount", "base_payment_amount", "parent"),
|
|
|
|
filters={"parent": ("in", invoices_to_update)},
|
2021-10-20 13:45:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
for item in payment_schedule_items:
|
2022-03-28 13:22:46 +00:00
|
|
|
invoices_to_update[item.parent].setdefault("payment_schedule", []).append(item)
|
2021-10-20 13:45:35 +00:00
|
|
|
|
|
|
|
status_map = {}
|
|
|
|
|
|
|
|
for invoice in invoices_to_update.values():
|
|
|
|
invoice.doctype = doctype
|
|
|
|
doc = frappe.get_doc(invoice)
|
|
|
|
correct_status = get_correct_status(doc)
|
|
|
|
if not correct_status or doc.status == correct_status:
|
|
|
|
continue
|
|
|
|
|
|
|
|
status_map.setdefault(correct_status, []).append(doc.name)
|
|
|
|
|
|
|
|
for status, docs in status_map.items():
|
2022-03-28 13:22:46 +00:00
|
|
|
frappe.db.set_value(doctype, {"name": ("in", docs)}, "status", status, update_modified=False)
|
2021-10-20 13:45:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_correct_status(doc):
|
2022-03-28 13:22:46 +00:00
|
|
|
outstanding_amount = flt(doc.outstanding_amount, doc.precision("outstanding_amount"))
|
2021-10-20 13:45:35 +00:00
|
|
|
total = get_total_in_party_account_currency(doc)
|
|
|
|
|
|
|
|
status = ""
|
|
|
|
if is_overdue(doc, total):
|
|
|
|
status = "Overdue"
|
|
|
|
elif 0 < outstanding_amount < total:
|
|
|
|
status = "Partly Paid"
|
|
|
|
elif outstanding_amount > 0 and getdate(doc.due_date) >= TODAY:
|
|
|
|
status = "Unpaid"
|
|
|
|
|
|
|
|
if not status:
|
|
|
|
return
|
|
|
|
|
|
|
|
if doc.status.endswith(" and Discounted"):
|
|
|
|
status += " and Discounted"
|
|
|
|
|
|
|
|
return status
|