feat: [production_plan -> fetching item description] Fetch item description from Material Request or Sales Order (#19541)

* Change packed item

* Remove description field on update_packed_items

* add possibility to modify description on packed items

* Fetch description from Material Request or Sales Order in production plan, add the possibility to modify the description un production plan

* sync with fork

* Fetch description from Material Request or Sales Order in production plan, Add the possibility to modify description in production plan

* code cleaning syncing fork

* code cleaning syncing fork

* code cleaning syncing fork

* code cleaning syncing fork

* rewied and add item_details.description in case of blank field
This commit is contained in:
MorezMartin 2019-11-12 13:49:01 +01:00 committed by Nabin Hait
parent 29a2e16f62
commit 4fa6194009
2 changed files with 18 additions and 19 deletions

View File

@ -99,7 +99,7 @@ class ProductionPlan(Document):
self.get_mr_items() self.get_mr_items()
def get_so_items(self): def get_so_items(self):
so_list = [d.sales_order for d in self.get("sales_orders", []) if d.sales_order] so_list = [d.sales_order for d in self.sales_orders if d.sales_order]
if not so_list: if not so_list:
msgprint(_("Please enter Sales Orders in the above table")) msgprint(_("Please enter Sales Orders in the above table"))
return [] return []
@ -109,7 +109,7 @@ class ProductionPlan(Document):
item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code)) item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code))
items = frappe.db.sql("""select distinct parent, item_code, warehouse, items = frappe.db.sql("""select distinct parent, item_code, warehouse,
(qty - work_order_qty) * conversion_factor as pending_qty, name (qty - work_order_qty) * conversion_factor as pending_qty, description, name
from `tabSales Order Item` so_item from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and qty > work_order_qty where parent in (%s) and docstatus = 1 and qty > work_order_qty
and exists (select name from `tabBOM` bom where bom.item=so_item.item_code and exists (select name from `tabBOM` bom where bom.item=so_item.item_code
@ -121,7 +121,7 @@ class ProductionPlan(Document):
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse, packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse,
(((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty) (((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty)
as pending_qty, pi.parent_item, so_item.name as pending_qty, pi.parent_item, pi.description, so_item.name
from `tabSales Order Item` so_item, `tabPacked Item` pi from `tabSales Order Item` so_item, `tabPacked Item` pi
where so_item.parent = pi.parent and so_item.docstatus = 1 where so_item.parent = pi.parent and so_item.docstatus = 1
and pi.parent_item = so_item.item_code and pi.parent_item = so_item.item_code
@ -134,7 +134,7 @@ class ProductionPlan(Document):
self.calculate_total_planned_qty() self.calculate_total_planned_qty()
def get_mr_items(self): def get_mr_items(self):
mr_list = [d.material_request for d in self.get("material_requests", []) if d.material_request] mr_list = [d.material_request for d in self.material_requests if d.material_request]
if not mr_list: if not mr_list:
msgprint(_("Please enter Material Requests in the above table")) msgprint(_("Please enter Material Requests in the above table"))
return [] return []
@ -143,7 +143,7 @@ class ProductionPlan(Document):
if self.item_code: if self.item_code:
item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code)) item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code))
items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, description,
(qty - ordered_qty) as pending_qty (qty - ordered_qty) as pending_qty
from `tabMaterial Request Item` mr_item from `tabMaterial Request Item` mr_item
where parent in (%s) and docstatus = 1 and qty > ordered_qty where parent in (%s) and docstatus = 1 and qty > ordered_qty
@ -162,7 +162,7 @@ class ProductionPlan(Document):
'include_exploded_items': 1, 'include_exploded_items': 1,
'warehouse': data.warehouse, 'warehouse': data.warehouse,
'item_code': data.item_code, 'item_code': data.item_code,
'description': item_details and item_details.description or '', 'description': data.description or item_details.description,
'stock_uom': item_details and item_details.stock_uom or '', 'stock_uom': item_details and item_details.stock_uom or '',
'bom_no': item_details and item_details.bom_no or '', 'bom_no': item_details and item_details.bom_no or '',
'planned_qty': data.pending_qty, 'planned_qty': data.pending_qty,
@ -174,10 +174,12 @@ class ProductionPlan(Document):
if self.get_items_from == "Sales Order": if self.get_items_from == "Sales Order":
pi.sales_order = data.parent pi.sales_order = data.parent
pi.sales_order_item = data.name pi.sales_order_item = data.name
pi.description = data.description
elif self.get_items_from == "Material Request": elif self.get_items_from == "Material Request":
pi.material_request = data.parent pi.material_request = data.parent
pi.material_request_item = data.name pi.material_request_item = data.name
pi.description = data.description
def calculate_total_planned_qty(self): def calculate_total_planned_qty(self):
self.total_planned_qty = 0 self.total_planned_qty = 0
@ -195,7 +197,6 @@ class ProductionPlan(Document):
for data in self.po_items: for data in self.po_items:
if data.name == production_plan_item: if data.name == production_plan_item:
data.produced_qty = produced_qty data.produced_qty = produced_qty
data.pending_qty = data.planned_qty - data.produced_qty
data.db_update() data.db_update()
self.calculate_total_produced_qty() self.calculate_total_produced_qty()
@ -302,6 +303,7 @@ class ProductionPlan(Document):
wo_list.extend(work_orders) wo_list.extend(work_orders)
frappe.flags.mute_messages = False frappe.flags.mute_messages = False
if wo_list: if wo_list:
wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \ wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in wo_list] (p, p) for p in wo_list]
@ -309,16 +311,15 @@ class ProductionPlan(Document):
else : else :
msgprint(_("No Work Orders created")) msgprint(_("No Work Orders created"))
def make_work_order_for_sub_assembly_items(self, item): def make_work_order_for_sub_assembly_items(self, item):
work_orders = [] work_orders = []
bom_data = {} bom_data = {}
get_sub_assembly_items(item.get("bom_no"), bom_data, item.get("qty")) get_sub_assembly_items(item.get("bom_no"), bom_data)
for key, data in bom_data.items(): for key, data in bom_data.items():
data.update({ data.update({
'qty': data.get("stock_qty"), 'qty': data.get("stock_qty") * item.get("qty"),
'production_plan': self.name, 'production_plan': self.name,
'company': self.company, 'company': self.company,
'fg_warehouse': item.get("fg_warehouse"), 'fg_warehouse': item.get("fg_warehouse"),
@ -561,7 +562,7 @@ def get_sales_orders(self):
item_filter += " and so_item.item_code = %(item)s" item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql(""" open_so = frappe.db.sql("""
select distinct so.name, so.transaction_date, so.customer, so.base_grand_total as grand_total select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
from `tabSales Order` so, `tabSales Order Item` so_item from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name where so_item.parent = so.name
and so.docstatus = 1 and so.status not in ("Stopped", "Closed") and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
@ -625,7 +626,7 @@ def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None):
for data in po_items: for data in po_items:
planned_qty = data.get('required_qty') or data.get('planned_qty') planned_qty = data.get('required_qty') or data.get('planned_qty')
ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or ignore_existing_ordered_qty ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or ignore_existing_ordered_qty
warehouse = warehouse or data.get("warehouse") warehouse = data.get("warehouse") or warehouse
item_details = {} item_details = {}
if data.get("bom") or data.get("bom_no"): if data.get("bom") or data.get("bom_no"):
@ -708,11 +709,11 @@ def get_item_data(item_code):
return { return {
"bom_no": item_details.get("bom_no"), "bom_no": item_details.get("bom_no"),
"stock_uom": item_details.get("stock_uom"), "stock_uom": item_details.get("stock_uom")
"description": item_details.get("description") # "description": item_details.get("description")
} }
def get_sub_assembly_items(bom_no, bom_data, qty): def get_sub_assembly_items(bom_no, bom_data):
data = get_children('BOM', parent = bom_no) data = get_children('BOM', parent = bom_no)
for d in data: for d in data:
if d.expandable: if d.expandable:
@ -729,6 +730,6 @@ def get_sub_assembly_items(bom_no, bom_data, qty):
}) })
bom_item = bom_data.get(key) bom_item = bom_data.get(key)
bom_item["stock_qty"] += ((d.stock_qty * qty) / d.parent_bom_qty) bom_item["stock_qty"] += d.stock_qty
get_sub_assembly_items(bom_item.get("bom_no"), bom_data, bom_item["stock_qty"]) get_sub_assembly_items(bom_item.get("bom_no"), bom_data)

View File

@ -11,11 +11,9 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import get_sa
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory
class TestProductionPlan(unittest.TestCase): class TestProductionPlan(unittest.TestCase):
def setUp(self): def setUp(self):
set_perpetual_inventory(0)
for item in ['Test Production Item 1', 'Subassembly Item 1', for item in ['Test Production Item 1', 'Subassembly Item 1',
'Raw Material Item 1', 'Raw Material Item 2']: 'Raw Material Item 1', 'Raw Material Item 2']:
create_item(item, valuation_rate=100) create_item(item, valuation_rate=100)