fix: allow to select parent warehouse in the website item (#37047)
(cherry picked from commit e6199dc802)
Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
@@ -312,7 +312,7 @@ class TestWebsiteItem(unittest.TestCase):
|
|||||||
# check if stock details are fetched and item not in stock with warehouse set
|
# check if stock details are fetched and item not in stock with warehouse set
|
||||||
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
||||||
self.assertFalse(bool(data.product_info["in_stock"]))
|
self.assertFalse(bool(data.product_info["in_stock"]))
|
||||||
self.assertEqual(data.product_info["stock_qty"][0][0], 0)
|
self.assertEqual(data.product_info["stock_qty"], 0)
|
||||||
|
|
||||||
# disable show stock availability
|
# disable show stock availability
|
||||||
setup_e_commerce_settings({"show_stock_availability": 0})
|
setup_e_commerce_settings({"show_stock_availability": 0})
|
||||||
@@ -355,7 +355,7 @@ class TestWebsiteItem(unittest.TestCase):
|
|||||||
# check if stock details are fetched and item is in stock with warehouse set
|
# check if stock details are fetched and item is in stock with warehouse set
|
||||||
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
||||||
self.assertTrue(bool(data.product_info["in_stock"]))
|
self.assertTrue(bool(data.product_info["in_stock"]))
|
||||||
self.assertEqual(data.product_info["stock_qty"][0][0], 2)
|
self.assertEqual(data.product_info["stock_qty"], 2)
|
||||||
|
|
||||||
# unset warehouse
|
# unset warehouse
|
||||||
frappe.db.set_value("Website Item", {"item_code": item_code}, "website_warehouse", "")
|
frappe.db.set_value("Website Item", {"item_code": item_code}, "website_warehouse", "")
|
||||||
@@ -364,7 +364,7 @@ class TestWebsiteItem(unittest.TestCase):
|
|||||||
# (even though it has stock in some warehouse)
|
# (even though it has stock in some warehouse)
|
||||||
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
data = get_product_info_for_website(item_code, skip_quotation_creation=True)
|
||||||
self.assertFalse(bool(data.product_info["in_stock"]))
|
self.assertFalse(bool(data.product_info["in_stock"]))
|
||||||
self.assertFalse(bool(data.product_info["stock_qty"]))
|
self.assertFalse(data.product_info["stock_qty"])
|
||||||
|
|
||||||
# disable show stock availability
|
# disable show stock availability
|
||||||
setup_e_commerce_settings({"show_stock_availability": 0})
|
setup_e_commerce_settings({"show_stock_availability": 0})
|
||||||
|
|||||||
@@ -5,12 +5,6 @@ frappe.ui.form.on('Website Item', {
|
|||||||
onload: (frm) => {
|
onload: (frm) => {
|
||||||
// should never check Private
|
// should never check Private
|
||||||
frm.fields_dict["website_image"].df.is_private = 0;
|
frm.fields_dict["website_image"].df.is_private = 0;
|
||||||
|
|
||||||
frm.set_query("website_warehouse", () => {
|
|
||||||
return {
|
|
||||||
filters: {"is_group": 0}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: (frm) => {
|
refresh: (frm) => {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Show Stock availability based on this warehouse.",
|
"description": "Show Stock availability based on this warehouse. If the parent warehouse is selected, then the system will display the consolidated available quantity of all child warehouses.",
|
||||||
"fieldname": "website_warehouse",
|
"fieldname": "website_warehouse",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
@@ -348,7 +348,7 @@
|
|||||||
"index_web_pages_for_search": 1,
|
"index_web_pages_for_search": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"make_attachments_public": 1,
|
"make_attachments_public": 1,
|
||||||
"modified": "2022-09-30 04:01:52.090732",
|
"modified": "2023-09-12 14:19:22.822689",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "E-commerce",
|
"module": "E-commerce",
|
||||||
"name": "Website Item",
|
"name": "Website Item",
|
||||||
|
|||||||
@@ -259,6 +259,10 @@ class ProductQuery:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_stock_availability(self, item):
|
def get_stock_availability(self, item):
|
||||||
|
from erpnext.templates.pages.wishlist import (
|
||||||
|
get_stock_availability as get_stock_availability_from_template,
|
||||||
|
)
|
||||||
|
|
||||||
"""Modify item object and add stock details."""
|
"""Modify item object and add stock details."""
|
||||||
item.in_stock = False
|
item.in_stock = False
|
||||||
warehouse = item.get("website_warehouse")
|
warehouse = item.get("website_warehouse")
|
||||||
@@ -274,11 +278,7 @@ class ProductQuery:
|
|||||||
else:
|
else:
|
||||||
item.in_stock = True
|
item.in_stock = True
|
||||||
elif warehouse:
|
elif warehouse:
|
||||||
# stock item and has warehouse
|
item.in_stock = get_stock_availability_from_template(item.item_code, warehouse)
|
||||||
actual_qty = frappe.db.get_value(
|
|
||||||
"Bin", {"item_code": item.item_code, "warehouse": item.get("website_warehouse")}, "actual_qty"
|
|
||||||
)
|
|
||||||
item.in_stock = bool(flt(actual_qty))
|
|
||||||
|
|
||||||
def get_cart_items(self):
|
def get_cart_items(self):
|
||||||
customer = get_customer(silent=True)
|
customer = get_customer(silent=True)
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ def place_order():
|
|||||||
item_stock = get_web_item_qty_in_stock(item.item_code, "website_warehouse")
|
item_stock = get_web_item_qty_in_stock(item.item_code, "website_warehouse")
|
||||||
if not cint(item_stock.in_stock):
|
if not cint(item_stock.in_stock):
|
||||||
throw(_("{0} Not in Stock").format(item.item_code))
|
throw(_("{0} Not in Stock").format(item.item_code))
|
||||||
if item.qty > item_stock.stock_qty[0][0]:
|
if item.qty > item_stock.stock_qty:
|
||||||
throw(_("Only {0} in Stock for item {1}").format(item_stock.stock_qty[0][0], item.item_code))
|
throw(_("Only {0} in Stock for item {1}").format(item_stock.stock_qty, item.item_code))
|
||||||
|
|
||||||
sales_order.flags.ignore_permissions = True
|
sales_order.flags.ignore_permissions = True
|
||||||
sales_order.insert()
|
sales_order.insert()
|
||||||
@@ -150,6 +150,10 @@ def update_cart(item_code, qty, additional_notes=None, with_items=False):
|
|||||||
empty_card = True
|
empty_card = True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
warehouse = frappe.get_cached_value(
|
||||||
|
"Website Item", {"item_code": item_code}, "website_warehouse"
|
||||||
|
)
|
||||||
|
|
||||||
quotation_items = quotation.get("items", {"item_code": item_code})
|
quotation_items = quotation.get("items", {"item_code": item_code})
|
||||||
if not quotation_items:
|
if not quotation_items:
|
||||||
quotation.append(
|
quotation.append(
|
||||||
@@ -159,11 +163,13 @@ def update_cart(item_code, qty, additional_notes=None, with_items=False):
|
|||||||
"item_code": item_code,
|
"item_code": item_code,
|
||||||
"qty": qty,
|
"qty": qty,
|
||||||
"additional_notes": additional_notes,
|
"additional_notes": additional_notes,
|
||||||
|
"warehouse": warehouse,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
quotation_items[0].qty = qty
|
quotation_items[0].qty = qty
|
||||||
quotation_items[0].additional_notes = additional_notes
|
quotation_items[0].additional_notes = additional_notes
|
||||||
|
quotation_items[0].warehouse = warehouse
|
||||||
|
|
||||||
apply_cart_settings(quotation=quotation)
|
apply_cart_settings(quotation=quotation)
|
||||||
|
|
||||||
@@ -322,6 +328,10 @@ def decorate_quotation_doc(doc):
|
|||||||
fields = fields[2:]
|
fields = fields[2:]
|
||||||
|
|
||||||
d.update(frappe.db.get_value("Website Item", {"item_code": item_code}, fields, as_dict=True))
|
d.update(frappe.db.get_value("Website Item", {"item_code": item_code}, fields, as_dict=True))
|
||||||
|
website_warehouse = frappe.get_cached_value(
|
||||||
|
"Website Item", {"item_code": item_code}, "website_warehouse"
|
||||||
|
)
|
||||||
|
d.warehouse = website_warehouse
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,8 @@ def get_attributes_and_values(item_code):
|
|||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def get_next_attribute_and_values(item_code, selected_attributes):
|
def get_next_attribute_and_values(item_code, selected_attributes):
|
||||||
|
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||||
|
|
||||||
"""Find the count of Items that match the selected attributes.
|
"""Find the count of Items that match the selected attributes.
|
||||||
Also, find the attribute values that are not applicable for further searching.
|
Also, find the attribute values that are not applicable for further searching.
|
||||||
If less than equal to 10 items are found, return item_codes of those items.
|
If less than equal to 10 items are found, return item_codes of those items.
|
||||||
@@ -168,7 +170,7 @@ def get_next_attribute_and_values(item_code, selected_attributes):
|
|||||||
product_info = None
|
product_info = None
|
||||||
|
|
||||||
product_id = ""
|
product_id = ""
|
||||||
website_warehouse = ""
|
warehouse = ""
|
||||||
if exact_match or filtered_items:
|
if exact_match or filtered_items:
|
||||||
if exact_match and len(exact_match) == 1:
|
if exact_match and len(exact_match) == 1:
|
||||||
product_id = exact_match[0]
|
product_id = exact_match[0]
|
||||||
@@ -176,16 +178,19 @@ def get_next_attribute_and_values(item_code, selected_attributes):
|
|||||||
product_id = list(filtered_items)[0]
|
product_id = list(filtered_items)[0]
|
||||||
|
|
||||||
if product_id:
|
if product_id:
|
||||||
website_warehouse = frappe.get_cached_value(
|
warehouse = frappe.get_cached_value(
|
||||||
"Website Item", {"item_code": product_id}, "website_warehouse"
|
"Website Item", {"item_code": product_id}, "website_warehouse"
|
||||||
)
|
)
|
||||||
|
|
||||||
available_qty = 0.0
|
available_qty = 0.0
|
||||||
if website_warehouse:
|
if warehouse and frappe.get_cached_value("Warehouse", warehouse, "is_group") == 1:
|
||||||
available_qty = flt(
|
warehouses = get_child_warehouses(warehouse)
|
||||||
frappe.db.get_value(
|
else:
|
||||||
"Bin", {"item_code": product_id, "warehouse": website_warehouse}, "actual_qty"
|
warehouses = [warehouse] if warehouse else []
|
||||||
)
|
|
||||||
|
for warehouse in warehouses:
|
||||||
|
available_qty += flt(
|
||||||
|
frappe.db.get_value("Bin", {"item_code": product_id, "warehouse": warehouse}, "actual_qty")
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1392,6 +1392,9 @@ def get_default_bom(item_code=None):
|
|||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_valuation_rate(item_code, company, warehouse=None):
|
def get_valuation_rate(item_code, company, warehouse=None):
|
||||||
|
if frappe.get_cached_value("Warehouse", warehouse, "is_group"):
|
||||||
|
return {"valuation_rate": 0.0}
|
||||||
|
|
||||||
item = get_item_defaults(item_code, company)
|
item = get_item_defaults(item_code, company)
|
||||||
item_group = get_item_group_defaults(item_code, company)
|
item_group = get_item_group_defaults(item_code, company)
|
||||||
brand = get_brand_defaults(item_code, company)
|
brand = get_brand_defaults(item_code, company)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
<span class="in-green has-stock">
|
<span class="in-green has-stock">
|
||||||
{{ _('In stock') }}
|
{{ _('In stock') }}
|
||||||
{% if product_info.show_stock_qty and product_info.stock_qty %}
|
{% if product_info.show_stock_qty and product_info.stock_qty %}
|
||||||
({{ product_info.stock_qty[0][0] }})
|
({{ product_info.stock_qty }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -25,9 +25,19 @@ def get_context(context):
|
|||||||
|
|
||||||
|
|
||||||
def get_stock_availability(item_code, warehouse):
|
def get_stock_availability(item_code, warehouse):
|
||||||
stock_qty = frappe.utils.flt(
|
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||||
|
|
||||||
|
if warehouse and frappe.get_cached_value("Warehouse", warehouse, "is_group") == 1:
|
||||||
|
warehouses = get_child_warehouses(warehouse)
|
||||||
|
else:
|
||||||
|
warehouses = [warehouse] if warehouse else []
|
||||||
|
|
||||||
|
stock_qty = 0.0
|
||||||
|
for warehouse in warehouses:
|
||||||
|
stock_qty += frappe.utils.flt(
|
||||||
frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "actual_qty")
|
frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "actual_qty")
|
||||||
)
|
)
|
||||||
|
|
||||||
return bool(stock_qty)
|
return bool(stock_qty)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from frappe.utils import cint, flt, fmt_money, getdate, nowdate
|
|||||||
|
|
||||||
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item
|
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item
|
||||||
from erpnext.stock.doctype.batch.batch import get_batch_qty
|
from erpnext.stock.doctype.batch.batch import get_batch_qty
|
||||||
|
from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
|
||||||
|
|
||||||
|
|
||||||
def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
||||||
@@ -22,7 +23,14 @@ def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
|||||||
"Website Item", {"item_code": template_item_code}, item_warehouse_field
|
"Website Item", {"item_code": template_item_code}, item_warehouse_field
|
||||||
)
|
)
|
||||||
|
|
||||||
if warehouse:
|
if warehouse and frappe.get_cached_value("Warehouse", warehouse, "is_group") == 1:
|
||||||
|
warehouses = get_child_warehouses(warehouse)
|
||||||
|
else:
|
||||||
|
warehouses = [warehouse] if warehouse else []
|
||||||
|
|
||||||
|
total_stock = 0.0
|
||||||
|
if warehouses:
|
||||||
|
for warehouse in warehouses:
|
||||||
stock_qty = frappe.db.sql(
|
stock_qty = frappe.db.sql(
|
||||||
"""
|
"""
|
||||||
select GREATEST(S.actual_qty - S.reserved_qty - S.reserved_qty_for_production - S.reserved_qty_for_sub_contract, 0) / IFNULL(C.conversion_factor, 1)
|
select GREATEST(S.actual_qty - S.reserved_qty - S.reserved_qty_for_production - S.reserved_qty_for_sub_contract, 0) / IFNULL(C.conversion_factor, 1)
|
||||||
@@ -34,11 +42,12 @@ def get_web_item_qty_in_stock(item_code, item_warehouse_field, warehouse=None):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if stock_qty:
|
if stock_qty:
|
||||||
stock_qty = adjust_qty_for_expired_items(item_code, stock_qty, warehouse)
|
total_stock += adjust_qty_for_expired_items(item_code, stock_qty, warehouse)
|
||||||
in_stock = stock_qty[0][0] > 0 and 1 or 0
|
|
||||||
|
in_stock = total_stock > 0 and 1 or 0
|
||||||
|
|
||||||
return frappe._dict(
|
return frappe._dict(
|
||||||
{"in_stock": in_stock, "stock_qty": stock_qty, "is_stock_item": is_stock_item}
|
{"in_stock": in_stock, "stock_qty": total_stock, "is_stock_item": is_stock_item}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -56,7 +65,7 @@ def adjust_qty_for_expired_items(item_code, stock_qty, warehouse):
|
|||||||
if not stock_qty[0][0]:
|
if not stock_qty[0][0]:
|
||||||
break
|
break
|
||||||
|
|
||||||
return stock_qty
|
return stock_qty[0][0] if stock_qty else 0
|
||||||
|
|
||||||
|
|
||||||
def get_expired_batches(batches):
|
def get_expired_batches(batches):
|
||||||
|
|||||||
Reference in New Issue
Block a user