Sales invoice cannot be cancelled through frappe api

Hi,

I am working on one shopify integration, and now one problem is I cannot cancel the sales invoice through the frappe api, here is the general configuration of my erpnext server:

ERPNext: v6.7.8
ERPNext Shopify: v0.0.1
Frappe Framework: v6.7.11

and here is part of my code which related to this cancel function:

so = frappe.db.get_value("Sales Order", {"shopify_id": order.get("id")}, "name")
if not so:
    so = frappe.get_doc({
        "doctype": "Sales Order",
        "naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
        "shopify_id": order.get("id"),
        "customer": frappe.db.get_value("Customer", {"shopify_id": order.get("customer").get("id")}, "name"),
        "membership_number": order["customer"]["membership_number"],
        "transaction_date": order.get("processed_at"),
        "delivery_date": order.get("processed_at"),
        "selling_price_list": shopify_settings.price_list,
        "ignore_pricing_rule": 1,
        "apply_discount_on": "Net Total",
        "discount_amount": flt(order.get("total_discounts")),
        "items": get_item_line(order.get("line_items"), shopify_settings),
        "taxes": get_tax_line(order, order.get("shipping_lines"), shopify_settings)
    }).insert()
    so.submit()
else:
    so = frappe.get_doc("Sales Order", so)
    if order.get("financial_status") == "refunded":
        if not frappe.db.sql("""select name from `tabSales Order` where shopify_id = %(shopify_id)s and docstatus = 2""", {"shopify_id": order.get("id")}):
            #
            ## Cancel the corresponding "Delivery Note" first
            ## We didn't submit the "Delivery Note" for now, so don't need to cancel it for canceling a "Sales Invoice"
            #
            # core_delivery_note = frappe.db.get_value("Delivery Note", {"shopify_id": order.get("id")}, "name")
            # core_delivery_note_doc = frappe.get_doc("Delivery Note", core_delivery_note)
            # core_delivery_note_doc.cancel()
            # core_delivery_note_doc.submit()
            # Cancel the corresponding "Sales Invoice" first
            #
            ## Don't know why the "cancel and submit" doesn't work here, according to the document, what the "cancel" does is:
            ##   Sets the docstatus = 2, then saves
            ## https://docs.frappe.io/current/api/model/frappe.model.document
            ## So here just achieve this through the set_value api
            #
            ## frappe.db.set_value("Sales Invoice", cstr(corre_sales_invoice), "docstatus", 2)
            #
            corre_sales_invoice = frappe.db.get_value("Sales Invoice", {"shopify_id": order.get("id")}, "name")
            corre_sales_invoice_doc = frappe.get_doc("Sales Invoice", corre_sales_invoice)
            corre_sales_invoice_doc.cancel()
            corre_sales_invoice_doc.submit()
            # Then cancel this order
            so.cancel()
            so.submit()
return so

actually when i didn’t try to cancel the sales invoice, the code will raise the error message: need to cancel the corresponding sales invoice first, after i add the code for cancelling the corresponding sales invoice, i got nothing, no exceptions, no errors, but nothing got changed in the erpnext.

can any one help on this?

yes, i forked that one, and improved, changed ,added something according to my requirements.

the point is: i don’t know why the “frappe.get_doc() then cancel()” doesn’t work for the “Sales Invoice”.

like what i described above, if i just invoke the “frappe.get_doc then cancel()” for the “Sales Order, erpnext will tell me “u need to cancel the corresponding sale invoice first”, in some extent this means the “get_doc() then cancel()” works, but after i tried to cancel the “Sales Invoice” in the same way, it raised nothing error, but also nothing get changed in erpnext.

need some help on this, totally no idea where went wrong.

thanks

@Leonard_Shi you need to cancel downstream docs first before canceling sales invoice.

Do share your PR if you end up making improvements.

“downstream docs”? we didn’t submit the “Delivery Note” for all “Sales Order” yet, other than “Delivery Note”, what else I need to cancel first? And also if i need to cancel something else first, then erpnext will give out the exception message just like when i tried to cancel the “Sales Order” but didn’t cancel the corresponding “Sales Invoice”, right?

Yea, I will, actually it is already on GitHub publicly, the original one is two rough, even didn’t implement the pagination for pulling all the items in Shopify, but for testing purpose, there are two many garbage commits, after everything is fine, i will release it properly.

thank you very much.

Sorry I meant downstream from Sales Order.

that is “Sales Invoice”, but when tried to cancel that through “frappe.get_doc() then cancel()” doesn’t work.

Share your trace.

That is the point, the following code give out no exceptions, no error logs, and also did nothing to the “Sales Invoice”.

corre_sales_invoice = frappe.db.get_value("Sales Invoice", {"shopify_id": order.get("id")}, "name")
corre_sales_invoice_doc = frappe.get_doc("Sales Invoice", corre_sales_invoice)
corre_sales_invoice_doc.cancel()
corre_sales_invoice_doc.submit()

Did you commit?

yes

No I meant frappe.db.commit()

oh, this is not enough? corre_sales_invoice_doc.submit()

when do i need to do the frappe.db.commit()

When you want to commit to the database. This happens automatically POST type requests so you don’t have to do it all the time.

            #
            ## Don't know why the "calcel" api doesn't work for "Sales Invoice", so for now need to go through the manually cancellation way.
            ## Just comment all of these out temporarily
            #
            corre_sales_invoice = frappe.db.get_value("Sales Invoice", {"shopify_id": order.get("id")}, "name")
            corre_sales_invoice_doc = frappe.get_doc("Sales Invoice", corre_sales_invoice)
            corre_sales_invoice_doc.cancel()
            corre_sales_invoice_doc.submit()
            frappe.db.commit()

            # # Then cancel this order
            so.cancel()
            so.submit()
            frappe.db.commit()

Tried to add the “frappe.db.commit()” as above, this fix nothing, the docstatus of “Sales Order” and “Sales Invoice” are not changed at all.

What are the other possible problems?

I don’t think this part of your script is executed at all. You can’t submit after cancel