Custom script to create product bundle from all purchase invoice items

I have a case where, in the process of providing a service to a customer like repairing or installation, materials purchased are to be directly billed to customers. While purchasing, the company will pay, but ultimately the supplier invoice must be forwarded to the customer while charging them the exact supplier bill amount. That being the case, sales invoice will not contain the items of purchase invoice from the suppliers but only references to the suppliers’ purchase invoice so that we may account receivables for the invoices instead of materials.

The problem is the purchase invoices needs to be processed for inventory purposes, to confirm the orders and receipt of the materials, but the sales invoice won’t be accounting for the said materials.

The best idea I could think of is make a product bundle for each of purchase invoices involved, and then adding the product bundles on customer’s sales invoice. However, is there a script that can automate this? I’m not quite sure how to script or get started with them.

Otherwise, if you’ve any better suggestion for described situation, please feel free to comment.

@mrmo, I tried your script, but it didn’t work:

The Purchase Invoice script that I made also didn’t work:

 frappe.ui.form.on("Purchase Invoice", "on_submit", function(frm, cdt, cdn) {
   bundle = frappe.model.get_doc({
	"doctype": "Product Bundle",
	"title": frm.bill_no,
	"status": "Open"
   $.each(pi.items, function(index, row){
      d = bundle.add_child("items");
      d.item_code = row.item_code;
      d.qty = row.qty;
      d.description = row.description;

Okay, I figured it out, with some help from other guides here in the forum. Please check my sample below.
I have tested it locally and it worked. Please keep in mind that you need a Parent Item in the Product Bundle for it to work correctly.

See this link for more details.

Any question, feel free to ask.

frappe.ui.form.on("Purchase Invoice", "on_submit", function(frm) {
    let pi = []
        $.each(frm.doc.items || [], function(i, row) {
                doctype: "Product Bundle",
                new_item_code: "Link to Parent Item",
                description: frm.doc.bill_no,
                items: [
                        item_code: row.item_code,
                        qty: row.qty,
                        description: row.description,
    const func = => {{
            method: "frappe.client.insert",
            args: {
                doc: doc // doc object
            callback: function(r) {}

    Promise.all(func).then(() => {
        console.log("Product Bundle Created!");
1 Like

Parent Item? Oh my God, I just realized what I wanted to do was make a Parent Item and Bundle at the same time. Until now, I was under the impression the Bundle itself is the item specified on invoices, FML. This is getting way too convoluted.