Repository: frappe/erpnext
Pull request: feat: Bulk Transaction Processing
**Before this Feature**
Lets take an example to get better idea
1. If the user had to create multiple sales invoice from multiple sales order it had to be done one by one by going into the   particular sales order and then create sales invoice against it which consumed a lot of time.Similarly this was the case for many doctype's for which creating multiple docs from multiple docs was time consuming.
2. Problem was identified from this issue #28229 


**Tasks**
- [x] Notification to the user when job is completed and some minor tasks.
- [x] Add Logger For Transactions
- [x] Tests
- [x] Increase Code Coverage for codecov/project

Following operations can be performed in bulk:

<img width="934" alt="Screenshot 2021-11-26 at 1 49 25 PM" src="https://user-images.githubusercontent.com/49878143/143549419-17367ca7-82e5-4ea4-9abb-2a37656e56c1.png">


**After this Feature**
1. To tackle this problem options are added into the actions menu. so when the user selects multiple invoices/orders the actions menu button appears from which user can select the bulk operation to be performed. thus saving a lot of time.
2. Since creation of multiple invoices/orders can take a lot of time it should not block user from doing other operations. so if there are more than 10 invoices/orders it will create a background job for the same.
3.  There might be situation where in while bulk creating of invoices/orders some exceptions might occur which might halt the creation of invoices/orders. There is a mechanism to bypass failing invoices/orders and continue forward creating other invoices/orders in the queue.

![bulk_transaction_processing](https://user-images.githubusercontent.com/49878143/143548448-950dad99-e7c5-4ad9-a8f5-9b690637cbc1.gif)


Problem statement:
Bulk Transaction Processing
Problem Statement:
Allow to create bulk transactions to process multiple invoices/DN from Sales Order. Likewise for other common flows (PR/PI from PO).

Expected Solution:
Use bulk actions in list view to give options to create transactions in one go. This will save time in processing multiple transactions as opposed to one by one by UI, or Excel import.

Hints from issue discussion:

Commit message: fix: add flags to ignore validations and exception handling correction

Patch to review:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
index f6ff83add8c5..be6600ad9b17 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js
@@ -56,4 +56,42 @@ frappe.listview_settings["Purchase Invoice"] = {
 			];
 		}
 	},
+
+	onload: function(listview) {
+		listview.page.add_action_item(__("Purchase Receipt"), ()=>{
+		    checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+		    frappe.confirm(__("Create {0} Purchase Receipt ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Purchase Receipt From Purchase Invoice"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} purchase receipt`,count_of_rows);
+				}
+		    })
+		});
+
+		listview.page.add_action_item(__("Payment"), ()=>{
+		    checked_items = listview.get_checked_items();
+		    count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Make {0} Payment ?", [count_of_rows]),()=>{
+		        frappe.call({
+		        method:"erpnext.utilities.bulk_transaction.transaction_processing",
+		        args: {data: checked_items, to_create: "Payment From Purchase Invoice"}
+		        }).then(r => {
+		        console.log(r);
+		        })
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} payment`,count_of_rows);
+				}
+		    })
+		});
+	}
 };
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
index 06e6f5118397..954e55136d99 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js
@@ -21,5 +21,43 @@ frappe.listview_settings['Sales Invoice'] = {
 		};
 		return [__(doc.status), status_colors[doc.status], "status,=,"+doc.status];
 	},
-	right_column: "grand_total"
+	right_column: "grand_total",
+
+	onload: function(listview) {
+		listview.page.add_action_item(__("Delivery Note"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Delivery Note ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Delivery Note From Sales Invoice"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} delivery note`,count_of_rows);
+				}
+			})
+		});
+
+		listview.page.add_action_item(__("Payment"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Make {0} Payment ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Payment From Sales Invoice"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} payment`,count_of_rows);
+				}
+			})
+		});
+	}
 };
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_list.js b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
index 8413eb65c3f1..dc81a79465fe 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_list.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_list.js
@@ -29,8 +29,61 @@ frappe.listview_settings['Purchase Order'] = {
 			listview.call_for_selected_items(method, { "status": "Closed" });
 		});
 
-		listview.page.add_menu_item(__("Re-open"), function () {
+		listview.page.add_menu_item(__("Reopen"), function () {
 			listview.call_for_selected_items(method, { "status": "Submitted" });
 		});
+
+
+		listview.page.add_action_item(__("Purchase Invoice"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Purchase Invoice ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Purchase Invoice From Purchase Order"}
+					}).then(r => {
+						console.log(r);
+						frappe.show_alert("Purchase Invoice Created Successfully !",5);
+					})
+			})
+		});
+
+		listview.page.add_action_item(__("Purchase Receipt"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Purchase Receipt ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Purchase Receipt From Purchase Order"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} purchase receipt`,count_of_rows);
+				}
+			})
+		});
+
+		listview.page.add_action_item(__("Advance Payment"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Make {0} Advance Payment ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Advance Payment From Purchase Order"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} advance payment`,count_of_rows);
+				}
+			})
+		});
+
 	}
 };
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index d65ab94a6d3a..171de7882dce 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -142,6 +142,26 @@ def update_item(obj, target, source_parent):
 
 	return doclist
 
+@frappe.whitelist()
+def make_purchase_invoice(source_name, target_doc=None):
+	doc = get_mapped_doc("Supplier Quotation", source_name, {
+		"Supplier Quotation": {
+			"doctype": "Purchase Invoice",
+			"validation": {
+				"docstatus": ["=", 1],
+			}
+		},
+		"Supplier Quotation Item": {
+			"doctype": "Purchase Invoice Item"
+		},
+		"Purchase Taxes and Charges": {
+			"doctype": "Purchase Taxes and Charges"
+		}
+	}, target_doc)
+
+	return doc
+
+
 @frappe.whitelist()
 def make_quotation(source_name, target_doc=None):
 	doclist = get_mapped_doc("Supplier Quotation", source_name, {
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
index 5ab6c980d00e..8fcbe129c4f6 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
@@ -8,5 +8,42 @@ frappe.listview_settings['Supplier Quotation'] = {
 		} else if(doc.status==="Expired") {
 			return [__("Expired"), "gray", "status,=,Expired"];
 		}
+	},
+
+	onload: function(listview){
+		listview.page.add_action_item(__("Purchase Order"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Purchase Order ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Purchase Order From Supplier Quotation"}
+				}).then(r => {
+					console.log(r);
+				})
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} purchase order`,count_of_rows);
+				}
+			});
+		});
+
+		listview.page.add_action_item(__("Purchase Invoice"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Purchase Invoice ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Purchase Invoice From Supplier Quotation"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} purchase invoice`,count_of_rows);
+				}
+			});
+		});
 	}
 };
diff --git a/erpnext/selling/doctype/quotation/quotation_list.js b/erpnext/selling/doctype/quotation/quotation_list.js
index b631685bd19b..995f9154f359 100644
--- a/erpnext/selling/doctype/quotation/quotation_list.js
+++ b/erpnext/selling/doctype/quotation/quotation_list.js
@@ -12,6 +12,41 @@ frappe.listview_settings['Quotation'] = {
 				};
 			};
 		}
+
+		listview.page.add_action_item(__("Sales Order"),()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Sales Order ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Sales Order From Quotation"}
+				}).then(r => {
+					console.log(r);
+				})
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background to create ${count_of_rows} sales order`,count_of_rows);
+				}
+			})
+		});
+
+		listview.page.add_action_item(__("Sales Invoice"),()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+
+			frappe.confirm(__("Create {0} Sales Invoice ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Sales Invoice From Quotation"}
+				}).then(r => {
+					console.log(r);
+				})
+			if(count_of_rows > 10){
+				frappe.show_alert(`Starting a background to create ${count_of_rows} sales invoice`,count_of_rows);
+			}
+
+			})
+		});
 	},
 
 	get_indicator: function(doc) {
diff --git a/erpnext/selling/doctype/sales_order/sales_order_list.js b/erpnext/selling/doctype/sales_order/sales_order_list.js
index 26d96d59f299..e0b51732e3e8 100644
--- a/erpnext/selling/doctype/sales_order/sales_order_list.js
+++ b/erpnext/selling/doctype/sales_order/sales_order_list.js
@@ -16,7 +16,7 @@ frappe.listview_settings['Sales Order'] = {
 				return [__("Overdue"), "red",
 					"per_delivered,<,100|delivery_date,<,Today|status,!=,Closed"];
 			} else if (flt(doc.grand_total) === 0) {
-				// not delivered (zero-amount order)
+				// not delivered (zeroount order)
 				return [__("To Deliver"), "orange",
 					"per_delivered,<,100|grand_total,=,0|status,!=,Closed"];
 			} else if (flt(doc.per_billed, 6) < 100) {
@@ -48,5 +48,53 @@ frappe.listview_settings['Sales Order'] = {
 			listview.call_for_selected_items(method, {"status": "Submitted"});
 		});
 
+		listview.page.add_action_item(__("Sales Invoice"),()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+			frappe.confirm(__("Create {0} Sales Invoice ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Sales Invoice From Sales Order"}
+				}).then(r => {
+					console.log(r);
+				})
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} sales invoice`,count_of_rows);
+				}
+			})
+		});
+
+		listview.page.add_action_item(__("Delivery Note"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+			frappe.confirm(__("Create {0} Delivery Note ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Delivery Note From Sales Order"}
+					}).then(r => {
+						console.log(r);
+					})
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background to create ${count_of_rows} delivery note`,count_of_rows);
+				}
+			})
+		})
+
+		listview.page.add_action_item(__("Advance Payment"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+			frappe.confirm(__("Create {0} Advance Payment ?", [count_of_rows]),()=>{
+				frappe.call({
+					method:"erpnext.utilities.bulk_transaction.transaction_processing",
+					args: {data: checked_items, to_create: "Advance Payment From Sales Order"}
+				}).then(r => {
+					console.log(r);
+				})
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} Advance Payment`,count_of_rows);
+				}
+			})
+		})
+
 	}
 };
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 52684607b4ba..66acec166795 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -580,7 +580,18 @@ def make_packing_slip(source_name, target_doc=None):
 			"validation": {
 				"docstatus": ["=", 0]
 			}
+		},
+
+		"Delivery Note Item":{
+		"doctype": "Packing Slip Item",
+		"field_map": {
+			"item_code": "item_code",
+			"item_name": "item_name",
+			"description": "description",
+			"qty": "qty",
 		}
+		}
+
 	}, target_doc)
 
 	return doclist
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index 040289804733..5754c7c8d299 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -14,7 +14,7 @@ frappe.listview_settings['Delivery Note'] = {
 			return [__("Completed"), "green", "per_billed,=,100"];
 		}
 	},
-	onload: function (doclist) {
+	onload: function (listview) {
 		const action = () => {
 			const selected_docs = doclist.get_checked_items();
 			const docnames = doclist.get_checked_items(true);
@@ -54,6 +54,42 @@ frappe.listview_settings['Delivery Note'] = {
 			};
 		};
 
-		doclist.page.add_actions_menu_item(__('Create Delivery Trip'), action, false);
+		// doclist.page.add_actions_menu_item(__('Create Delivery Trip'), action, false);
+
+		listview.page.add_action_item(__('Create Delivery Trip'), action);
+
+		listview.page.add_action_item(__("Sales Invoice"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+			frappe.confirm(__("Create {0} Sales Invoice ?", [count_of_rows]),()=>{
+			frappe.call({
+				method:"erpnext.utilities.bulk_transaction.transaction_processing",
+				args: {data: checked_items, to_create: "Sales Invoice From Delivery Note"}
+				}).then(r => {
+					console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} sales invoice`,count_of_rows);
+				}
+			})
+		});
+
+		listview.page.add_action_item(__("Packaging Slip From Delivery Note"), ()=>{
+			checked_items = listview.get_checked_items();
+			count_of_rows = checked_items.length;
+			frappe.confirm(__("Create {0} Packaging Slip ?", [count_of_rows]),()=>{
+			frappe.call({
+				method:"erpnext.utilities.bulk_transaction.transaction_processing",
+				args: {data: checked_items, to_create: "Packaging Slip"}
+				}).then(r => {
+						console.log(r);
+				})
+
+				if(count_of_rows > 10){
+					frappe.show_alert(`Starting a background job to create ${count_of_rows} packing slip`,count_of_rows);
+				}
+			})
+		});
 	}
 };
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index 77711de93f7e..0840b9855eb3 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -13,5 +13,27 @@ frappe.listview_settings['Purchase Receipt'] = {
 		} else if (flt(doc.grand_total) === 0 || flt(doc.per_billed, 2) === 100) {
 			return [__("Completed"), "green", "per_billed,=,100"];
 		}
+	},
+
+	onload: function(listview){
+
+	listview.page.add_action_item(__("Purchase Invoice"), ()=>{
+		checked_items = listview.get_checked_items();
+		count_of_rows = checked_items.length;
+
+		frappe.confirm(__("Create {0} Purchase Invoice ?", [count_of_rows]),()=>{
+			frappe.call({
+			method:"erpnext.utilities.bulk_transaction.transaction_processing",
+			args: {data: checked_items, to_create: "Purchase Invoice From Purchase Receipt"}
+			}).then(r => {
+			console.log(r);
+			})
+
+			if(count_of_rows > 10){
+				frappe.show_alert(`Starting a background job to create ${count_of_rows} purchase invoice`,count_of_rows);
+			}
+		})
+		});
 	}
+
 };
diff --git a/erpnext/utilities/bulk_transaction.py b/erpnext/utilities/bulk_transaction.py
new file mode 100644
index 000000000000..c4695a89bd07
--- /dev/null
+++ b/erpnext/utilities/bulk_transaction.py
@@ -0,0 +1,128 @@
+import json
+
+import frappe
+
+
+@frappe.whitelist()
+def transaction_processing(data, to_create):
+	deserialized_data = json.loads(data)
+	length_of_data = len(deserialized_data)
+
+	if length_of_data > 10:
+		# frappe.msgprint("Started a background job to create {1} {0}".format(to_create,length_of_data))
+		frappe.enqueue(job, deserialized_data=deserialized_data, to_create=to_create)
+	else:
+		job(deserialized_data, to_create)
+
+def job(deserialized_data, to_create):
+	from erpnext.accounts.doctype.payment_entry import payment_entry
+	from erpnext.accounts.doctype.purchase_invoice import purchase_invoice
+	from erpnext.accounts.doctype.sales_invoice import sales_invoice
+	from erpnext.buying.doctype.purchase_order import purchase_order
+	from erpnext.buying.doctype.supplier_quotation import supplier_quotation
+	from erpnext.selling.doctype.quotation import quotation
+	from erpnext.selling.doctype.sales_order import sales_order
+	from erpnext.stock.doctype.delivery_note import delivery_note
+	from erpnext.stock.doctype.purchase_receipt import purchase_receipt
+
+	i = 0
+	for d in deserialized_data:
+		try:
+			i+=1
+
+			# From Sales Order
+			if to_create == "Sales Invoice From Sales Order":
+				si = sales_order.make_sales_invoice(d.get('name'))
+				si.flags.ignore_validate = True
+				si.insert(ignore_mandatory=True)
+
+			if to_create == "Delivery Note From Sales Order":
+				dn_so = sales_order.make_delivery_note(d.get('name'))
+				si.flags.ignore_validate = True
+				dn_so.insert(ignore_mandatory=True)
+
+			if to_create == "Advance Payment From Sales Order":
+				ap_so = payment_entry.get_payment_entry("Sales Order", d.get('name'))
+				ap_so.flags.ignore_validate = True
+				ap_so.insert(ignore_mandatory=True)
+
+			# From Sales Invoice
+			if to_create == "Delivery Note From Sales Invoice":
+				dn_si = sales_invoice.make_delivery_note(d.get('name'))
+				dn_si.flags.ignore_validate = True
+				dn_si.insert(ignore_mandatory=True)
+
+			if to_create == "Payment Sales Invoice":
+				p_si = payment_entry.get_payment_entry("Sales Invoice", d.get('name'))
+				p_si.flags.ignore_validate = True
+				p_si.insert(ignore_mandatory=True)
+
+			# From Delivery Note
+			if to_create == "Sales Invoice From Delivery Note":
+				si_from_dn = delivery_note.make_sales_invoice(d.get('name'))
+				si_from_dn.flags.ignore_validate = True
+				si_from_dn.insert(ignore_mandatory=True)
+
+			if to_create == "Packaging Slip From Delivery Note":
+				ps  = delivery_note.make_packing_slip(d.get('name'))
+				ps.flags.ignore_validate = True
+				ps.insert(ignore_mandatory=True)
+
+			# From Quotation
+			if to_create == "Sales Order From Quotation":
+				so_qtn = quotation._make_sales_order(d.get('name'))
+				so_qtn.flags.ignore_validate = True
+				so_qtn.insert(ignore_mandatory=True)
+
+			if to_create == "Sales Invoice From Quotation":
+				si_qtn = quotation._make_sales_invoice(d.get('name'))
+				si_qtn.flags.ignore_validate = True
+				si_qtn.insert(ignore_mandatory=True)
+
+			# From Supplier Quotation
+			if to_create == "Purchase Order From Supplier Quotation":
+				po_sq = supplier_quotation.make_purchase_order(d.get('name'))
+				po_sq.flags.ignore_validate = True
+				po_sq.insert(ignore_mandatory=True)
+
+			if to_create == "Purchase Invoice From Supplier Quotation":
+				# created method to create purchase invoice from supplier quotation
+				pi_sq = supplier_quotation.make_purchase_invoice(d.get('name'))
+				pi_sq.flags.ignonre_validate = True
+				pi_sq.insert(ignore_mandatory=True)
+
+			# From Purchase Order
+			if to_create == "Purchase Invoice From Purchase Order":
+				pi_po = purchase_order.get_mapped_purchase_invoice(d.get('name'))
+				pi_po.flags.ignore_validate = True
+				pi_po.insert(ignore_mandatory=True)
+
+			if to_create == "Purchase Receipt From Purchase Order":
+				pr_po = purchase_order.make_purchase_receipt(d.get('name'))
+				pr_po.flags.ignore_validate = True
+				pr_po.insert(ignore_mandatory=True)
+
+			if to_create == "Advance Payment From Purchase Order":
+				ap_po = payment_entry.get_payment_entry("Purchase Order", d.get('name'))
+				ap_po.flags.ignore_validate = True
+				ap_po.insert(ignore_mandatory=True)
+
+			# From Purchase Invoice
+			if to_create == "Purchase Receipt From Purchase Invoice":
+				pr_pi = purchase_invoice.make_purchase_receipt(d.get('name'))
+				pr_pi.flags.ignore_valdiate = True
+				pr_pi.insert(ignore_mandatory=True)
+
+			if to_create == "Payment Purchase Invoice":
+				p_pi = payment_entry.get_payment_entry("Purchase Invoice", d.get("name"))
+				p_pi.flags.ignore_validate = True
+				p_pi.insert(ignore_mandatory=True)
+
+			# From Purchase Receipt
+			if to_create == "Purchase Invoice From Purchase Receipt":
+				pr_pi = purchase_receipt.make_purchase_invoice(d.get('name'))
+				pr_pi.flags.ignore_validate = True
+				pr_pi.insert(ignore_mandatory=True)
+
+		except Exception as e:
+			frappe.msgprint("Error while creating {1} from {0}".format(d.get('name'), to_create), title="Invoice Creation Failed")


Code review comments:
diff_hunk: @@ -0,0 +1,128 @@
+import json
+
+import frappe
+
+
+@frappe.whitelist()
+def transaction_processing(data, to_create):
+	deserialized_data = json.loads(data)
+	length_of_data = len(deserialized_data)
+
+	if length_of_data > 10:
+		# frappe.msgprint("Started a background job to create {1} {0}".format(to_create,length_of_data))
+		frappe.enqueue(job, deserialized_data=deserialized_data, to_create=to_create)
+	else:
+		job(deserialized_data, to_create)
+
+def job(deserialized_data, to_create):
+	from erpnext.accounts.doctype.payment_entry import payment_entry
+	from erpnext.accounts.doctype.purchase_invoice import purchase_invoice
+	from erpnext.accounts.doctype.sales_invoice import sales_invoice
+	from erpnext.buying.doctype.purchase_order import purchase_order
+	from erpnext.buying.doctype.supplier_quotation import supplier_quotation
+	from erpnext.selling.doctype.quotation import quotation
+	from erpnext.selling.doctype.sales_order import sales_order
+	from erpnext.stock.doctype.delivery_note import delivery_note
+	from erpnext.stock.doctype.purchase_receipt import purchase_receipt
+
+	i = 0
+	for d in deserialized_data:
+		try:
+			i+=1
+
+			# From Sales Order
+			if to_create == "Sales Invoice From Sales Order":
path: erpnext/utilities/bulk_transaction.py
text: @user1:
Too much code duplication here?

Python allows treating functions as first class objects, just create a mapping like this instead: 


`Tuple[from_doctype, to_doctype] -> Function`


If a particular function needs non-standard or extra default arguments you can create a partial function: https://docs.python.org/3/library/functools.html#functools.partial