Creating Multiple Purchase Orders at once

I’ve searched here and not found anyone mentioning this so I’m curious if others have a need like this to simplify our process. We might have 15-20 suppliers on one sales order. We currently have to Make>Purchase Order>select ONE supplier>save PO>Submit PO. Then, we start all over back at sales order and do the same process 15-20 times per order.

I would love if I could click one button “generate all purchase orders” and it would complete them all. Then, I could go to purchase order list and click all and save>submit.

It seems the ability to do batches like this is missing unless I’m missing something (which is very likely!).

Thanks for any input.

Hi @charlie-cook

You can use the data import tool to create bulk purchase orders.

I’m not talking about bringing purchase orders in. I’m referring to the process of just creating purchase orders. Create a sales order with multiple suppliers and need to issue purchase orders to each supplier for their products. I have to keep going in and creating them one by one from the sales order. I should be able to click and create all purchase orders, even if just creates them all in draft mode and then I can go in and check them and submit.

Hi @charlie-cook

Ok, got your point, instead of selecting one supplier at a time, you need provision to select all the items and supplier to make multiple purchase orders from the sales order. Right now there is no such feature but we can add this feature in the core module, can you please make github issue?

Got it! Thanks for letting me know. I’ll create an issue. :slight_smile:

1 Like

Hi @charlie-cook

Like @rohit_w said there is no default feature for it currently.

But if you are customising you can do something like this:

  1. Create the list of suppliers in Sales Order (Lets say Child Table)
  2. Create a button or Action in Sales Order doc type say “Create Sales Order”
  3. Write a Hook or API in your custom App, which runs a loop to create PO Dynamically for all the suppliers.
  4. The Child table mentioned above will also need to have QTY, Item information etc, because the system will not understand which items will be provided by which suppliers and in which qty.

Hope it helps.

Regards,

Parth

Issue created: https://github.com/frappe/erpnext/issues/15031

Thanks @szufisher! I’ve been following that pull request!

I wonder how long it will take for us to get this on ERPNext Cloud?

@joshiparthin We’ve got some of this working but can’t get it to loop through all suppliers. Since we are on Cloud, we have some limitations. Any help doing this in py so it loops?

frappe.call({ method: “frappe.client.insert”, args: { doc: doc // doc object }, callback: function® { //callback script } });

@charlie-cook,
if you can not wait till the pull request merged into core and finally available in SAAS, here the pure front end based custom script version of the same feature.

frappe.ui.form.on(“Sales Order”, {
refresh: function(frm, dt, dn) {
var me = this;
var doc = frm.doc
//this._super();
var allow_purchase = false;

	if(doc.docstatus==1) {
		if(doc.status != 'Closed') {

			for (var i in doc.items) {
				var item = 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 (allow_purchase) {
					break;
				}
			}
			// make purchase order
			if(flt(doc.per_delivered, 6) < 100 && allow_purchase) {
				frm.add_custom_button(__('Purchase Order(All)'),
					function() { frm.trigger("make_all_purchase_order") }, __("Make"));
			}
		}
	}
},

make_all_purchase_order: function(){
	var dialog = new frappe.ui.Dialog({
		title: __("For Supplier"),
		fields: [
			{"fieldtype": "Link", "label": __("Supplier"), "fieldname": "supplier", "options":"Supplier",
			 "description": __("Leave the field empty to make purchase orders for all suppliers"),
			"get_query": function () {
				return {
					query:"erpnext.selling.doctype.sales_order.sales_order.get_supplier",
					filters: {'parent': cur_frm.doc.name}
				};
			}},
			{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
		]
	});

	dialog.fields_dict.make_purchase_order.$input.click(function() {
		var args = dialog.get_values();
		var suppliers = [];
		var dfd = new $.Deferred();
		dialog.hide();
		if (args.supplier){
			suppliers.push(args.supplier);
		}
		else{
			(cur_frm.doc["items"] || []).forEach(function(d) {
				var supplier = d["supplier"];
				if(supplier && suppliers.indexOf(supplier)===-1) {
					suppliers.push(supplier);
				}
			});
		}
		frappe.db.get_list("Purchase Order",{filters:{"supplier":["in", suppliers.join(",")],
		"sales_order":cur_frm.doc.name},fields:["supplier"], as_list:true})
			.then(r=>{
				if (r){
					r.forEach(function(d) {
						if (d[0] in suppliers) {
							var index = suppliers.indexOf(d[0]);
							if (index > -1) {
								suppliers.splice(index, 1);
							}
						}
					})						
				}
				dfd.resolve();
			})
		var dfd1 = $.Deferred();
		$.when(dfd).then(r=>{if (suppliers.length === 0){
			frappe.msgprint(__("All Purchase orders created already!"));
                        }
			dfd1.resolve()
		})
		var eachcount=0;
		$.when(dfd1).then(r=>{$.each(suppliers,function(i,supplier){
			frappe.call({
				type: "GET",
				method: "erpnext.selling.doctype.sales_order.sales_order.make_purchase_order_for_drop_shipment",
				args: {
					"source_name": cur_frm.doc.name,
					"for_supplier": supplier
				},
				freeze: true
			}).then(r =>{
				if (!r.exc){
					var cur_doc = frappe.model.sync(r.message);
					cur_doc = cur_doc[0];
					//frappe.call({
					//	method: "frappe.desk.form.save.savedocs",
					//	args: { doc: cur_doc, action: "Save"},
					//	freeze: true
					//}).then(r =>{
					frappe.db.insert(cur_doc).then(r =>{
						eachcount ++;
						if (eachcount>= suppliers.length){
							frappe.msgprint(__("Created " + suppliers.length + " purchase orders"));
							frappe.route_options = {"sales_order":cur_frm.doc.name};
							frappe.set_route("List","Purchase Order");
						}
					});
				}
			});
		});
	})
	});
	dialog.show();
}

});

1 Like

Hello, is there already any tool to do this? In my case this would help a lot. I have both items and product bundles and tens of items in them from different suppliers. When I define a supplier for an item, PO still needs to do manually.