Custom Sales Order Title to Include Item Codes

I’m trying to create a custom script that will set the title of a SO to the customers name plus a list of the item codes on the sales order.

This is what I’ve got so far:

frappe.ui.form.on(“Sales Order”, “validate”, function(frm)
Some how fetch item codes from child table and store them in an array
{ var custom_title = frm.doc.customer_name + " - " somehow cycle through an array of items;
cur_frm.set_value(“title”, custom_title); }
);

Pretty weak effort I know, but could anyone point me to an example of similar code?

Loop through doc.items
I’ll give you the logic:

for rows in doc.item:
custom_title += rows.fieldnameyouwant

That’s in Python, so do I just use the same logic in Java, or can I mix them in the custom script?

Apologies, I have much better theoretical knowledge of programming than I do actual time spent typing it. So I understand the concepts and the logic, but I get incredibly rusty with the actual syntax.

I’m about to reveal the depth of my ignorance.

I understand that doc.item is an property of the doc object, right? And I’m running a For loop through all of the item properties and storing them in rows, correct? So is “rows” an array? I’m not as familiar with Python and the above looks so simple compared to Java.

I guess I’d better start with the most obvious and the most stupid question, am I meant to be writing this custom script in Java, or Python?

What you’re writing in the front-end is JavaScript, not Java.

doc is the doctype, item is the field name. Search for doctype list in the search bar and view the doctype of SO; you’ll get an idea.

Here, item is the fieldname of the table containing the items in the SO. And you iterate through every row to fetch the different item’s code.

Oh right, at first I thought you’d written the logic and then I thought it looked kind of like some kind of for each loop and then I noticed the colon.

Anyway, so the actual javascript should start out with something more like:

frappe.ui.form.on(“Sales Order”, “validate”, function(frm)
{
$.each(frm.doc.items), function(i, d) {
d.item_code

Am I getting anywhere? That loops through DOM elements, right? Is that what I’m meant to be looping through?

Can I use toString? Having the items separated by a comma would be ideal.

frappe.ui.form.on(“Sales Order”, “validate”, function(frm){
var custom_title = frm.doc.customer_name + " - " + frm.doc.items.toString();
cur_frm.set_value(“title”, custom_title); }
);

What about this:

frappe.ui.form.on(‘Sales Order’, “validate”, function(frm){
frm.doc.items.prototype.toString = function() {
return ‘’+this.item_code;
}
var custom_title = frm.doc.customer_name + " - " + frm.doc.items.toString();
cur_frm.set_value(“title”, custom_title); }
);

Or this:

frappe.ui.form.on(“Sales Order”, “validate”, function(frm) {
const objectArray = Object.values(cur_frm.doc.items);
var custom_description = objectArray.toString();
cur_frm.set_value(“title”, custom_description);
});

That outputs Object object…

I’ve gone back over the original suggestion. Is this closer:

frappe.ui.form.on(“Sales Order”, “validate”, function(frm) {
var custom_title = “”;
var rows;
for (rows in cur_frm.doc.item) {
custom_title += cur_frm.doc.item[rows];
}
cur_frm.set_value(“title”, custom_title);
});

I feel like I’m close.

I’ve tried iterating through doc.items with a for/in loop and I’ve tried using Object.values.

I get “object Object”. I can’t understand why, both of the above approaches are specifically suggested to avoid returning object Object.

Here is my latest attempt:

frappe.ui.form.on(“Sales Order”, “validate”, function(frm) {
var item_array = Object.values(frm.doc.items);
cur_frm.set_value(“title”, item_array.toString());
});

Right now I’m just trying to output any properties at all as a string and from there I was hoping to figure out the next step.

Got it! This works perfectly. I found some examples on the forum and worked it out from there.

frappe.ui.form.on(“Sales Order”, “validate”, function(frm) {
var item_codes = “” ;
var item;
for (item in frm.doc.items) {
item_codes += frm.doc.items[item].item_code + " ";
}
var custom_description = frm.doc.customer_name + " - " + item_codes;
cur_frm.set_value(“title”, custom_description);
});

2 Likes

Glad you solved it yourself. Mark this answer as solution!:relaxed: