Merge pull request #29723 from frappe/mergify/copy/version-13-hotfix/pr-29715

fix: Reserved for Production calculation considered closed work orders (copy #29715)
This commit is contained in:
Ankush Menat
2022-02-09 15:59:23 +05:30
committed by GitHub
5 changed files with 73 additions and 17 deletions

View File

@@ -198,6 +198,21 @@ class TestWorkOrder(ERPNextTestCase):
self.assertEqual(cint(bin1_on_end_production.reserved_qty_for_production),
cint(bin1_on_start_production.reserved_qty_for_production))
def test_reserved_qty_for_production_closed(self):
wo1 = make_wo_order_test_record(item="_Test FG Item", qty=2,
source_warehouse=self.warehouse)
item = wo1.required_items[0].item_code
bin_before = get_bin(item, self.warehouse)
bin_before.update_reserved_qty_for_production()
make_wo_order_test_record(item="_Test FG Item", qty=2,
source_warehouse=self.warehouse)
close_work_order(wo1.name, "Closed")
bin_after = get_bin(item, self.warehouse)
self.assertEqual(bin_before.reserved_qty_for_production, bin_after.reserved_qty_for_production)
def test_backflush_qty_for_overpduction_manufacture(self):
cancel_stock_entry = []
allow_overproduction("overproduction_percentage_for_work_order", 30)

View File

@@ -8,6 +8,8 @@ from dateutil.relativedelta import relativedelta
from frappe import _
from frappe.model.document import Document
from frappe.model.mapper import get_mapped_doc
from frappe.query_builder import Case
from frappe.query_builder.functions import Sum
from frappe.utils import (
cint,
date_diff,
@@ -1171,3 +1173,27 @@ def create_pick_list(source_name, target_doc=None, for_qty=None):
doc.set_item_locations()
return doc
def get_reserved_qty_for_production(item_code: str, warehouse: str) -> float:
"""Get total reserved quantity for any item in specified warehouse"""
wo = frappe.qb.DocType("Work Order")
wo_item = frappe.qb.DocType("Work Order Item")
return (
frappe.qb
.from_(wo)
.from_(wo_item)
.select(Sum(Case()
.when(wo.skip_transfer == 0, wo_item.required_qty - wo_item.transferred_qty)
.else_(wo_item.required_qty - wo_item.consumed_qty))
)
.where(
(wo_item.item_code == item_code)
& (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))
)
).run()[0][0] or 0.0

View File

@@ -347,4 +347,5 @@ erpnext.patches.v13_0.hospitality_deprecation_warning
erpnext.patches.v13_0.delete_bank_reconciliation_detail
erpnext.patches.v13_0.update_sane_transfer_against
erpnext.patches.v13_0.enable_provisional_accounting
erpnext.patches.v13_0.update_disbursement_account
erpnext.patches.v13_0.update_disbursement_account
erpnext.patches.v13_0.update_reserved_qty_closed_wo

View File

@@ -0,0 +1,28 @@
import frappe
from erpnext.stock.utils import get_bin
def execute():
wo = frappe.qb.DocType("Work Order")
wo_item = frappe.qb.DocType("Work Order Item")
incorrect_item_wh = (
frappe.qb
.from_(wo)
.join(wo_item).on(wo.name == wo_item.parent)
.select(wo_item.item_code, wo.source_warehouse).distinct()
.where(
(wo.status == "Closed")
& (wo.docstatus == 1)
& (wo.source_warehouse.notnull())
)
).run()
for item_code, warehouse in incorrect_item_wh:
if not (item_code and warehouse):
continue
bin = get_bin(item_code, warehouse)
bin.update_reserved_qty_for_production()

View File

@@ -31,23 +31,9 @@ class Bin(Document):
def update_reserved_qty_for_production(self):
'''Update qty reserved for production from Production Item tables
in open work orders'''
self.reserved_qty_for_production = frappe.db.sql('''
SELECT
SUM(CASE WHEN ifnull(skip_transfer, 0) = 0 THEN
item.required_qty - item.transferred_qty
ELSE
item.required_qty - item.consumed_qty END)
END
FROM `tabWork Order` pro, `tabWork Order Item` item
WHERE
item.item_code = %s
and item.parent = pro.name
and pro.docstatus = 1
and item.source_warehouse = %s
and pro.status not in ("Stopped", "Completed")
and (item.required_qty > item.transferred_qty or item.required_qty > item.consumed_qty)
''', (self.item_code, self.warehouse))[0][0]
from erpnext.manufacturing.doctype.work_order.work_order import get_reserved_qty_for_production
self.reserved_qty_for_production = get_reserved_qty_for_production(self.item_code, self.warehouse)
self.set_projected_qty()
self.db_set('reserved_qty_for_production', flt(self.reserved_qty_for_production))