What is the correct way to create a new doc from Client Script?

I have a “before_submit” handler on a Delivery Note, that must create and submit a Stock Entry.

I’ve been skimming the documentation and looking through this forum and stepping through videos at 2x speed and I can’t find any clear statement of how it should be done.

I try with …

frappe.new_doc('Stock Entry').then((se) => {
    console.log("New stock entry:");
    console.log(se);
});

… which opens up a new empty Stock Entry form, but the browser log shows …

New stock entry:
undefined

I do not need a form to open!
I already have all the data to create and immediately submit a new StockEntry.

This works:

return { // Get the Stock Item of this single item row.  Process further if required.
    method:"erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry",
    args: {
        item_code: 'Whitehouse Documents',
        qty: 2,
        company: 'Trump Org',
        from_warehouse: 'Mar-a-Lago',
        to_warehouse: 'Dumpster Out Back',
        serial_no: 'IBAA414\nIBAA418'
    },
    callback: response => {
         const { message: stockEntry } = response;
         stockEntry.items[0].allow_zero_valuation_rate = 1;
         frappe.call({
             method:"frappe.client.insert",
             args: { doc: stockEntry },
             callback: response => console.log(response)
         })
    }
};

It does work, but …
Is it the recommended way to do it?

Is there any reason why you want to use client script instead of server script?

My preference would be to hook on before_submit server side event, this way you are sure that both stock entry and delivery note submit are transactionally consistent.

Otherwise with the client script approach, stock entry submit may commit but not the delivery note (for whatever reason) and you are stuck with an orphan stock entry.

3 Likes

We have serial numbered returnable containers.

The delivery note validation script detects items that must be delivered with a serial numbered container. It adds a temporary item line for the container and fails the validation.

The user tries again to save the DN and is required to provide serial numbers.

When the user submits the DN, the before_submit script creates a Material Transfer Stock Entry to a special “customer consignment” warehouse location, submits it, deletes the temporary line item then submits the DN.

As you can see there is a lot of client-side work involved, however I think you are correct that that last step is better done server side.

frappe.db.insert would be the correct method to use for a new background doc client-side. My aesthetic preference would be to call it directly rather than embedding it in a frappe.call, but I think either works.

Oh! Really?

So what does .db. signify? I have assumed it refers to a way of interacting directly with MySql through an ORM – implying that many required relations with other DocTypes would be ignored.

Does frappe.db.insert of a Stock Entry automagically update inventory and accounting (for example)?

If it is, in fact, the right tool for the job shouldn’t it be mentioned in the Frappe Database API documentation?

The .db. namespace tends to be for database methods, including ORM. All of the ORM methods call server-side hooks, so things like inventory entries will indeed be created. (They don’t call client-side hooks, however, which is why guimorin is suggesting doing this server-side.)

For documentation, the page you’re linking is for the Python API. The method is described in the JavaScript API section:

https://frappeframework.com/docs/v13/user/en/api/server-calls#frappedbinsert

2 Likes

Ok! That’s an excellent clarification.

Thank you.