feat: purchase order against sales order (#17975)

* feat: purchase order against sales order

* fix: remove unwanted checks

* fix:Related tests
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index f4bb070..26ca7c6 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -107,7 +107,6 @@
 	refresh: function(doc, dt, dn) {
 		var me = this;
 		this._super();
-		var allow_purchase = false;
 		var allow_delivery = false;
 
 		if(doc.docstatus==1) {
@@ -129,28 +128,9 @@
 					   me.frm.cscript.update_status('Re-open', 'Draft')
 				   }, __("Status"));
 			   }
-		    }
+			}
 			if(doc.status !== 'Closed') {
 				if(doc.status !== 'On Hold') {
-					for (var i in this.frm.doc.items) {
-						var item = this.frm.doc.items[i];
-						if(item.delivered_by_supplier === 1 || item.supplier){
-							if(item.qty > flt(item.ordered_qty)
-								&& item.qty > flt(item.delivered_qty)) {
-								allow_purchase = true;
-							}
-						}
-
-						if (item.delivered_by_supplier===0) {
-							if(item.qty > flt(item.delivered_qty)) {
-								allow_delivery = true;
-							}
-						}
-
-						if (allow_delivery && allow_purchase) {
-							break;
-						}
-					}
 
 					if (this.frm.has_perm("submit")) {
 						if(flt(doc.per_delivered, 6) < 100 || flt(doc.per_billed) < 100) {
@@ -180,9 +160,8 @@
 					}
 
 					// make purchase order
-					if(flt(doc.per_delivered, 6) < 100 && allow_purchase) {
 						this.frm.add_custom_button(__('Purchase Order'), () => this.make_purchase_order(), __('Create'));
-					}
+
 					// maintenance
 					if(flt(doc.per_delivered, 2) < 100 &&
 							["Sales", "Shopping Cart"].indexOf(doc.order_type)===-1) {
@@ -543,6 +522,42 @@
 							filters: {'parent': me.frm.doc.name}
 						}
 					}},
+					{fieldname: 'items_for_po', fieldtype: 'Table', label: 'Select Items',
+					fields: [
+						{
+							fieldtype:'Data',
+							fieldname:'item_code',
+							label: __('Item'),
+							read_only:1,
+							in_list_view:1
+						},
+						{
+							fieldtype:'Data',
+							fieldname:'item_name',
+							label: __('Item name'),
+							read_only:1,
+							in_list_view:1
+						},
+						{
+							fieldtype:'Float',
+							fieldname:'qty',
+							label: __('Quantity'),
+							read_only: 1,
+							in_list_view:1
+						},
+						{
+							fieldtype:'Link',
+							read_only:1,
+							fieldname:'uom',
+							label: __('UOM'),
+							in_list_view:1
+						}
+					],
+					data: cur_frm.doc.items,
+					get_data: function() {
+						return cur_frm.doc.items
+					}
+				},
 
 				{"fieldtype": "Button", "label": __('Create Purchase Order'), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
 			]
@@ -550,13 +565,22 @@
 
 		dialog.fields_dict.make_purchase_order.$input.click(function() {
 			var args = dialog.get_values();
+			let selected_items = dialog.fields_dict.items_for_po.grid.get_selected_children()
+			if(selected_items.length == 0) {
+				frappe.throw({message: 'Please select Item form Table', title: __('Message'), indicator:'blue'})
+			}
+			let selected_items_list = []
+			for(let i in selected_items){
+				selected_items_list.push(selected_items[i].item_code)
+			}
 			dialog.hide();
 			return frappe.call({
 				type: "GET",
-				method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
+				method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order",
 				args: {
 					"source_name": me.frm.doc.name,
-					"for_supplier": args.supplier
+					"for_supplier": args.supplier,
+					"selected_items": selected_items_list
 				},
 				freeze: true,
 				callback: function(r) {
@@ -576,6 +600,8 @@
 				}
 			})
 		});
+		dialog.get_field("items_for_po").grid.only_sortable()
+		dialog.get_field("items_for_po").refresh()
 		dialog.show();
 	},
 	hold_sales_order: function(){
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 493da99..8ad3bf0 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -764,7 +764,10 @@
 	return data
 
 @frappe.whitelist()
-def make_purchase_order_for_drop_shipment(source_name, for_supplier=None, target_doc=None):
+def make_purchase_order(source_name, for_supplier=None, selected_items=[], target_doc=None):
+	if isinstance(selected_items, string_types):
+		selected_items = json.loads(selected_items)
+
 	def set_missing_values(source, target):
 		target.supplier = supplier
 		target.apply_discount_on = ""
@@ -843,7 +846,7 @@
 						"price_list_rate"
 					],
 					"postprocess": update_item,
-					"condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == supplier
+					"condition": lambda doc: doc.ordered_qty < doc.qty and doc.supplier == supplier and doc.item_code in selected_items
 				}
 			}, target_doc, set_missing_values)
 			if not for_supplier:
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e7697e2..569c53f 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -449,7 +449,7 @@
 		frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 1)
 
 	def test_drop_shipping(self):
-		from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment
+		from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order
 		from erpnext.buying.doctype.purchase_order.purchase_order import update_status
 
 		make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
@@ -495,7 +495,7 @@
 		so = make_sales_order(item_list=so_items, do_not_submit=True)
 		so.submit()
 
-		po = make_purchase_order_for_drop_shipment(so.name, '_Test Supplier')
+		po = make_purchase_order(so.name, '_Test Supplier', selected_items=[so_items[0]['item_code']])
 		po.submit()
 
 		dn = create_dn_against_so(so.name, delivered_qty=1)