-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: incorrect status being set in Invoices
- Loading branch information
Showing
5 changed files
with
163 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import frappe | ||
from frappe.utils import flt, getdate | ||
|
||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import is_overdue | ||
|
||
TODAY = getdate() | ||
|
||
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"): | ||
# For invoices wrongly set as overdue in daily scheduler event | ||
invoices_to_update = frappe.get_all( | ||
doctype, | ||
fields="*", | ||
filters={ | ||
"docstatus": 1, | ||
"status": "Overdue", | ||
"modified": (">", "2021-01-01"), | ||
"outstanding_amount": (">", 0) | ||
# an assumption is being made that only invoices modified after 2021 | ||
# got affected as incorrectly overdue. required for performance reasons. | ||
} | ||
) | ||
|
||
# For wrong statuses set using invoice.set_status (excl. Overdue) | ||
invoices_to_update += frappe.get_all( | ||
doctype, | ||
fields="*", | ||
filters={ | ||
"docstatus": 1, | ||
"status": ("in", ( | ||
"Overdue and Discounted", | ||
"Partly Paid", | ||
"Partly Paid and Discounted" | ||
)), | ||
"modified": (">", "2021-09-22"), | ||
"outstanding_amount": (">", 0) | ||
} | ||
) | ||
|
||
invoices_to_update = { | ||
invoice.name: invoice for invoice in invoices_to_update | ||
} | ||
|
||
payment_schedule_items = frappe.get_all( | ||
"Payment Schedule", | ||
fields=["due_date", "base_payment_amount", "parent"], | ||
filters={"parent": ("in", invoices_to_update)} | ||
) | ||
|
||
for item in payment_schedule_items: | ||
invoices_to_update[item.parent].setdefault( | ||
"payment_schedule", [] | ||
).append(item) | ||
|
||
status_map = {} | ||
|
||
for invoice in invoices_to_update.values(): | ||
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(): | ||
frappe.db.set_value(doctype, {"name": ("in", docs)}, "status", status) | ||
|
||
|
||
|
||
def get_correct_status(doc): | ||
outstanding_amount = flt( | ||
doc.outstanding_amount, doc.precision("outstanding_amount") | ||
) | ||
|
||
total_fieldname = ( | ||
"base_grand_total" | ||
if doc.disable_rounded_total | ||
else "base_rounded_total" | ||
) | ||
|
||
total = flt(doc.get(total_fieldname), doc.precision(total_fieldname)) | ||
|
||
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 |