diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index fbb42fe2f64e..fc99d776d4a5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -295,131 +295,12 @@ erpnext.buying.PurchaseOrderController = class PurchaseOrderController extends e } make_stock_entry() { - var items = $.map(cur_frm.doc.items, function(d) { return d.bom ? d.item_code : false; }); - var me = this; - - if(items.length >= 1){ - me.raw_material_data = []; - me.show_dialog = 1; - let title = __('Transfer Material to Supplier'); - let fields = [ - {fieldtype:'Section Break', label: __('Raw Materials')}, - {fieldname: 'sub_con_rm_items', fieldtype: 'Table', label: __('Items'), - fields: [ - { - fieldtype:'Data', - fieldname:'item_code', - label: __('Item'), - read_only:1, - in_list_view:1 - }, - { - fieldtype:'Data', - fieldname:'rm_item_code', - label: __('Raw Material'), - read_only:1, - in_list_view:1 - }, - { - fieldtype:'Float', - read_only:1, - fieldname:'qty', - label: __('Quantity'), - read_only:1, - in_list_view:1 - }, - { - fieldtype:'Data', - read_only:1, - fieldname:'warehouse', - label: __('Reserve Warehouse'), - in_list_view:1 - }, - { - fieldtype:'Float', - read_only:1, - fieldname:'rate', - label: __('Rate'), - hidden:1 - }, - { - fieldtype:'Float', - read_only:1, - fieldname:'amount', - label: __('Amount'), - hidden:1 - }, - { - fieldtype:'Link', - read_only:1, - fieldname:'uom', - label: __('UOM'), - hidden:1 - } - ], - data: me.raw_material_data, - get_data: function() { - return me.raw_material_data; - } - } - ] - - me.dialog = new frappe.ui.Dialog({ - title: title, fields: fields - }); - - if (me.frm.doc['supplied_items']) { - me.frm.doc['supplied_items'].forEach((item, index) => { - if (item.rm_item_code && item.main_item_code && item.required_qty - item.supplied_qty != 0) { - me.raw_material_data.push ({ - 'name':item.name, - 'item_code': item.main_item_code, - 'rm_item_code': item.rm_item_code, - 'item_name': item.rm_item_code, - 'qty': item.required_qty - item.supplied_qty, - 'warehouse':item.reserve_warehouse, - 'rate':item.rate, - 'amount':item.amount, - 'stock_uom':item.stock_uom - }); - me.dialog.fields_dict.sub_con_rm_items.grid.refresh(); - } - }) - } - - me.dialog.get_field('sub_con_rm_items').check_all_rows() - - me.dialog.show() - this.dialog.set_primary_action(__('Transfer'), function() { - me.values = me.dialog.get_values(); - if(me.values) { - me.values.sub_con_rm_items.map((row,i) => { - if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) { - let row_id = i+1; - frappe.throw(__("Item Code, warehouse and quantity are required on row {0}", [row_id])); - } - }) - me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children()) - me.dialog.hide() - } - }); - } - - me.dialog.get_close_btn().on('click', () => { - me.dialog.hide(); - }); - - } - - _make_rm_stock_entry(rm_items) { frappe.call({ method:"erpnext.controllers.subcontracting_controller.make_rm_stock_entry", args: { subcontract_order: cur_frm.doc.name, - rm_items: rm_items, order_doctype: cur_frm.doc.doctype - } - , + }, callback: function(r) { var doclist = frappe.model.sync(r.message); frappe.set_route("Form", doclist[0].doctype, doclist[0].name); diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py index bbd950ed37ad..202a880750e1 100644 --- a/erpnext/controllers/subcontracting_controller.py +++ b/erpnext/controllers/subcontracting_controller.py @@ -770,7 +770,7 @@ def get_item_details(items): item = frappe.qb.DocType("Item") item_list = ( frappe.qb.from_(item) - .select(item.item_code, item.description, item.allow_alternative_item) + .select(item.item_code, item.item_name, item.description, item.allow_alternative_item) .where(item.name.isin(items)) .run(as_dict=True) ) @@ -783,68 +783,93 @@ def get_item_details(items): @frappe.whitelist() -def make_rm_stock_entry(subcontract_order, rm_items, order_doctype="Subcontracting Order"): - rm_items_list = rm_items +def make_rm_stock_entry( + subcontract_order, rm_items=None, order_doctype="Subcontracting Order", target_doc=None +): + if subcontract_order: + subcontract_order = frappe.get_doc(order_doctype, subcontract_order) - if isinstance(rm_items, str): - rm_items_list = json.loads(rm_items) - elif not rm_items: - frappe.throw(_("No Items available for transfer")) + if not rm_items: + if not subcontract_order.supplied_items: + frappe.throw(_("No item available for transfer.")) - if rm_items_list: - fg_items = list(set(item["item_code"] for item in rm_items_list)) - else: - frappe.throw(_("No Items selected for transfer")) + rm_items = subcontract_order.supplied_items - if subcontract_order: - subcontract_order = frappe.get_doc(order_doctype, subcontract_order) + fg_item_code_list = list( + set(item.get("main_item_code") or item.get("item_code") for item in rm_items) + ) - if fg_items: - items = tuple(set(item["rm_item_code"] for item in rm_items_list)) - item_wh = get_item_details(items) + if fg_item_code_list: + rm_item_code_list = tuple(set(item.get("rm_item_code") for item in rm_items)) + item_wh = get_item_details(rm_item_code_list) - stock_entry = frappe.new_doc("Stock Entry") - stock_entry.purpose = "Send to Subcontractor" - if order_doctype == "Purchase Order": - stock_entry.purchase_order = subcontract_order.name - else: - stock_entry.subcontracting_order = subcontract_order.name - stock_entry.supplier = subcontract_order.supplier - stock_entry.supplier_name = subcontract_order.supplier_name - stock_entry.supplier_address = subcontract_order.supplier_address - stock_entry.address_display = subcontract_order.address_display - stock_entry.company = subcontract_order.company - stock_entry.to_warehouse = subcontract_order.supplier_warehouse - stock_entry.set_stock_entry_type() - - if order_doctype == "Purchase Order": - rm_detail_field = "po_detail" - else: - rm_detail_field = "sco_rm_detail" - - for item_code in fg_items: - for rm_item_data in rm_items_list: - if rm_item_data["item_code"] == item_code: - rm_item_code = rm_item_data["rm_item_code"] - items_dict = { - rm_item_code: { - rm_detail_field: rm_item_data.get("name"), - "item_name": rm_item_data["item_name"], - "description": item_wh.get(rm_item_code, {}).get("description", ""), - "qty": rm_item_data["qty"], - "from_warehouse": rm_item_data["warehouse"], - "stock_uom": rm_item_data["stock_uom"], - "serial_no": rm_item_data.get("serial_no"), - "batch_no": rm_item_data.get("batch_no"), - "main_item_code": rm_item_data["item_code"], - "allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"), + field_no_map, rm_detail_field = "purchase_order", "sco_rm_detail" + if order_doctype == "Purchase Order": + field_no_map, rm_detail_field = "subcontracting_order", "po_detail" + + if target_doc and target_doc.get("items"): + target_doc.items = [] + + stock_entry = get_mapped_doc( + order_doctype, + subcontract_order.name, + { + order_doctype: { + "doctype": "Stock Entry", + "field_map": { + "to_warehouse": "supplier_warehouse", + }, + "field_no_map": [field_no_map], + "validation": { + "docstatus": ["=", 1], + }, + }, + }, + target_doc, + ignore_child_tables=True, + ) + + stock_entry.purpose = "Send to Subcontractor" + + if order_doctype == "Purchase Order": + stock_entry.purchase_order = subcontract_order.name + else: + stock_entry.subcontracting_order = subcontract_order.name + + stock_entry.set_stock_entry_type() + + for fg_item_code in fg_item_code_list: + for rm_item in rm_items: + + if rm_item.get("main_item_code") or rm_item.get("item_code") == fg_item_code: + rm_item_code = rm_item.get("rm_item_code") + + items_dict = { + rm_item_code: { + rm_detail_field: rm_item.get("name"), + "item_name": rm_item.get("item_name") + or item_wh.get(rm_item_code, {}).get("item_name", ""), + "description": item_wh.get(rm_item_code, {}).get("description", ""), + "qty": rm_item.get("qty") + or max(rm_item.get("required_qty") - rm_item.get("total_supplied_qty"), 0), + "from_warehouse": rm_item.get("warehouse") or rm_item.get("reserve_warehouse"), + "to_warehouse": subcontract_order.supplier_warehouse, + "stock_uom": rm_item.get("stock_uom"), + "serial_no": rm_item.get("serial_no"), + "batch_no": rm_item.get("batch_no"), + "main_item_code": fg_item_code, + "allow_alternative_item": item_wh.get(rm_item_code, {}).get("allow_alternative_item"), + } } - } - stock_entry.add_to_stock_entry_detail(items_dict) - return stock_entry.as_dict() - else: - frappe.throw(_("No Items selected for transfer")) - return subcontract_order.name + + stock_entry.add_to_stock_entry_detail(items_dict) + + if target_doc: + return stock_entry + else: + return stock_entry.as_dict() + else: + frappe.throw(_("No Items selected for transfer.")) def add_items_in_ste( diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index a952a93ac725..266ea5f674fb 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -625,6 +625,12 @@ frappe.ui.form.on('Stock Entry', { purchase_order: (frm) => { if (frm.doc.purchase_order) { frm.set_value("subcontracting_order", ""); + erpnext.utils.map_current_doc({ + method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontract_order', + source_name: frm.doc.purchase_order, + target_doc: frm, + freeze: true, + }); } }, @@ -632,7 +638,7 @@ frappe.ui.form.on('Stock Entry', { if (frm.doc.subcontracting_order) { frm.set_value("purchase_order", ""); erpnext.utils.map_current_doc({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontracting_order', + method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontract_order', source_name: frm.doc.subcontracting_order, target_doc: frm, freeze: true, diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 62f2acd2fd7f..738ac330e395 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -1945,6 +1945,8 @@ def add_to_stock_entry_detail(self, item_dict, bom_no=None): se_child.is_finished_item = item_row.get("is_finished_item", 0) se_child.is_scrap_item = item_row.get("is_scrap_item", 0) se_child.is_process_loss = item_row.get("is_process_loss", 0) + se_child.po_detail = item_row.get("po_detail") + se_child.sco_rm_detail = item_row.get("sco_rm_detail") for field in [ self.subcontract_data.rm_detail_field, @@ -2591,50 +2593,15 @@ def get_supplied_items( @frappe.whitelist() -def get_items_from_subcontracting_order(source_name, target_doc=None): - def post_process(source, target): - target.stock_entry_type = target.purpose = "Send to Subcontractor" - target.subcontracting_order = source_name +def get_items_from_subcontract_order(source_name, target_doc=None): + from erpnext.controllers.subcontracting_controller import make_rm_stock_entry - if target.items: - target.items = [] + if isinstance(target_doc, str): + target_doc = frappe.get_doc(json.loads(target_doc)) - warehouses = {} - for item in source.items: - warehouses[item.name] = item.warehouse - - for item in source.supplied_items: - target.append( - "items", - { - "s_warehouse": warehouses.get(item.reference_name), - "t_warehouse": source.supplier_warehouse, - "subcontracted_item": item.main_item_code, - "item_code": item.rm_item_code, - "qty": max(item.required_qty - item.total_supplied_qty, 0), - "transfer_qty": item.required_qty, - "uom": item.stock_uom, - "stock_uom": item.stock_uom, - "conversion_factor": 1, - "sco_rm_detail": item.name, - }, - ) - - target_doc = get_mapped_doc( - "Subcontracting Order", - source_name, - { - "Subcontracting Order": { - "doctype": "Stock Entry", - "field_no_map": ["purchase_order"], - "validation": { - "docstatus": ["=", 1], - }, - }, - }, - target_doc, - post_process, - ignore_child_tables=True, + order_doctype = "Purchase Order" if target_doc.purchase_order else "Subcontracting Order" + target_doc = make_rm_stock_entry( + subcontract_order=source_name, order_doctype=order_doctype, target_doc=target_doc ) return target_doc diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js index 40963f863730..15a2ac909127 100644 --- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js +++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js @@ -205,20 +205,10 @@ erpnext.buying.SubcontractingOrderController = class SubcontractingOrderControll } make_stock_entry() { - frappe.model.open_mapped_doc({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_items_from_subcontracting_order', - source_name: cur_frm.doc.name, - freeze: true, - freeze_message: __('Creating Stock Entry ...') - }); - } - - make_rm_stock_entry(rm_items) { frappe.call({ method: 'erpnext.controllers.subcontracting_controller.make_rm_stock_entry', args: { subcontract_order: cur_frm.doc.name, - rm_items: rm_items, order_doctype: cur_frm.doc.doctype }, callback: (r) => {