Merge pull request #39659 from rohitwaghchaure/fixed-timeout-error-while-making-auto-mr
perf: timeout for auto material request through reorder level
This commit is contained in:
commit
675a0b810f
@ -599,7 +599,7 @@ class SellingController(StockController):
|
||||
if self.doctype in ["Sales Order", "Quotation"]:
|
||||
for item in self.items:
|
||||
item.gross_profit = flt(
|
||||
((item.base_rate - item.valuation_rate) * item.stock_qty), self.precision("amount", item)
|
||||
((item.base_rate - flt(item.valuation_rate)) * item.stock_qty), self.precision("amount", item)
|
||||
)
|
||||
|
||||
def set_customer_address(self):
|
||||
|
@ -1785,6 +1785,48 @@ class TestStockEntry(FrappeTestCase):
|
||||
|
||||
self.assertRaises(frappe.ValidationError, se1.cancel)
|
||||
|
||||
def test_auto_reorder_level(self):
|
||||
from erpnext.stock.reorder_item import reorder_item
|
||||
|
||||
item_doc = make_item(
|
||||
"Test Auto Reorder Item - 001",
|
||||
properties={"stock_uom": "Kg", "purchase_uom": "Nos", "is_stock_item": 1},
|
||||
uoms=[{"uom": "Nos", "conversion_factor": 5}],
|
||||
)
|
||||
|
||||
if not frappe.db.exists("Item Reorder", {"parent": item_doc.name}):
|
||||
item_doc.append(
|
||||
"reorder_levels",
|
||||
{
|
||||
"warehouse_reorder_level": 0,
|
||||
"warehouse_reorder_qty": 10,
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"material_request_type": "Purchase",
|
||||
},
|
||||
)
|
||||
|
||||
item_doc.save(ignore_permissions=True)
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "auto_indent", 1)
|
||||
|
||||
mr_list = reorder_item()
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "auto_indent", 0)
|
||||
mrs = frappe.get_all(
|
||||
"Material Request Item",
|
||||
fields=["qty", "stock_uom", "stock_qty"],
|
||||
filters={"item_code": item_doc.name, "uom": "Nos"},
|
||||
)
|
||||
|
||||
for mri in mrs:
|
||||
self.assertEqual(mri.stock_uom, "Kg")
|
||||
self.assertEqual(mri.stock_qty, 10)
|
||||
self.assertEqual(mri.qty, 2)
|
||||
|
||||
for mr in mr_list:
|
||||
mr.cancel()
|
||||
mr.delete()
|
||||
|
||||
|
||||
def make_serialized_item(**args):
|
||||
args = frappe._dict(args)
|
||||
|
@ -86,7 +86,8 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru
|
||||
|
||||
get_party_item_code(args, item, out)
|
||||
|
||||
set_valuation_rate(out, args)
|
||||
if args.get("doctype") in ["Sales Order", "Quotation"]:
|
||||
set_valuation_rate(out, args)
|
||||
|
||||
update_party_blanket_order(args, out)
|
||||
|
||||
@ -269,7 +270,9 @@ def get_basic_details(args, item, overwrite_warehouse=True):
|
||||
if not item:
|
||||
item = frappe.get_doc("Item", args.get("item_code"))
|
||||
|
||||
if item.variant_of and not item.taxes:
|
||||
if (
|
||||
item.variant_of and not item.taxes and frappe.db.exists("Item Tax", {"parent": item.variant_of})
|
||||
):
|
||||
item.update_template_tables()
|
||||
|
||||
item_defaults = get_item_defaults(item.name, args.company)
|
||||
|
@ -34,73 +34,157 @@ def _reorder_item():
|
||||
erpnext.get_default_company() or frappe.db.sql("""select name from tabCompany limit 1""")[0][0]
|
||||
)
|
||||
|
||||
items_to_consider = frappe.db.sql_list(
|
||||
"""select name from `tabItem` item
|
||||
where is_stock_item=1 and has_variants=0
|
||||
and disabled=0
|
||||
and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %(today)s)
|
||||
and (exists (select name from `tabItem Reorder` ir where ir.parent=item.name)
|
||||
or (variant_of is not null and variant_of != ''
|
||||
and exists (select name from `tabItem Reorder` ir where ir.parent=item.variant_of))
|
||||
)""",
|
||||
{"today": nowdate()},
|
||||
)
|
||||
items_to_consider = get_items_for_reorder()
|
||||
|
||||
if not items_to_consider:
|
||||
return
|
||||
|
||||
item_warehouse_projected_qty = get_item_warehouse_projected_qty(items_to_consider)
|
||||
|
||||
def add_to_material_request(
|
||||
item_code, warehouse, reorder_level, reorder_qty, material_request_type, warehouse_group=None
|
||||
):
|
||||
if warehouse not in warehouse_company:
|
||||
def add_to_material_request(**kwargs):
|
||||
if isinstance(kwargs, dict):
|
||||
kwargs = frappe._dict(kwargs)
|
||||
|
||||
if kwargs.warehouse not in warehouse_company:
|
||||
# a disabled warehouse
|
||||
return
|
||||
|
||||
reorder_level = flt(reorder_level)
|
||||
reorder_qty = flt(reorder_qty)
|
||||
reorder_level = flt(kwargs.reorder_level)
|
||||
reorder_qty = flt(kwargs.reorder_qty)
|
||||
|
||||
# projected_qty will be 0 if Bin does not exist
|
||||
if warehouse_group:
|
||||
projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse_group))
|
||||
if kwargs.warehouse_group:
|
||||
projected_qty = flt(
|
||||
item_warehouse_projected_qty.get(kwargs.item_code, {}).get(kwargs.warehouse_group)
|
||||
)
|
||||
else:
|
||||
projected_qty = flt(item_warehouse_projected_qty.get(item_code, {}).get(warehouse))
|
||||
projected_qty = flt(
|
||||
item_warehouse_projected_qty.get(kwargs.item_code, {}).get(kwargs.warehouse)
|
||||
)
|
||||
|
||||
if (reorder_level or reorder_qty) and projected_qty <= reorder_level:
|
||||
deficiency = reorder_level - projected_qty
|
||||
if deficiency > reorder_qty:
|
||||
reorder_qty = deficiency
|
||||
|
||||
company = warehouse_company.get(warehouse) or default_company
|
||||
company = warehouse_company.get(kwargs.warehouse) or default_company
|
||||
|
||||
material_requests[material_request_type].setdefault(company, []).append(
|
||||
{"item_code": item_code, "warehouse": warehouse, "reorder_qty": reorder_qty}
|
||||
material_requests[kwargs.material_request_type].setdefault(company, []).append(
|
||||
{
|
||||
"item_code": kwargs.item_code,
|
||||
"warehouse": kwargs.warehouse,
|
||||
"reorder_qty": reorder_qty,
|
||||
"item_details": kwargs.item_details,
|
||||
}
|
||||
)
|
||||
|
||||
for item_code in items_to_consider:
|
||||
item = frappe.get_doc("Item", item_code)
|
||||
for item_code, reorder_levels in items_to_consider.items():
|
||||
for d in reorder_levels:
|
||||
if d.has_variants:
|
||||
continue
|
||||
|
||||
if item.variant_of and not item.get("reorder_levels"):
|
||||
item.update_template_tables()
|
||||
|
||||
if item.get("reorder_levels"):
|
||||
for d in item.get("reorder_levels"):
|
||||
add_to_material_request(
|
||||
item_code,
|
||||
d.warehouse,
|
||||
d.warehouse_reorder_level,
|
||||
d.warehouse_reorder_qty,
|
||||
d.material_request_type,
|
||||
warehouse_group=d.warehouse_group,
|
||||
)
|
||||
add_to_material_request(
|
||||
item_code=item_code,
|
||||
warehouse=d.warehouse,
|
||||
reorder_level=d.warehouse_reorder_level,
|
||||
reorder_qty=d.warehouse_reorder_qty,
|
||||
material_request_type=d.material_request_type,
|
||||
warehouse_group=d.warehouse_group,
|
||||
item_details=frappe._dict(
|
||||
{
|
||||
"item_code": item_code,
|
||||
"name": item_code,
|
||||
"item_name": d.item_name,
|
||||
"item_group": d.item_group,
|
||||
"brand": d.brand,
|
||||
"description": d.description,
|
||||
"stock_uom": d.stock_uom,
|
||||
"purchase_uom": d.purchase_uom,
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
if material_requests:
|
||||
return create_material_request(material_requests)
|
||||
|
||||
|
||||
def get_items_for_reorder() -> dict[str, list]:
|
||||
reorder_table = frappe.qb.DocType("Item Reorder")
|
||||
item_table = frappe.qb.DocType("Item")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(reorder_table)
|
||||
.inner_join(item_table)
|
||||
.on(reorder_table.parent == item_table.name)
|
||||
.select(
|
||||
reorder_table.warehouse,
|
||||
reorder_table.warehouse_group,
|
||||
reorder_table.material_request_type,
|
||||
reorder_table.warehouse_reorder_level,
|
||||
reorder_table.warehouse_reorder_qty,
|
||||
item_table.name,
|
||||
item_table.stock_uom,
|
||||
item_table.purchase_uom,
|
||||
item_table.description,
|
||||
item_table.item_name,
|
||||
item_table.item_group,
|
||||
item_table.brand,
|
||||
item_table.variant_of,
|
||||
item_table.has_variants,
|
||||
)
|
||||
.where(
|
||||
(item_table.disabled == 0)
|
||||
& (item_table.is_stock_item == 1)
|
||||
& (
|
||||
(item_table.end_of_life.isnull())
|
||||
| (item_table.end_of_life > nowdate())
|
||||
| (item_table.end_of_life == "0000-00-00")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
data = query.run(as_dict=True)
|
||||
itemwise_reorder = frappe._dict({})
|
||||
for d in data:
|
||||
itemwise_reorder.setdefault(d.name, []).append(d)
|
||||
|
||||
itemwise_reorder = get_reorder_levels_for_variants(itemwise_reorder)
|
||||
|
||||
return itemwise_reorder
|
||||
|
||||
|
||||
def get_reorder_levels_for_variants(itemwise_reorder):
|
||||
item_table = frappe.qb.DocType("Item")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(item_table)
|
||||
.select(
|
||||
item_table.name,
|
||||
item_table.variant_of,
|
||||
)
|
||||
.where(
|
||||
(item_table.disabled == 0)
|
||||
& (item_table.is_stock_item == 1)
|
||||
& (
|
||||
(item_table.end_of_life.isnull())
|
||||
| (item_table.end_of_life > nowdate())
|
||||
| (item_table.end_of_life == "0000-00-00")
|
||||
)
|
||||
& (item_table.variant_of.notnull())
|
||||
)
|
||||
)
|
||||
|
||||
variants_item = query.run(as_dict=True)
|
||||
for row in variants_item:
|
||||
if not itemwise_reorder.get(row.name) and itemwise_reorder.get(row.variant_of):
|
||||
itemwise_reorder.setdefault(row.name, []).extend(itemwise_reorder.get(row.variant_of, []))
|
||||
|
||||
return itemwise_reorder
|
||||
|
||||
|
||||
def get_item_warehouse_projected_qty(items_to_consider):
|
||||
item_warehouse_projected_qty = {}
|
||||
items_to_consider = list(items_to_consider.keys())
|
||||
|
||||
for item_code, warehouse, projected_qty in frappe.db.sql(
|
||||
"""select item_code, warehouse, projected_qty
|
||||
@ -164,7 +248,7 @@ def create_material_request(material_requests):
|
||||
|
||||
for d in items:
|
||||
d = frappe._dict(d)
|
||||
item = frappe.get_doc("Item", d.item_code)
|
||||
item = d.get("item_details")
|
||||
uom = item.stock_uom
|
||||
conversion_factor = 1.0
|
||||
|
||||
@ -190,6 +274,7 @@ def create_material_request(material_requests):
|
||||
"item_code": d.item_code,
|
||||
"schedule_date": add_days(nowdate(), cint(item.lead_time_days)),
|
||||
"qty": qty,
|
||||
"conversion_factor": conversion_factor,
|
||||
"uom": uom,
|
||||
"stock_uom": item.stock_uom,
|
||||
"warehouse": d.warehouse,
|
||||
|
Loading…
x
Reference in New Issue
Block a user