mirror of
https://github.com/frappe/erpnext.git
synced 2026-09-02 08:03:21 +00:00
Merge pull request #57560 from nishkagosalia/gh-56632
fix: handling negative grand total
This commit is contained in:
@@ -210,6 +210,23 @@ class AccountsController(TransactionBase):
|
||||
)
|
||||
frappe.msgprint(msg)
|
||||
|
||||
def is_negative_grand_total_allowed(self) -> bool:
|
||||
"""Return True if this document may save with a negative grand total.
|
||||
|
||||
Sales Order and Purchase Order never post to the GL, so a negative
|
||||
total is safe there whenever the user has explicitly opted into
|
||||
negative rates via Selling/Buying Settings. Every other
|
||||
AccountsController doctype (invoices, delivery notes, receipts,
|
||||
quotations, ...) keeps relying on the `is_return` escape hatch only.
|
||||
"""
|
||||
if self.doctype == "Sales Order":
|
||||
return bool(frappe.get_single_value("Selling Settings", "allow_negative_rates_for_items"))
|
||||
|
||||
if self.doctype == "Purchase Order":
|
||||
return bool(frappe.get_single_value("Buying Settings", "allow_negative_rates_for_items"))
|
||||
|
||||
return False
|
||||
|
||||
def validate(self):
|
||||
if not self.get("is_return") and not self.get("is_debit_note"):
|
||||
self.validate_qty_is_not_zero()
|
||||
@@ -262,7 +279,8 @@ class AccountsController(TransactionBase):
|
||||
self.calculate_taxes_and_totals()
|
||||
|
||||
if not self.meta.get_field("is_return") or not self.is_return:
|
||||
self.validate_value("base_grand_total", ">=", 0)
|
||||
if not self.is_negative_grand_total_allowed():
|
||||
self.validate_value("base_grand_total", ">=", 0)
|
||||
|
||||
validate_return(self)
|
||||
|
||||
|
||||
@@ -265,6 +265,9 @@ class StatusUpdater(Document):
|
||||
|
||||
def validate_qty(self):
|
||||
"""Validates qty at row level"""
|
||||
selling_doctypes = ("Sales Order", "Sales Invoice", "Delivery Note")
|
||||
buying_doctypes = ("Purchase Order", "Purchase Invoice", "Purchase Receipt")
|
||||
|
||||
for args in self.status_updater:
|
||||
if "target_ref_field" not in args or args.get("validate_qty") is False:
|
||||
# if target_ref_field is not specified or validate_qty is explicitly set to False, skip validation
|
||||
@@ -292,11 +295,8 @@ class StatusUpdater(Document):
|
||||
if hasattr(d, "qty") and flt(d.qty) > 0 and self.get("is_return"):
|
||||
frappe.throw(_("For an item {0}, quantity must be a negative number").format(d.item_code))
|
||||
|
||||
if (
|
||||
not selling_negative_rate_allowed and self.doctype in ["Sales Invoice", "Delivery Note"]
|
||||
) or (
|
||||
not buying_negative_rate_allowed
|
||||
and self.doctype in ["Purchase Invoice", "Purchase Receipt"]
|
||||
if (not selling_negative_rate_allowed and self.doctype in selling_doctypes) or (
|
||||
not buying_negative_rate_allowed and self.doctype in buying_doctypes
|
||||
):
|
||||
if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0:
|
||||
frappe.throw(
|
||||
@@ -307,7 +307,7 @@ class StatusUpdater(Document):
|
||||
frappe.bold(_("`Allow Negative rates for Items`")),
|
||||
get_link_to_form(
|
||||
"Selling Settings"
|
||||
if self.doctype in ["Sales Invoice", "Delivery Note"]
|
||||
if self.doctype in selling_doctypes
|
||||
else "Buying Settings"
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user