Add entries to a doctype table with Javascript?

I’m trying to code a button that will show up on the Sales Order form after it’s been saved, then take the sales order number, add it to the customer name, create a new project with that string, and add it to the project field in the draft sales order before submitting.

Is this possible with Javascript only? What method can be used to add an entry to a doctype table, if there is one?

You can add a button in the doctype as well from Customize Form and put in a condition to show it etc.

For inserting a new document,
doc = frappe.new_doc({
“doctype”: “Project”,
“title”: “Test”,
“status”: “Open”
})
doc.insert()

It is possible using only JS but will result in complicated client side code.
Better to write a whitelisted method and call it using frappe.call

1 Like

Not working for me unfortunately, any ideas?

Code so far:

frappe.ui.form.on("Sales Order", "refresh", function(frm){
    if(cur_frm.doc.docstatus === 0) {
      frm.add_custom_button(__("Create Project"), function() {
    var soNumb = frm.doc.name;
    var soCust = frm.doc.customer;
    doc = frappe.new_doc({
    "doctype": "Project",
    "project_name": soNumb + " " + soCust,
    "status": "Open",
    "project_type": "External"
    })
    doc.insert()
                }
         );
    }
});

Button appears and will open a new Project window, but it won’t fill the fields with data or save.

1 Like

I was hoping to do this with javascript only. Can you give me an example of how it’s done in Python.

I have little experience in Javascript, but even less in Python… :slight_smile:

Hi, this part

doc = frappe.new_doc({
“doctype”: “Project”,
“project_name”: soNumb + " " + soCust,
“status”: “Open”,
“project_type”: “External”
})
doc.insert()

it is a Python code :slight_smile:

For Javascript you should try

frappe.ui.form.on("Sales Order", "refresh", function(frm){
     if(cur_frm.doc.docstatus === 0) {
        frm.add_custom_button(__("Create Project"), function() {
           tn = frappe.model.make_new_doc_and_get_name("Project");
           locals["Project"][tn].project_name = frm.doc.name + " " + frm.doc.customer;
           locals["Project"][tn].status = "Open";
           locals["Project"][tn].project_type = "External";
       frappe.set_route("Form", "Project", tn);
              }
    }
});

How it works with Python, you should check other buttons in the Sales Order like

cur_frm.add_custom_button(__('Delivery'), this.make_delivery_note, __("Make"));

make_delivery_note: function() { frappe.model.open_mapped_doc({ method: "erpnext.selling.doctype.sales_order.sales_order.make_delivery_note", frm: cur_frm }) }

2 Likes

Thanks for the clarification!

I tried your Javascript code and it does open a new project and put some data in the form, but since my requirement is to enter a new project in the database, attach the project name to the sales order form, and then submit the sales order form, it seems like a server side script is really needed to put an entry in the database WITHOUT opening a new form and navigating away from the sales order form.

I’m trying to get this going server side now but not having any luck:

JS:

frappe.ui.form.on("Sales Order",{
refresh: function(frm) {
if(frm.doc.docstatus===0) {
frm.add_custom_button(__("Create Project"), function(foo) {
        frappe.call({
            method:"nautcustom.nautcustom.create_project.createProj",
            args: {
                soNumb: cur_frm.doc.name,
          soCust: cur_frm.doc.customer,
            },
            callback: function(r) {
                frm.reload_doc();
            }
        });
});
}}
});

PY:

from __future__ import unicode_literals
import frappe
@frappe.whitelist()
def createProj(soNumb, soCust):
    doc = frappe.new_doc({
        "doctype": "Project"
        "project_name": soNumb + " " + soCust
        "status": "Open"
        "project_type": "External"
        })
    doc.insert()

Python code won’t run. Keeps saying “The resource you’re looking for is not available”. I’m already using other buttons to trigger py files in the exact same location though. Any ideas?

Hi could you try this one:

from future import unicode_literals
import frappe
@frappe.whitelist()
def createProj(soNumb, soCust):
proj_doc = frappe.get_doc({
“doctype”: “Project”,
“project_name”: soNumb + " " + soCust,
“status”: “Open”,
“project_type”: “External”
}).insert(ignore_permissions=True)
return proj_doc.name

Still says “The resource you are looking for is not available” :worried:

are you sure that you use correct path to the method method:"nautcustom.nautcustom.create_project.createProj",?

ahh, sorry now I saw that you have other buttons to trigger py files in the exact same location
and everything works on my side, sorry don’t have other ideas.

@SwitsolAG can i save the newly created project without rerouting to it ?
like just to create it in the background and save it


Best regards

Hi, I am not sure that I’ve understood you correct but you can create project in the background.
For example when you save Sale Order you can add creating Project.
It’s possible only with your own custom application.
You can make it with python script.
For helping you to write it I need more details.

first thank you for your quick reply,
I cant use python as i dont have access to any of the files i can only do it client side,

i used your code and changed it to trigger on a button “update” from a doctype called trial to create a new record in a diff doctype called trial2 and take the value of a field called amount in the first doc and put it in “qty1” in the second one and it works like a charm but then it reroutes to the newly created doc, i need it to save the newly created doc without redirecting me to it.

//Replace "DocType" with the source DocType
frappe.ui.form.on("trial", {
	//The trigger can be changed, but refresh must be used to use a button
	refresh: function(frm) {
		//The following line creates a button.
		frm.add_custom_button(__("Update"),
			//The function below is triggered when the button is pressed.
			function() {
           tn = frappe.model.make_new_doc_and_get_name("trial2");
           locals["trial2"][tn].qty1 = frm.doc.amount;
       frappe.set_route("Form", "trial2", tn);
              });
	}
});

Hmmm, sorry I don’t think that it’s possible only on the client side but please try this:

//Replace "DocType" with the source DocType
frappe.ui.form.on("trial", {
	//The trigger can be changed, but refresh must be used to use a button
	refresh: function(frm) {
		//The following line creates a button.
		frm.add_custom_button(__("Update"),
			//The function below is triggered when the button is pressed.
			function() {
           tn = frappe.model.make_new_doc_and_get_name("trial2");
           locals["trial2"][tn].qty1 = frm.doc.amount;
           tn.insert()
         });
	}
});

i tried it but no luck

So, I don’t know how to make it only with client side, sorry

thank you,
I appreciate you taking the time to help


Best regards

Hi @Mohammed_ElKadee,

I have managed to do this client side using frappe.run_serially
I feels like a bit of a hack since it’s used mainly for writing code tests but it does work. It is not “invisible” like doing the same thing in Python that can run in the background, but I personally prefer to stay client side if I can.

I wrote this to force the user to create a project AFTER the Sales Order is saved in draft (so it has a number) but BEFORE it’s submitted and can’t be modified. This way a new project can be created linked to the Sales Order number and the SO can be linked to the project number so they can be easily referenced from the dashboard.

  • The first part of the code changes the “Project” field on the SO to required as soon as the SO is saved as a draft

  • This code is set to run when the “Create a new project” link is clicked while in the SO doctype

  • frappe.route_options is a list of field data that is sent from the current form (SO) to the new form (Project)

  • then the new_doc is created and the field data gets copied in

  • the new_doc becomes the current form so cur_frm.save() saves the new project form

  • frappe.set_route then follows the newly set SO link on the project form and takes me back to the original SO form

  • lastly, I use cur_frm.set_value to add the newly saved project name to the SO, SO can then be submitted.

      frappe.ui.form.on("Sales Order", "refresh", function(frm, cdt, cdn){
      	if (!frm.doc.__islocal) {
      		(frm.toggle_reqd("project", true));
      	}
      	else {
      		(frm.toggle_reqd("project", false));
      	}
      });
      frappe.ui.form.on('Sales Order', {
      	refresh: function(frm) {
      	frm.fields_dict.project.new_doc = function(){
      		frappe.run_serially([
      		() => frappe.route_options = {
      			"project_name": frm.doc.project_name,
      			"project_type": "External",
      			"sales_order": frm.doc.name,
      			"customer": frm.doc.customer,
      			},
      		() => frappe.new_doc("Project"),
      		() => cur_frm.save(),
      		() => frappe.set_route('Form', 'Sales Order', frm.doc.name),
      		() => cur_frm.set_value("project", frm.doc.project_name),
      		])
      		};
      	}
      });
    

I realize you’re probably not trying to do the same thing I was, but hopefully explaining this example will help you adapt it to your needs.

3 Likes

I was actually thinking about taking this approach with the run_serially command before I read your reply but i didnt know exactly how I’ll do it but now i know thanks to you, I too prefer to use client side scripting. I really appreciate your help and I will go now implement it and hopefully it will work. I love how you explained everything and how detailed your answer is. this forum needs more people like you :smiley:.

Edit: It works like a charm:vulcan_salute:


Best regards
Mohammed Elkadee

2 Likes