fix: add condition for allow negative stock in pos (backport #50369) (#50600)

Co-authored-by: Logesh Periyasamy <logeshperiyasamy24@gmail.com>
fix: add condition for allow negative stock in pos (#50369)
This commit is contained in:
mergify[bot]
2025-11-18 17:05:47 +05:30
committed by GitHub
parent a4a0a2a0fb
commit 2d6640ac61
3 changed files with 19 additions and 10 deletions

View File

@@ -189,6 +189,9 @@ class POSInvoice(SalesInvoice):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def validate(self): def validate(self):
if not self.customer:
frappe.throw(_("Please select Customer first"))
if not cint(self.is_pos): if not cint(self.is_pos):
frappe.throw( frappe.throw(
_("POS Invoice should have the field {0} checked.").format(frappe.bold(_("Include Payment"))) _("POS Invoice should have the field {0} checked.").format(frappe.bold(_("Include Payment")))
@@ -345,14 +348,14 @@ class POSInvoice(SalesInvoice):
): ):
return return
from erpnext.stock.stock_ledger import is_negative_stock_allowed
for d in self.get("items"): for d in self.get("items"):
if not d.serial_and_batch_bundle: if not d.serial_and_batch_bundle:
if is_negative_stock_allowed(item_code=d.item_code): available_stock, is_stock_item, is_negative_stock_allowed = get_stock_availability(
return d.item_code, d.warehouse
)
available_stock, is_stock_item = get_stock_availability(d.item_code, d.warehouse) if is_negative_stock_allowed:
continue
item_code, warehouse, _qty = ( item_code, warehouse, _qty = (
frappe.bold(d.item_code), frappe.bold(d.item_code),
@@ -760,20 +763,22 @@ class POSInvoice(SalesInvoice):
@frappe.whitelist() @frappe.whitelist()
def get_stock_availability(item_code, warehouse): def get_stock_availability(item_code, warehouse):
from erpnext.stock.stock_ledger import is_negative_stock_allowed
if frappe.db.get_value("Item", item_code, "is_stock_item"): if frappe.db.get_value("Item", item_code, "is_stock_item"):
is_stock_item = True is_stock_item = True
bin_qty = get_bin_qty(item_code, warehouse) bin_qty = get_bin_qty(item_code, warehouse)
pos_sales_qty = get_pos_reserved_qty(item_code, warehouse) pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
return bin_qty - pos_sales_qty, is_stock_item return bin_qty - pos_sales_qty, is_stock_item, is_negative_stock_allowed(item_code=item_code)
else: else:
is_stock_item = True is_stock_item = True
if frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0}): if frappe.db.exists("Product Bundle", {"name": item_code, "disabled": 0}):
return get_bundle_availability(item_code, warehouse), is_stock_item return get_bundle_availability(item_code, warehouse), is_stock_item, False
else: else:
is_stock_item = False is_stock_item = False
# Is a service item or non_stock item # Is a service item or non_stock item
return 0, is_stock_item return 0, is_stock_item, False
def get_bundle_availability(bundle_item_code, warehouse): def get_bundle_availability(bundle_item_code, warehouse):

View File

@@ -55,7 +55,7 @@ def search_by_term(search_term, warehouse, price_list):
} }
) )
item_stock_qty, is_stock_item = get_stock_availability(item_code, warehouse) item_stock_qty, is_stock_item, is_negative_stock_allowed = get_stock_availability(item_code, warehouse)
item_stock_qty = item_stock_qty // item.get("conversion_factor", 1) item_stock_qty = item_stock_qty // item.get("conversion_factor", 1)
item.update({"actual_qty": item_stock_qty}) item.update({"actual_qty": item_stock_qty})
@@ -198,7 +198,7 @@ def get_items(start, page_length, price_list, item_group, pos_profile, search_te
current_date = frappe.utils.today() current_date = frappe.utils.today()
for item in items_data: for item in items_data:
item.actual_qty, _ = get_stock_availability(item.item_code, warehouse) item.actual_qty, _, is_negative_stock_allowed = get_stock_availability(item.item_code, warehouse)
item_prices = frappe.get_all( item_prices = frappe.get_all(
"Item Price", "Item Price",

View File

@@ -759,12 +759,16 @@ erpnext.PointOfSale.Controller = class {
const resp = (await this.get_available_stock(item_row.item_code, warehouse)).message; const resp = (await this.get_available_stock(item_row.item_code, warehouse)).message;
const available_qty = resp[0]; const available_qty = resp[0];
const is_stock_item = resp[1]; const is_stock_item = resp[1];
const is_negative_stock_allowed = resp[2];
frappe.dom.unfreeze(); frappe.dom.unfreeze();
const bold_uom = item_row.stock_uom.bold(); const bold_uom = item_row.stock_uom.bold();
const bold_item_code = item_row.item_code.bold(); const bold_item_code = item_row.item_code.bold();
const bold_warehouse = warehouse.bold(); const bold_warehouse = warehouse.bold();
const bold_available_qty = available_qty.toString().bold(); const bold_available_qty = available_qty.toString().bold();
if (is_negative_stock_allowed) return;
if (!(available_qty > 0)) { if (!(available_qty > 0)) {
if (is_stock_item) { if (is_stock_item) {
frappe.model.clear_doc(item_row.doctype, item_row.name); frappe.model.clear_doc(item_row.doctype, item_row.name);