This is an article to quickly demo a couple of snippets of code to display values in a custom related list as well as to display empty custom related lists.
Why?
Because I keep forgetting how to do this and it takes about an hour to go through the documentation and get a working solution.
How?
So the article below shows how to do this Zoho CRM and how to do it in Zoho Books...
The example below is that we are going to search for some records in Zoho Creator and display these in either Zoho Books or Zoho CRM. For demonstration purposes, these have been simplified and will need to be adapted for your needs. Note that I have used 2 URL methods of linking to the Creator app and some data formatting that I tend to use regularly for my benefit later on when I simply copy & paste the below code templates.
Zoho CRM
// // initialize v_Index = 0; // // search in Creator v_OwnerName = <AppOwner>; v_AppLinkName = <AppName>; v_FormLinkName = <FormName>; v_ViewLinkName = <ReportName>; v_Condition = "(Opportunities==\"" + v_DealID + "\")&&(UpdateClick==\"Yes\")"; r_SearchResults = zoho.creator.getRecords(v_OwnerName,v_AppLinkName,v_ViewLinkName,v_Condition,1,100,"joels_connection"); v_ResponseCode = ifnull(r_SearchResults.get("code"),500).toLong(); // // if found records if(v_ResponseCode == 3000) { v_RelatedListXML = "<record>"; l_SearchResults = r_SearchResults.get("data").toJSONList(); for each r_Result in l_SearchResults { // init v_DateTill= "-"; v_QuoteTotalDisp= "-"; v_Index = v_Index + 1; v_RelatedListXML = v_RelatedListXML + "<row no=\"" + v_Index + "\">"; // // retrieve v_CreatorQuoteID = r_Result.get("ID"); v_LinkUrl2 = "https://creatorapp.zoho.eu/" + v_OwnerName + "/" + v_AppLinkName + "/#Page:OpenQuote?ID=" + v_CreatorQuoteID; v_QuoteRef = ifnull(r_Result.get("Quote_Ref"),"-"); v_QuoteName = ifnull(r_Result.get("Quote_Name"),"-"); v_QuoteStage = ifnull(r_Result.get("Quote_Stage"),"-"); v_QuoteCurr = ifnull(r_Result.get("Quote_Currency"),"GBP"); v_QuoteTotal = ifnull(r_Result.get("Total_Amount"),0.0).toDecimal(); v_ExchangeRate = ifnull(r_Result.get("Exchange_Rate"),1); v_ModifiedTime = ifnull(r_Result.get("Modified_Time"),r_Result.get("Added_Time")).toTime().toString("dd/MM/yyyy hh:mm a"); // // future proofs v_ExchangeRate = if(v_ExchangeRate == 0,1,v_ExchangeRate); // // transforms if(r_Result.get("Valid_Till") != null) { v_DateTill = r_Result.get("Valid_Until").toDate().toString("dd/MM/yyyy"); } if(v_QuoteTotal != 0) { v_QuoteTotalGBP = (v_QuoteTotal.toDecimal() / v_ExchangeRate).toDecimal().round(2); // // format currency with commas (thousand separator) and 2 decimals v_QuoteTotalStr = v_QuoteTotal.toDecimal().round(2).toString().replaceAll("(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)",","); v_QuoteTotalGBPStr = v_QuoteTotalGBP.toDecimal().round(2).toString().replaceAll("(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)",","); // // to display both side by side if different otherwise display GBP if(!isnull(m_Currencies.get(v_QuoteCurr))) { if(v_QuoteCurr == "GBP") { v_QuoteTotalDisp = m_Currencies.get(v_QuoteCurr) + " " + v_QuoteTotalGBPStr; } else { v_QuoteTotalDisp = m_Currencies.get(v_QuoteCurr) + " " + v_QuoteTotalStr + " (£ " + v_QuoteTotalGBPStr + ")"; } } else { v_QuoteTotalDisp = v_QuoteTotalStr + " " + v_QuoteCurr + " (£ " + v_QuoteTotalGBPStr + ")"; } } v_RelatedListXML = v_RelatedListXML + "<FL val=\"Quote Ref\">" + v_QuoteRef + "</FL>"; // don't forget to escape quote name with CDATA in case of XML banned characters v_RelatedListXML = v_RelatedListXML + "<FL val=\"Quote Name\" link=\"true\" url=\"" + v_LinkUrl2 + "\"><![CDATA[" + v_QuoteName + "]]></FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Valid Till\">" + v_DateTill + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Stage\">" + v_QuoteStage + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Total Amount\">" + v_QuoteTotalDisp + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Modified Time\">" + v_ModifiedTime + "</FL>"; v_RelatedListXML = v_RelatedListXML + "</row>"; v_Index = v_Index + 1; } v_RelatedListXML = v_RelatedListXML + "</record>"; } else { // display "no records found" v_RelatedListXML = "<error><message>"; v_RelatedListXML = v_RelatedListXML + "No records found"; v_RelatedListXML = v_RelatedListXML + "</message></error>"; } // // output return v_RelatedListXML;
- //
- // initialize
- v_Index = 0;
- //
- // search in Creator
- v_OwnerName = <AppOwner>;
- v_AppLinkName = <AppName>;
- v_FormLinkName = <FormName>;
- v_ViewLinkName = <ReportName>;
- v_Condition = "(Opportunities==\"" + v_DealID + "\")&&(UpdateClick==\"Yes\")";
- r_SearchResults = zoho.creator.getRecords(v_OwnerName,v_AppLinkName,v_ViewLinkName,v_Condition,1,100,"joels_connection");
- v_ResponseCode = ifnull(r_SearchResults.get("code"),500).toLong();
- //
- // if found records
- if(v_ResponseCode == 3000)
- {
- v_RelatedListXML = "<record>";
- l_SearchResults = r_SearchResults.get("data").toJSONList();
- for each r_Result in l_SearchResults
- {
- // init
- v_DateTill= "-";
- v_QuoteTotalDisp= "-";
- v_Index = v_Index + 1;
- v_RelatedListXML = v_RelatedListXML + "<row no=\"" + v_Index + "\">";
- //
- // retrieve
- v_CreatorQuoteID = r_Result.get("ID");
- v_LinkUrl2 = "https://creatorapp.zoho.eu/" + v_OwnerName + "/" + v_AppLinkName + "/#Page:OpenQuote?ID=" + v_CreatorQuoteID;
- v_QuoteRef = ifnull(r_Result.get("Quote_Ref"),"-");
- v_QuoteName = ifnull(r_Result.get("Quote_Name"),"-");
- v_QuoteStage = ifnull(r_Result.get("Quote_Stage"),"-");
- v_QuoteCurr = ifnull(r_Result.get("Quote_Currency"),"GBP");
- v_QuoteTotal = ifnull(r_Result.get("Total_Amount"),0.0).toDecimal();
- v_ExchangeRate = ifnull(r_Result.get("Exchange_Rate"),1);
- v_ModifiedTime = ifnull(r_Result.get("Modified_Time"),r_Result.get("Added_Time")).toTime().toString("dd/MM/yyyy hh:mm a");
- //
- // future proofs
- v_ExchangeRate = if(v_ExchangeRate == 0,1,v_ExchangeRate);
- //
- // transforms
- if(r_Result.get("Valid_Till") != null)
- {
- v_DateTill = r_Result.get("Valid_Until").toDate().toString("dd/MM/yyyy");
- }
- if(v_QuoteTotal != 0)
- {
- v_QuoteTotalGBP = (v_QuoteTotal.toDecimal() / v_ExchangeRate).toDecimal().round(2);
- //
- // format currency with commas (thousand separator) and 2 decimals
- v_QuoteTotalStr = v_QuoteTotal.toDecimal().round(2).toString().replaceAll("(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)",",");
- v_QuoteTotalGBPStr = v_QuoteTotalGBP.toDecimal().round(2).toString().replaceAll("(?<!\.\d)(?<=\d)(?=(?:\d\d\d)+\b)",",");
- //
- // to display both side by side if different otherwise display GBP
- if(!isnull(m_Currencies.get(v_QuoteCurr)))
- {
- if(v_QuoteCurr == "GBP")
- {
- v_QuoteTotalDisp = m_Currencies.get(v_QuoteCurr) + " " + v_QuoteTotalGBPStr;
- }
- else
- {
- v_QuoteTotalDisp = m_Currencies.get(v_QuoteCurr) + " " + v_QuoteTotalStr + " (£ " + v_QuoteTotalGBPStr + ")";
- }
- }
- else
- {
- v_QuoteTotalDisp = v_QuoteTotalStr + " " + v_QuoteCurr + " (£ " + v_QuoteTotalGBPStr + ")";
- }
- }
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Quote Ref\">" + v_QuoteRef + "</FL>";
- // don't forget to escape quote name with CDATA in case of XML banned characters
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Quote Name\" link=\"true\" url=\"" + v_LinkUrl2 + "\"><![CDATA[" + v_QuoteName + "]]></FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Valid Till\">" + v_DateTill + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Stage\">" + v_QuoteStage + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Total Amount\">" + v_QuoteTotalDisp + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Modified Time\">" + v_ModifiedTime + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "</row>";
- v_Index = v_Index + 1;
- }
- v_RelatedListXML = v_RelatedListXML + "</record>";
- }
- else
- {
- // display "no records found"
- v_RelatedListXML = "<error><message>";
- v_RelatedListXML = v_RelatedListXML + "No records found";
- v_RelatedListXML = v_RelatedListXML + "</message></error>";
- }
- //
- // output
- return v_RelatedListXML;
in Zoho Books
// // find all related quotes l_DataRows = List(); v_QuoteRefID = "0"; v_CrmOppID = "0"; v_OwnerName = <AppOwner>; v_AppLinkName = <AppName>; v_FormLinkName = <FormName>; v_ViewLinkName = <ReportName>; if(!isnull(salesorder.get("salesorder_id"))) { v_CreatorSoID = salesorder.get("salesorder_id"); } v_SearchCriteria = "Sales_Order_ID==\"" + v_CreatorSoID + "\""; r_SearchResults = zoho.creator.getRecords(v_OwnerName,v_AppLinkName,v_ViewLinkName,v_SearchCriteria,1,100,"joels_connnection"); v_ResponseCode = ifnull(r_SearchResults.get("code"),500).toLong(); if(v_ResponseCode == 3000) { l_HeaderColumns = List(); l_HeaderColumns.add({"key":"quote_name","value":"Name"}); l_HeaderColumns.add({"key":"valid_till","value":"Valid Till"}); l_HeaderColumns.add({"key":"quote_status","value":"Quote Status"}); l_SearchResults = r_SearchResults.get("data").toJSONList(); for each r_Result in l_SearchResults { v_CreatorQuoteID = r_Result.get("ID"); m_DataRow = Map(); m_LinkedValue = Map(); m_LinkedValue.put("value",r_Result.get("Quote_Name")); m_LinkedValue.put("isExternal",true); m_LinkedValue.put("link","https://app.zohocreator.eu/"+v_OwnerName+"/"+v_AppLinkName+"/"+v_FormLinkName+"/record-edit/"+v_ViewLinkName+"/"+v_CreatorQuoteID+"?param1=my_param_value"); v_DateTill = "-"; if(!isnull(r_Result.get("Valid_Till"))) { v_DateTill = r_Result.get("Valid_Till").toDate().toString("dd/MM/yyyy"); } m_DataRow.put("quote_name",m_LinkedValue); m_DataRow.put("valid_till",v_DateTill); m_DataRow.put("quote_status",r_Result.get("Quote_Status")); l_DataRows.add(m_DataRow); } } else { l_HeaderColumns = List(); l_HeaderColumns.add({"key":"message","value":"Message"}); // if(v_ResponseCode == 3100) { m_DataRow = Map(); m_DataRow.put("message","No records found"); l_DataRows.add(m_DataRow); } else { m_DataRow = Map(); m_DataRow.put("message",r_SearchResults.get("message") + " :: " + v_ResponseCode); l_DataRows.add(m_DataRow); } } // m_RelatedList = Map(); m_RelatedList.put("header_context",l_HeaderColumns); m_RelatedList.put("data",l_DataRows); return m_RelatedList;
- //
- // find all related quotes
- l_DataRows = List();
- v_QuoteRefID = "0";
- v_CrmOppID = "0";
- v_OwnerName = <AppOwner>;
- v_AppLinkName = <AppName>;
- v_FormLinkName = <FormName>;
- v_ViewLinkName = <ReportName>;
- if(!isnull(salesorder.get("salesorder_id")))
- {
- v_CreatorSoID = salesorder.get("salesorder_id");
- }
- v_SearchCriteria = "Sales_Order_ID==\"" + v_CreatorSoID + "\"";
- r_SearchResults = zoho.creator.getRecords(v_OwnerName,v_AppLinkName,v_ViewLinkName,v_SearchCriteria,1,100,"joels_connnection");
- v_ResponseCode = ifnull(r_SearchResults.get("code"),500).toLong();
- if(v_ResponseCode == 3000)
- {
- l_HeaderColumns = List();
- l_HeaderColumns.add({"key":"quote_name","value":"Name"});
- l_HeaderColumns.add({"key":"valid_till","value":"Valid Till"});
- l_HeaderColumns.add({"key":"quote_status","value":"Quote Status"});
- l_SearchResults = r_SearchResults.get("data").toJSONList();
- for each r_Result in l_SearchResults
- {
- v_CreatorQuoteID = r_Result.get("ID");
- m_DataRow = Map();
- m_LinkedValue = Map();
- m_LinkedValue.put("value",r_Result.get("Quote_Name"));
- m_LinkedValue.put("isExternal",true);
- m_LinkedValue.put("link","https://app.zohocreator.eu/"+v_OwnerName+"/"+v_AppLinkName+"/"+v_FormLinkName+"/record-edit/"+v_ViewLinkName+"/"+v_CreatorQuoteID+"?param1=my_param_value");
- v_DateTill = "-";
- if(!isnull(r_Result.get("Valid_Till")))
- {
- v_DateTill = r_Result.get("Valid_Till").toDate().toString("dd/MM/yyyy");
- }
- m_DataRow.put("quote_name",m_LinkedValue);
- m_DataRow.put("valid_till",v_DateTill);
- m_DataRow.put("quote_status",r_Result.get("Quote_Status"));
- l_DataRows.add(m_DataRow);
- }
- }
- else
- {
- l_HeaderColumns = List();
- l_HeaderColumns.add({"key":"message","value":"Message"});
- //
- if(v_ResponseCode == 3100)
- {
- m_DataRow = Map();
- m_DataRow.put("message","No records found");
- l_DataRows.add(m_DataRow);
- }
- else
- {
- m_DataRow = Map();
- m_DataRow.put("message",r_SearchResults.get("message") + " :: " + v_ResponseCode);
- l_DataRows.add(m_DataRow);
- }
- }
- //
- m_RelatedList = Map();
- m_RelatedList.put("header_context",l_HeaderColumns);
- m_RelatedList.put("data",l_DataRows);
- return m_RelatedList;
Error(s) Encountered
- Sorry, there was a problem processing your request.: Your returned XML is invalid
- Sorry, there is a tag discrepancy in the function. The related list cannot be displayed.: You are trying to return <record> </record> (an empty record dataset).