fix: production plan reserved qty incorrect calculation (backport #37400) (#37458)

fix: production plan reserved qty incorrect calculation (#37400)

(cherry picked from commit f3238f9105)

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
This commit is contained in:
mergify[bot]
2023-10-11 14:41:32 +05:30
committed by GitHub
parent fb0b426fe4
commit 573b159541
3 changed files with 21 additions and 27 deletions

View File

@@ -8,7 +8,6 @@ import json
import frappe
from frappe import _, msgprint
from frappe.model.document import Document
from frappe.query_builder import Case
from frappe.query_builder.functions import IfNull, Sum
from frappe.utils import (
add_days,
@@ -1617,21 +1616,13 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
table = frappe.qb.DocType("Production Plan")
child = frappe.qb.DocType("Material Request Plan Item")
completed_production_plans = get_completed_production_plans()
non_completed_production_plans = get_non_completed_production_plans()
case = Case()
query = (
frappe.qb.from_(table)
.inner_join(child)
.on(table.name == child.parent)
.select(
Sum(
child.quantity
* IfNull(
case.when(child.material_request_type == "Purchase", child.conversion_factor).else_(1.0), 1.0
)
)
)
.select(Sum(child.required_bom_qty))
.where(
(table.docstatus == 1)
& (child.item_code == item_code)
@@ -1640,8 +1631,8 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
)
)
if completed_production_plans:
query = query.where(table.name.notin(completed_production_plans))
if non_completed_production_plans:
query = query.where(table.name.isin(non_completed_production_plans))
query = query.run()
@@ -1652,7 +1643,7 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
reserved_qty_for_production = flt(
get_reserved_qty_for_production(
item_code, warehouse, completed_production_plans, check_production_plan=True
item_code, warehouse, non_completed_production_plans, check_production_plan=True
)
)
@@ -1662,7 +1653,7 @@ def get_reserved_qty_for_production_plan(item_code, warehouse):
return reserved_qty_for_production_plan - reserved_qty_for_production
def get_completed_production_plans():
def get_non_completed_production_plans():
table = frappe.qb.DocType("Production Plan")
child = frappe.qb.DocType("Production Plan Item")
@@ -1674,7 +1665,7 @@ def get_completed_production_plans():
.where(
(table.docstatus == 1)
& (table.status.notin(["Completed", "Closed"]))
& (child.ordered_qty >= child.planned_qty)
& (child.planned_qty > child.ordered_qty)
)
).run(as_dict=True)

View File

@@ -6,8 +6,8 @@ from frappe.utils import add_to_date, flt, getdate, now_datetime, nowdate
from erpnext.controllers.item_variant import create_variant
from erpnext.manufacturing.doctype.production_plan.production_plan import (
get_completed_production_plans,
get_items_for_material_requests,
get_non_completed_production_plans,
get_sales_orders,
get_warehouse_list,
)
@@ -1132,9 +1132,9 @@ class TestProductionPlan(FrappeTestCase):
self.assertEqual(after_qty, before_qty)
completed_plans = get_completed_production_plans()
completed_plans = get_non_completed_production_plans()
for plan in plans:
self.assertTrue(plan in completed_plans)
self.assertFalse(plan in completed_plans)
def test_resered_qty_for_production_plan_for_material_requests_with_multi_UOM(self):
from erpnext.stock.utils import get_or_make_bin

View File

@@ -1493,7 +1493,7 @@ def create_pick_list(source_name, target_doc=None, for_qty=None):
def get_reserved_qty_for_production(
item_code: str,
warehouse: str,
completed_production_plans: list = None,
non_completed_production_plans: list = None,
check_production_plan: bool = False,
) -> float:
"""Get total reserved quantity for any item in specified warehouse"""
@@ -1516,19 +1516,22 @@ def get_reserved_qty_for_production(
& (wo_item.parent == wo.name)
& (wo.docstatus == 1)
& (wo_item.source_warehouse == warehouse)
& (wo.status.notin(["Stopped", "Completed", "Closed"]))
& (
(wo_item.required_qty > wo_item.transferred_qty)
| (wo_item.required_qty > wo_item.consumed_qty)
)
)
)
if check_production_plan:
query = query.where(wo.production_plan.isnotnull())
else:
query = query.where(
(wo.status.notin(["Stopped", "Completed", "Closed"]))
& (
(wo_item.required_qty > wo_item.transferred_qty)
| (wo_item.required_qty > wo_item.consumed_qty)
)
)
if completed_production_plans:
query = query.where(wo.production_plan.notin(completed_production_plans))
if non_completed_production_plans:
query = query.where(wo.production_plan.isin(non_completed_production_plans))
return query.run()[0][0] or 0.0