I have found a solution to this, in case anyone needs a working serverscript. This can be added after submit on Delivery Notes:
# Collect all Sales Orders from the current Delivery Note
sales_orders = set()
for item in doc.items:
if item.against_sales_order:
sales_orders.add(item.against_sales_order)
# Check every Sales Order
for so_name in sales_orders:
so = frappe.get_doc("Sales Order", so_name)
# frappe.msgprint(f"SO {so.name}: per_delivered={so.per_delivered}, per_billed={so.per_billed}")
# Check if the sales order is fully delivered and not yet fully billed
if so.per_delivered == 100 and so.per_billed < 100:
try:
# Create Sales Invoice from Sales Order with frappe.get_doc
sales_invoice = frappe.get_mapped_doc(
"Sales Order",
so.name,
{
"Sales Order": {
"doctype": "Sales Invoice"
},
"Sales Order Item": {
"doctype": "Sales Invoice Item",
"field_map": {
"parent": "sales_order",
"name": "so_detail"
}
}
}
)
# Set Delivery Note references for every item
for si_item in sales_invoice.items:
# Find respective Delivery Note Item
for dn_item in doc.items:
if dn_item.against_sales_order == so.name and dn_item.so_detail == si_item.so_detail:
si_item.delivery_note = doc.name
si_item.dn_detail = dn_item.name
break
sales_invoice.insert()
# Optional: submit invoice directly
sales_invoice.submit()
frappe.msgprint(f"Sales Invoice {sales_invoice.name} was automatically created for Sales Order {so.name}")
except Exception as e:
frappe.log_error(
message=f"Error while creating Sales Inovices for Order {so.name}: {str(e)}",
title="Auto Sales Invoice Creation Error"
)