Client Script in Erpnext

Could you please review this custom client script , the purpose is to fetch child table data from Purchase Order and populate it in a Payment Request child table The data is populating correctly, but I’m encountering an issue where I can’t proceed to submit the form after saving. The submit button briefly appears, but then reverts back to the save option. Could you please assist me in resolving this issue? Your help is greatly appreciated. Thank you.

#frappe.ui.form.on("Payment Request", {
    refresh: function(frm) {
        console.log("Payment Request form refreshed");
        // Function to fetch Purchase Order Items and add them as child documents
        function fetchPurchaseOrderItems() {
            console.log("Fetching Purchase Order Items");
            if (frm.doc.reference_doctype === "Purchase Order" && frm.doc.reference_name) {
                frappe.call({
                    method: "frappe.client.get",
                    args: {
                        doctype: "Purchase Order",
                        name: frm.doc.reference_name
                    },
                    callback: function(response) {
                        console.log("Purchase Order API callback invoked");
                        var purchase_order = response.message;
                        if (purchase_order && purchase_order.items) {
                            // Clear the child table
                            frm.clear_table("request_payment");
                            console.log("Child table cleared");

                            // Populate fields in the child table
                            purchase_order.items.forEach(function(item) {
                                var child_row = frappe.model.add_child(frm.doc, "Payment Request 
    Item", "request_payment");
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "item_name", item.item_name);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "amount", item.amount);
                                frappe.model.set_value(child_row.doctype, child_row.name, "rate", 
     item.rate);
                                frappe.model.set_value(child_row.doctype, child_row.name, "qty", 
     item.qty);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
     "item_code", item.item_code);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "description", item.description);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
     "stock_uom", item.stock_uom);
                                frappe.model.set_value(child_row.doctype, child_row.name, "uom", 
    item.uom);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "conversion_factor", item.conversion_factor);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "base_rate", item.base_rate);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "base_amount", item.base_amount);
                                frappe.model.set_value(child_row.doctype, child_row.name, 
    "total", item.amount);
                                frappe.model.set_value(child_row.doctype, child_row.name,    
    "schedule_date", item.schedule_date);
                                // Set other fields as needed
                            });
                            console.log("Child table populated");
                            frm.refresh_field("request_payment");
                            console.log("Child table refreshed");
                        }
                    }
                });
            }
        }
        // Fetch Purchase Order Items on form refresh
        fetchPurchaseOrderItems();
        console.log("fetchPurchaseOrderItems function called");

        // Re-fetch Purchase Order Items when the "Reference Document" field changes
        frm.set_query("reference_name", function() {
            return {
                filters: {
                    'reference_doctype': "Purchase Order"
                }
            };
        });
        console.log("Set reference_name query");
    },
    // Triggered whenever the document is loaded or status changes
    "cur_frm.cscript.doc": function(frm) {
        console.log("Document loaded or status changed. Current status:", frm.doc.docstatus);
        // Check if the form status is not "Draft", change save button to submit button
        if (frm.doc.docstatus !== 0) {
            console.log("Document status is not Draft. Changing button to Submit.");
            // Remove existing click event handler and bind a new one to the submit button
            frm.page.btn_primary.removeClass("btn-danger").addClass("btn-  
             primary").html(__('Submit'));
            frm.page.btn_primary.off("click").on("click", function() {
                console.log("Submit button clicked. Saving form.");
                frm.save('Submit', function() {
                    // After submission, refresh the form
                    frm.refresh();
                });
            });
            console.log("Submit event handler bound to the button.");
        } else {
            console.log("Document status is Draft. Changing button to Cancel.");
            // Change button to "Cancel" when the document status is "Submitted"
            frm.page.btn_primary.removeClass("btn-primary").addClass("btn-  
                    danger").html(__('Cancel'));
            frm.page.btn_primary.off("click").on("click", function() {
                console.log("Cancel button clicked. Cancelling form.");
                frm.save('Cancel', function() {
                    // After cancellation, refresh the form
                    frm.refresh();
                });
            });
            console.log("Cancel event handler bound to the button.");
         }
        }

@lalala_lisa

i see nothing wrong with your script. try using the formatted code !!

frappe.ui.form.on("Payment Request", {
    refresh: function(frm) {
        // Function to fetch Purchase Order Items and add them as child documents
        function fetchPurchaseOrderItems() {
            if (frm.doc.reference_doctype === "Purchase Order" && frm.doc.reference_name) {
                frappe.call({
                    method: "frappe.client.get",
                    args: {
                        doctype: "Purchase Order",
                        name: frm.doc.reference_name
                    },
                    callback: function(response) {
                        var purchase_order = response.message;
                        if (purchase_order && purchase_order.items) {
                            // Clear the child table
                            frm.clear_table("request_payment");

                            // Populate fields in the child table
                            purchase_order.items.forEach(function(item) {
                                var child_row = frappe.model.add_child(frm.doc, "Payment Request Item", "request_payment");
                                frappe.model.set_value(child_row.doctype, child_row.name, "item_name", item.item_name);
                                frappe.model.set_value(child_row.doctype, child_row.name, "amount", item.amount);
                                frappe.model.set_value(child_row.doctype, child_row.name, "rate", item.rate);
                                frappe.model.set_value(child_row.doctype, child_row.name, "qty", item.qty);
                                frappe.model.set_value(child_row.doctype, child_row.name, "item_code", item.item_code);
                                frappe.model.set_value(child_row.doctype, child_row.name, "description", item.description);
                                frappe.model.set_value(child_row.doctype, child_row.name, "stock_uom", item.stock_uom);
                                frappe.model.set_value(child_row.doctype, child_row.name, "uom", item.uom);
                                frappe.model.set_value(child_row.doctype, child_row.name, "conversion_factor", item.conversion_factor);
                                frappe.model.set_value(child_row.doctype, child_row.name, "base_rate", item.base_rate);
                                frappe.model.set_value(child_row.doctype, child_row.name, "base_amount", item.base_amount);
                                frappe.model.set_value(child_row.doctype, child_row.name, "total", item.amount);
                                frappe.model.set_value(child_row.doctype, child_row.name, "schedule_date", item.schedule_date);
                            });

                            // Refresh child table
                            frm.refresh_field("request_payment");
                        }
                    }
                });
            }
        }

        // Fetch Purchase Order Items on form refresh
        fetchPurchaseOrderItems();

        // Re-fetch Purchase Order Items when the "Reference Document" field changes
        frm.set_query("reference_name", function() {
            return {
                filters: {
                    'reference_doctype': "Purchase Order"
                }
            };
        });
    },

    // Triggered whenever the document is loaded or status changes
    "cur_frm.cscript.doc": function(frm) {
        // Check if the form status is not "Draft", change save button to submit button
        if (frm.doc.docstatus !== 0) {
            frm.page.btn_primary.removeClass("btn-danger").addClass("btn-primary").html(__('Submit'));
            frm.page.btn_primary.off("click").on("click", function() {
                frm.save('Submit', function() {
                    // After submission, refresh the form
                    frm.refresh();
                });
            });
        } else {
            // Change button to "Cancel" when the document status is "Submitted"
            frm.page.btn_primary.removeClass("btn-primary").addClass("btn-danger").html(__('Cancel'));
            frm.page.btn_primary.off("click").on("click", function() {
                frm.save('Cancel', function() {
                    // After cancellation, refresh the form
                    frm.refresh();
                });
            });
        }
    }
});

1 Like

Thank you, @Chibuzor_Derrick. I tried it, and the issue remains the same. However, when I click the save button multiple times, a confirmation prompt for submission pops up. Upon submitting, the status changes to ‘Initiated’

But when I open the form, this is what is displayed, and when I click the update, an error prompt appears."


Hello,

If you’re calling the function in “refresh” and setting the values in the child table, then even if you save, every time it refreshes, it dynamically updates the values, resulting in the message “Not Saved” being displayed because the values have changed.

1 Like

Hi @Nirvisha_Soni , could you please advise on what steps I should take to prevent this from happening? Thank you.

sure, can you give me details on what do you want to achieve and when (Before submitting or saving Invoice or After)?

1 Like

Thank you so much @Nirvisha_Soni , hope you can assist me with this.

After submitting the Purchase Order, the client wants to create a Payment Request as an internal document/copy. They also want to populate the Purchase Order Item (child table) in the Payment Request. I created a custom child table in the Payment Request. While the script successfully populates the data, when I save the Payment Request, the submit button briefly appears then reverts back to ‘save’ again. I simply want to save the payment request, but the status remains as ‘draft’.

In that case, I suggest utilising a Server Script on the ‘Before Insert’ event of the Payment Request DocType.

Create Server Script, select Payment Request in DocType and select Before Insert in DocType Event

Below is the code you can use:

if doc.reference_name and doc.reference_doctype == "Purchase Order": #making sure payment request is for Purchase Order and Purchase order is set
    
    purchase_order_items= frappe.get_doc("Purchase Order",doc.reference_name).items #get items table from Purchase Order
    
    for item in purchase_order_items: 
        
        #Adding items into Payment Request's Child Table "purchase_order_items" change accordingly
        doc.append("purchase_order_items", {
            'item_code': item.item_code,
            'item_name': item.item_name,
            'schedule_date': item.schedule_date,
            'qty': item.qty,
            'description':item.description,
            'stock_uom': item.stock_uom,
            'uom': item.uom, 
            'conversion_factor': item.conversion_factor, 
            'base_rate': item.base_rate, 
            'base_amount': item.base_amount #add any other field you want
        })
1 Like

It’s working, but I used the ‘Before Validate’ in the Doctype Event because when I used the ‘Before Insert’ and saved the Payment Request Form, the data in the child table became empty.
Thank you very much, @Nirvisha_Soni,for helping me reach my objective.

1 Like