Sync Template Changes

When a template BOM is updated, the script ensures that all associated variant BOMs (BOMs for variant items) are updated to reflect the template’s items and operations. I want it to work on submittable variants also.
I created this server script but it was not working:
server script:

Server Script for BOM: Sync Template BOM changes to Variant BOMs

Trigger: On Update (after save) and on Create Variant BOM button

Check if the BOM is a template (item has variants)

is_template = frappe.db.get_value(“Item”, doc.item, “has_variants”)
if not is_template:
frappe.response[“message”] = “This BOM is not a template with variants.”
frappe.response[“status”] = “success”
else:
# Fetch all variant BOMs for the item (excluding the template BOM)
variant_boms = frappe.db.get_all(“BOM”, filters={
“item”: doc.item,
“is_active”: 1,
“name”: [“!=”, doc.name]
}, fields=[“name”, “docstatus”])

if not variant_boms:
    frappe.response["message"] = "No variant BOMs found for this template."
    frappe.response["status"] = "success"
else:
    for variant in variant_boms:
        variant_bom_name = variant.name
        variant_docstatus = variant.docstatus

        # Load the variant BOM document
        variant_doc = frappe.get_doc("BOM", variant_bom_name)

        # Clear existing items and operations in variant BOM
        variant_doc.items = []
        variant_doc.operations = []

        # Sync items from template BOM
        for item in doc.items:
            new_item = frappe.get_doc({
                "doctype": "BOM Item",
                "item_code": item.item_code,
                "item_name": item.item_name,
                "do_not_explode": item.do_not_explode,
                "bom_no": item.bom_no,
                "allow_alternative_item": item.allow_alternative_item,
                "is_stock_item": item.is_stock_item,
                "qty": item.qty,
                "uom": item.uom,
                "stock_qty": item.stock_qty,
                "stock_uom": item.stock_uom,
                "conversion_factor": item.conversion_factor,
                "rate": item.rate,
                "has_variants": item.has_variants,
                "include_item_in_manufacturing": item.include_item_in_manufacturing,
                "amount": item.amount,
                "sourced_by_supplier": item.sourced_by_supplier,
                "idx": item.idx
            })
            variant_doc.append("items", new_item)

        # Sync operations from template BOM
        for operation in doc.operations:
            new_operation = frappe.get_doc({
                "doctype": "BOM Operation",
                "operation": operation.operation,
                "description": operation.description,
                "workstation": operation.workstation,
                "time_in_mins": operation.time_in_mins,
                "fixed_time": operation.fixed_time,
                "idx": operation.idx
            })
            variant_doc.append("operations", new_operation)

        # Save the variant BOM, ignoring permissions and validation
        try:
            variant_doc.save(ignore_permissions=True, ignore_validate=True)
            if variant_docstatus == 1:
                # Update modified timestamp for submitted BOMs
                frappe.db.set_value("BOM", variant_bom_name, "modified", frappe.utils.now())
            frappe.db.commit()
        except Exception as e:
            frappe.log_error(f"Error updating variant BOM {variant_bom_name}: {str(e)}")
            frappe.response["message"] = f"Error updating variant BOM {variant_bom_name}: {str(e)}"
            frappe.response["status"] = "error"
            break

    else:
        frappe.response["message"] = "Successfully updated all variant BOMs."
        frappe.response["status"] = "success"

Handle Create Variant BOM button

if doc.get(“create_variant_bom_company”):
# Check if a variant BOM exists for the selected company
new_variant_bom = frappe.db.get_value(“BOM”, {
“item”: doc.item,
“company”: doc.create_variant_bom_company,
“is_active”: 1,
“name”: [“!=”, doc.name]
}, “name”)

if new_variant_bom:
    # Load the new variant BOM document
    variant_doc = frappe.get_doc("BOM", new_variant_bom)

    # Clear existing items and operations
    variant_doc.items = []
    variant_doc.operations = []

    # Sync items from template BOM
    for item in doc.items:
        new_item = frappe.get_doc({
            "doctype": "BOM Item",
            "item_code": item.item_code,
            "item_name": item.item_name,
            "do_not_explode": item.do_not_explode,
            "bom_no": item.bom_no,
            "allow_alternative_item": item.allow_alternative_item,
            "is_stock_item": item.is_stock_item,
            "qty": item.qty,
            "uom": item.uom,
            "stock_qty": item.stock_qty,
            "stock_uom": item.stock_uom,
            "conversion_factor": item.conversion_factor,
            "rate": item.rate,
            "has_variants": item.has_variants,
            "include_item_in_manufacturing": item.include_item_in_manufacturing,
            "amount": item.amount,
            "sourced_by_supplier": item.sourced_by_supplier,
            "idx": item.idx
        })
        variant_doc.append("items", new_item)

    # Sync operations from template BOM
    for operation in doc.operations:
        new_operation = frappe.get_doc({
            "doctype": "BOM Operation",
            "operation": operation.operation,
            "description": operation.description,
            "workstation": operation.workstation,
            "time_in_mins": operation.time_in_mins,
            "fixed_time": operation.fixed_time,
            "idx": operation.idx
        })
        variant_doc.append("operations", new_operation)

    # Save the variant BOM, ignoring permissions and validation
    try:
        variant_doc.save(ignore_permissions=True, ignore_validate=True)
        frappe.db.commit()
        frappe.response["message"] = "New variant BOM updated with template data."
        frappe.response["status"] = "success"
    except Exception as e:
        frappe.log_error(f"Error updating new variant BOM {new_variant_bom}: {str(e)}")
        frappe.response["message"] = f"Error updating new variant BOM {new_variant_bom}: {str(e)}"
        frappe.response["status"] = "error"