How to create invoice from sales order using API

I am new to ERPNext, I’m in the process of transitioning my company from an old ERP system to ERPNext and we have some existing processes I’m trying to emulate. We take orders from various systems and store them in XML. I will be using that data to create sales orders with the ERPNext REST API, and that looks fairly straight forward, by passing in data using a POST to api/resource/Sales Order.
My next step will be generating an invoice for the order. There is a whitelisted function in the selling.doctype.sales_order.sales_order file called make_sales_invoice. It seemed logical to me that this function would return JSON which could then be fed into api/resource/Sales Invoice to create the invoice and submit it. But the call api/resource/Sales Invoice returns errors.
My question is if there is way to easily generate the JSON to generate a Sales Invoice from a Sales Order using the API, or if I just need to GET the sales order and construct the JSON to make the Sales Invoice myself?

1 Like

Try the following (in Linux).

But first, jq is crazy good.

sudo apt install jq;

Then correct the first three envvars and the rest oughtta work straight out of box:

declare A_SALES_ORDER="SAL-ORD-2020-00001";
declare ERPNToken="ec226d15b52879e:934bad7c3fadda0";
declare YOUR_HOST="dev.yourpublic.work";

curl -slX POST "https://${YOUR_HOST}/api/method/erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice" \
    -H "Authorization: token ${ERPNToken}" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data-urlencode "source_name=${A_SALES_ORDER}" \
> freshFromTheOven.json;

jq .message ./freshFromTheOven.json > hotButtered.json;

curl -slX POST "https://${YOUR_HOST}/api/resource/Sales%20Invoice" \
    -H "Authorization: token ${ERPNToken}" \
    -H "Content-Type: application/json" \
    -d @./hotButtered.json \
> jellySandwich.json;

jq .data ./jellySandwich.json;

We just got a bread making machine :crazy_face:

4 Likes

Thank you so much @MartinHBramwell. Worked like a charm! Now I need to figure out what I was doing differently with Postman. I really appreciate the quick, accurate help! Also the humor. I hope you’re enjoying some fresh bread :smile:

Glad to hear it helped.

I wonder, were you trying to call this …

https://${YOUR_HOST}/api/resource/erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice"

… or this …

https://${YOUR_HOST}/api/method/erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice"

???

Also, tell me you if you used jq, please.

Bread’s all et up … and I put on a pound from a half pound loaf :frowning: Now I can perch my phone on my pandemic paunch.

I used:

https://${YOUR_HOST}/api/method/erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice"

I used jq as you did in the script when I tested on bash. Can’t do that with postman. But I think it should still work without pretty printed json. I am guessing I just had some header set wrong in my Postman requests.

How did you make it using Postman?

1 Like

Good Day

Was trying to create a Delivery Note from Sales Order with Insomnia.

How to?

Thank You

Albertus Geyser

1 Like

Did you manage to get this done?

Yes thank you.

Could you explain to me the process?
Edit: im looking to create and complete production orders from delivery notes. But not sure how to go about.

@Berik

To do in Postman what I demonstrated in shell script:

Screenshot_2022-02-07_12-30-28

Screenshot_2022-02-07_12-36-27

Screenshot_2022-02-07_12-31-34

Screenshot_2022-02-07_12-32-30

(please pardon the brief delay in responding)

1 Like

Hi!

I used the script as mentioned above, but it throws a weird exception.
When executing the second curl code block, here is the output:

{

"exception": "TypeError: bad operand type for abs(): 'NoneType'",

"exc": "[\"Traceback (most recent call last):\\n  File \\\"apps/frappe/frappe/app.py\\\", line 68, in application\\n    response = frappe.api.handle()\\n  File \\\"apps/frappe/frappe/api.py\\\", line 140, in handle\\n    doc = frappe.get_doc(data).insert()\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 240, in insert\\n    self.run_before_save_methods()\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 971, in run_before_save_methods\\n    self.run_method(\\\"validate\\\")\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 869, in run_method\\n    out = Document.hook(fn)(self, *args, **kwargs)\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 1161, in composer\\n    return composed(self, method, *args, **kwargs)\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 1144, in runner\\n    add_to_return_value(self, fn(self, *args, **kwargs))\\n  File \\\"apps/frappe/frappe/model/document.py\\\", line 866, in fn\\n    return method_object(*args, **kwargs)\\n  File \\\"apps/erpnext/erpnext/accounts/doctype/sales_invoice/sales_invoice.py\\\", line 95, in validate\\n    super(SalesInvoice, self).validate()\\n  File \\\"apps/erpnext/erpnext/controllers/selling_controller.py\\\", line 30, in validate\\n    super(SellingController, self).validate()\\n  File \\\"apps/erpnext/erpnext/controllers/stock_controller.py\\\", line 30, in validate\\n    super(StockController, self).validate()\\n  File \\\"apps/erpnext/erpnext/controllers/accounts_controller.py\\\", line 139, in validate\\n    self.set_total_in_words()\\n  File \\\"apps/erpnext/erpnext/controllers/selling_controller.py\\\", line 115, in set_total_in_words\\n    base_amount = self.base_grand_total\\nTypeError: bad operand type for abs(): 'NoneType'\\n\"]"

Steps tried to resolve the error

  1. Edited the selling_controller.py and removed abs function. Typeconverted to int and float manually. Same exception.

  2. Sent integer and float value through postman. Same exception.

Any pointers on how to resolve this?
Thanks in advance :smiley: