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 
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 