Help on Sales Order for Services Items

I operate mostly as a service company but also include tangible goods. I don’t maintain inventory (considered mostly cash basis business vs accrual).

I have the desire to use sales orders when I know the customer won’t pay within the calendar year (tax period when the work was performed).

This is not tax advice nor a guarantee of a bug-free process :wink:

Use at your own risk:

With the help of ChatGPT I create a server script and client script that adds a button to submitted sales orders that will allow me to set the delivery date and mark as 100% delivered. This should not have negative impact in my system as ALL of my items have “maintain stock = no”. I also default sales orders and sales invoices “update stock = no” (again, I don’t maintain any inventory).

Perhaps others may be in a similar situation and find these scripts useful. I was tired of going into the databse backend and manually changing these values.

Client script creates the button and calls the server script:

DocType = Sales Order

Apply to = Form

frappe.ui.form.on("Sales Order", {
  refresh(frm) {
    if (frm.doc.docstatus === 1 && frm.doc.per_delivered !== 100) {
      frm.add_custom_button(__("Set Delivery"), function() {
        frappe.prompt(
          [
            {
              fieldname: "delivery_date",
              label: "Delivery Date",
              fieldtype: "Date",
              reqd: 1,
              default: frm.doc.delivery_date || frappe.datetime.now_date()
            }
          ],
          (values) => {
            frappe.call({
              method: "set_as_delivered_100",
              args: {
                sales_order_name: frm.doc.name,
                delivery_date: values.delivery_date
              },
              freeze: true,
              freeze_message: __("Updating delivery status"),
              callback(r) {
                if (r.message && !r.message.error) {
                  frappe.msgprint(__("Sales Order marked as 100% Delivered on {0}", [values.delivery_date]));
                  frm.reload_doc();
                } else if (r.message && r.message.error) {
                  frappe.msgprint(__("Error: {0}", [r.message.error]));
                }
              }
            });
          },
          __("Set Delivery Date"),
          __("Mark Delivered")
        );
      });
    }
  }
});

Server script allows modifying the submitted Sales Order.

Script type = API

API Method = set_as_delivered_100

try:
    sales_order = frappe.get_doc('Sales Order', frappe.form_dict.sales_order_name)

    if not sales_order:
        frappe.response["message"] = {"error": "Sales Order not found"}

    # Set delivery date from dialog
    frappe.db.set_value("Sales Order", sales_order.name, "delivery_date", frappe.form_dict.delivery_date)

    # Set delivered_qty = ordered qty for each item
    for item in sales_order.items:
        if item.qty:
            frappe.db.set_value("Sales Order Item", item.name, "delivered_qty", item.qty)

    # Mark as 100% delivered
    frappe.db.set_value("Sales Order", sales_order.name, "per_delivered", 100)
    frappe.db.set_value("Sales Order", sales_order.name, "delivery_status", "Delivered")

    frappe.response["message"] = {"status": "ok"}

except Exception as e:
    frappe.response["message"] = {"error": str(e)}

EDIT: This does not update tabSales Order Item table with the delivery date for the items, not sure I care :slight_smile: