This is an article because there was no documentation that I could find that describes how to do this. When an invoice is created, not by clicking on the "convert sales order to invoice" button, I needed a way to programmatically link the sales order to the invoice.
Why?
The documentation around the API does not detail how to do this. I also couldn't find any search result via Google or DuckDuckGo (can't say for Bing, I never get around to searching that). This took several hours but it is possible, I was just about to give up even after having spoken to Zoho Support... And then I started updating multiple fields at the same time.
How?
Through sweat and perseverance.
The trick is to update both the sales order id and to update the invoice line items with their respective sales order item id value. For our client's purpose, we are running a custom function off the invoice module which:
- creates a sales order
- checks the returning sales order line items
- cycles through the invoice line items to insert the "sales_order_item_id" field
v_InvoiceID = invoice.get("invoice_id"); v_BooksOrgID = organization.get("organization_id"); // // a sales order has been created, get its ID (required) and reference (optional) r_NewSoDetails = r_CreateSO.get("salesorder"); v_NewSoID = r_NewSoDetails.get("salesorder_id"); v_NewRefNum = r_NewSoDetails.get("salesorder_number"); // // build up a reference map from the line items of the newly created sales order m_NewLineItems = Map(); for each r_NewLineItem in r_NewSoDetails.get("line_items") { v_NewSoItemID = r_NewLineItem.get("item_id"); v_NewSoLineItemQuantity = r_NewLineItem.get("quantity").round(0); v_NewSoLineItemRate = r_NewLineItem.get("rate"); m_NewLineItems.put(v_NewSoItemID + "|" + v_NewSoLineItemQuantity + "|" + v_NewSoLineItemRate,r_NewLineItem.get("line_item_id")); } // // now loop through the invoice line items and rebuild the list l_UpdateLineItems = List(); for each r_OldLineItem in invoice.get("line_items") { m_LineItem = Map(); v_OldInvoiceItemID = r_OldLineItem.get("item_id"); m_LineItem.put("item_id",v_OldInvoiceItemID); v_OldInvoiceLineItemQuantity = r_OldLineItem.get("quantity"); m_LineItem.put("quantity",v_OldInvoiceLineItemQuantity.round(0)); v_OldInvoiceItemRate = r_OldLineItem.get("rate"); m_LineItem.put("rate",v_OldInvoiceItemRate); v_OldKey = v_OldInvoiceItemID + "|" + v_OldInvoiceLineItemQuantity + "|" + v_OldInvoiceItemRate; if(!isnull(m_NewLineItems.get(v_OldKey))) { m_LineItem.put("salesorder_item_id",m_NewLineItems.get(v_OldKey)); } l_UpdateLineItems.add(m_LineItem); } // // now update the current invoice with the sales order details m_UpdateInvoice = Map(); m_UpdateInvoice.put("line_items",l_UpdateLineItems); m_UpdateInvoice.put("reference_number",v_NewRefNum); m_UpdateInvoice.put("salesorder_id",v_NewSoID); m_UpdateInvoice.put("salesorder_number",v_NewRefNum); r_Update = zoho.books.updateRecord("Invoices",v_BooksOrgID,v_InvoiceID,m_UpdateInvoice); info r_Update;
- v_InvoiceID = invoice.get("invoice_id");
- v_BooksOrgID = organization.get("organization_id");
- //
- // a sales order has been created, get its ID (required) and reference (optional)
- r_NewSoDetails = r_CreateSO.get("salesorder");
- v_NewSoID = r_NewSoDetails.get("salesorder_id");
- v_NewRefNum = r_NewSoDetails.get("salesorder_number");
- //
- // build up a reference map from the line items of the newly created sales order
- m_NewLineItems = Map();
- for each r_NewLineItem in r_NewSoDetails.get("line_items")
- {
- v_NewSoItemID = r_NewLineItem.get("item_id");
- v_NewSoLineItemQuantity = r_NewLineItem.get("quantity").round(0);
- v_NewSoLineItemRate = r_NewLineItem.get("rate");
- m_NewLineItems.put(v_NewSoItemID + "|" + v_NewSoLineItemQuantity + "|" + v_NewSoLineItemRate,r_NewLineItem.get("line_item_id"));
- }
- //
- // now loop through the invoice line items and rebuild the list
- l_UpdateLineItems = List();
- for each r_OldLineItem in invoice.get("line_items")
- {
- m_LineItem = Map();
- v_OldInvoiceItemID = r_OldLineItem.get("item_id");
- m_LineItem.put("item_id",v_OldInvoiceItemID);
- v_OldInvoiceLineItemQuantity = r_OldLineItem.get("quantity");
- m_LineItem.put("quantity",v_OldInvoiceLineItemQuantity.round(0));
- v_OldInvoiceItemRate = r_OldLineItem.get("rate");
- m_LineItem.put("rate",v_OldInvoiceItemRate);
- v_OldKey = v_OldInvoiceItemID + "|" + v_OldInvoiceLineItemQuantity + "|" + v_OldInvoiceItemRate;
- if(!isnull(m_NewLineItems.get(v_OldKey)))
- {
- m_LineItem.put("salesorder_item_id",m_NewLineItems.get(v_OldKey));
- }
- l_UpdateLineItems.add(m_LineItem);
- }
- //
- // now update the current invoice with the sales order details
- m_UpdateInvoice = Map();
- m_UpdateInvoice.put("line_items",l_UpdateLineItems);
- m_UpdateInvoice.put("reference_number",v_NewRefNum);
- m_UpdateInvoice.put("salesorder_id",v_NewSoID);
- m_UpdateInvoice.put("salesorder_number",v_NewRefNum);
- r_Update = zoho.books.updateRecord("Invoices",v_BooksOrgID,v_InvoiceID,m_UpdateInvoice);
- info r_Update;
Update 2023
If the above doesn't work, consider making an API call to the following endpoint:
m_Params = Map(); m_Params.put("invoice_ids", <v_InvoiceID>); m_Params.put("organization_id", <v_BooksOrgID>); r_Associate = invokeUrl [ url: "https://www.zohoapis.eu/books/v3/invoices/mapwithorder" type: POST parameters: m_Params connection: "zbooks" ]
- m_Params = Map();
- m_Params.put("invoice_ids", <v_InvoiceID>);
- m_Params.put("organization_id", <v_BooksOrgID>);
- r_Associate = invokeUrl
- [
- url: "https://www.zohoapis.eu/books/v3/invoices/mapwithorder"
- type: POST
- parameters: m_Params
- connection: "zbooks"
- ]
m_Params = Map(); m_Params.put("line_items", <l_UpdateLineItems>); m_Params.put("organization_id", <v_BooksOrgID>); r_Associate = invokeUrl [ url: "https://www.zohoapis.eu/books/v3/invoices/fromsalesorder" type: POST parameters: m_Params connection: "zbooks" ]
- m_Params = Map();
- m_Params.put("line_items", <l_UpdateLineItems>);
- m_Params.put("organization_id", <v_BooksOrgID>);
- r_Associate = invokeUrl
- [
- url: "https://www.zohoapis.eu/books/v3/invoices/fromsalesorder"
- type: POST
- parameters: m_Params
- connection: "zbooks"
- ]