Suppose you have a long list of records in Books/CRM/another database that needs to be manually reviewed before you decide to execute certain actions. Instead of going through each and every record on the database (which is tideous and inefficient), custom functions can be written to pull relevant record information from the database into Creator as Subform Rows. Edits to those subform rows can affect the related record upon submission. Custom actions could also be performed around each record via a Decision Box field on the subform row that would act as a general trigger.
To aid the illustration, we will use an example case: Periodically, the accounting team needs to review all overdue invoices from Zoho Books, and decide if they want to levy a finance charge (late fee) on each of the invoices.
The following connections need to be set up in Creator (Main Dashboard > Account Setup > Extensions > Connections):
Get all Overdue Invoices from Zoho Books, and pull the necessary fields to a subform in Creator. Here, accountants get to view all overdue invoices in one screen and tick the rows where late fees should be charged. The following script needs to be written on load of the Creator form.
Org ID refers to your organization ID as specified in Zoho Books. It will be needed for the API calls later.
//Get the Org ID
getOrganizations = invokeurl
[
url :"https://books.zoho.com/api/v3/organizations"
type :GET
connection:"zohobooks" // Change this to your connection name
];
orgId = getOrganizations.get("organizations").get(0).get("organization_id");
info orgId;d,{"Company_Overview":company_overview});
info update2;
}
}
A pagination iterator is used to get > 200 records (API limit) – read more about API pagination here.
// List of page numbers. This should start with '1' and be much longer than the expected number of pages.
pageIterationList = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
// Number of results to return per page. DO NOT exceed the per_page limit of your API, or this function will not perform correctly.
perPageLimit = 200;
// List to accumulate all records
allRecords = List();
// The 'while' condition for evaluation. While this is 'false', the API requests will continue.
iterationComplete = false;
// Loop over each page in the page list
for each page in pageIterationList
{
// Evaluate whether 'while' condition is satisfied
if(iterationComplete == false)
{
paramap = Map(); //Change the paramap based on your requirement
paramap.put("status","overdue");
paramap.put("cf_fc",false);
paramap.put("sort_column","customer_name");
response = invokeurl
[
url :"https://books.zoho.com/api/v3/invoices?organization_id=" + orgId + "&page=" + page + "&per_page=" + perPageLimit
type :GET
parameters:paramap
connection:"zohobooks" // Change this to your connection name
];
// Get records from API response. Add them to allRecords list.
records = response.get("invoices");
allRecords.addAll(records);
// Update 'while' condition status
if(records.size() < perPageLimit)
{
iterationComplete = true;
}
}
}
// Check for correctness
info "Number of Records: " + allRecords.size();
n = 0;
for each r in allRecords
{
// Declaring the row
row_n = Invoice_Financing.Overdue_Invoices();
// Assigning values to subform fields in the row
row_n.Invoice_No=r.get("invoice_number");
row_n.Invoice_ID=r.get("invoice_id");
row_n.Customer_Name=r.get("customer_name");
row_n.Due_Date=r.get("due_date");
row_n.Outstanding_Amount=r.get("balance");
row_n.Invoice_URL="https://books.zoho.com/app#/invoices/" + r.get("invoice_id");
// The .002739 is 1/365, i.e. the rate of interest charged per day
row_n.Interest_Charge=days360(r.get("due_date").toDate(),today) * 0.18 * r.get("balance") * .002739; // Arbitrary calculation for interest charge
row_n.Customer_ID=r.get("customer_id");
row_n.Current_Finance_Charge_Date=r.get("custom_field_hash").get("cf_next_finance_charge_unformatted");
// declare a variable to hold the collection of rows
update = Collection();
update.insert(row_n);
// insert the rows into the subform through the variable
input.Overdue_Invoices.insert(update);
n = n + 1;
}
Note: Change the row names row_n
& field API names r.get("field_name")
based on your requirements.
When the accounting team is done reviewing the invoices, upon submission of the form, 2 main actions are executed for rows where the “Levy Finance Charge” field is ticked (detailed mechanics and criteria to be explained as we go):
The following script needs to be written on submission of the Creator form.
//Get the Org ID
getOrganizations = invokeurl
[
url :"https://books.zoho.com/api/v3/organizations"
type :GET
connection:"zohobooks" // Change this to your connection name
];
orgId = getOrganizations.get("organizations").get(0).get("organization_id");
info orgId;
customerIDs = List();
for each row in Overdue_Invoices
{
if(row.Levy_Finance_Charge = true)
{
if(!customerIDs.contains(row.Customer_ID))
{
customerIDs.add(row.Customer_ID);
}
}
}
The script below executes the 2 main actions:
for each c in customerIDs
{
prevFC = "";
currFC = "";
line_items = List();
invoiceIDList = List();
for each row in Overdue_Invoices
{
if(row.Levy_Finance_Charge = true)
{
if(c = row.Customer_ID)
{
line_item = Map();
line_item.put("description",row.Invoice_No);
line_item.put("rate",row.Interest_Charge);
line_item.put("item_id",2066391000003720076); // This is a custom item created for Finance Charge. Create your own and replace the ID here.
line_item.put("quantity",1);
line_items.add(line_item);
invoiceIDList.add(row.Invoice_ID);
}
}
}
invoicemap = Map();
invoicemap.put("customer_id",c);
invoicemap.put("date",today);
invoicemap.put("due_date",today.addBusinessDay(10));
invoicemap.put("line_items",line_items);
// Create List of Custom Fields to Check the FC field
customFieldList2 = List();
customFieldMap3 = Map();
customFieldMap3.put("label","FC");
customFieldMap3.put("value",true);
customFieldList2.add(customFieldMap3);
invoicemap.put("custom_fields",customFieldList2);
// Create the Invoice
createInvoice = zoho.books.createRecord("Invoices",orgId.toString(),invoicemap);
info createInvoice;
//Mark created invoice as sent
marksent = invokeurl
[
url :"https://books.zoho.com/api/v3/invoices/" + createInvoice.get("invoice").get("invoice_id") + "/status/sent?organization_id=" + orgId
type :POST
connection:"zohobooks" // Change this to your connection name
];
info marksent;
currentDate = zoho.currentdate.toString("yyyy-MM-dd");
//info currentDate;
// Create List of Custom Fields for Current Finance Charge
financeCharge = Map();
customFieldList = List();
customFieldMap1 = Map();
customFieldMap1.put("label","Current Finance Charge");
customFieldMap1.put("value",currentDate);
customFieldList.add(customFieldMap1);
for each row in Overdue_Invoices
{
if(row.Levy_Finance_Charge = true)
{
if(c = row.Customer_ID)
{
// Get current CF Invoice no
currFC = createInvoice.get("invoice").get("invoice_number");
// Get the original Invoice no
oriInvoice = zoho.books.getRecordsByID("invoices",orgId,row.Invoice_ID);
// Get previous CF invoice no. if exists
if(oriInvoice.get("invoice").get("custom_field_hash").get("cf_finance_charge_invoices") != null)
{
prevFC = oriInvoice.get("invoice").get("custom_field_hash").get("cf_finance_charge_invoices");
prevFC = prevFC + "\n";
fcInvoice = prevFC + currFC;
}
else
{
fcInvoice = currFC;
}
info "oriInvoice" : + oriInvoice;
info "fcInvoice: " + fcInvoice;
}
}
}
// Create List of Custom Fields for Finance Charge Invoice(s)
customFieldMap2 = Map();
customFieldMap2.put("label","Finance Charge Invoice(s)");
customFieldMap2.put("value",fcInvoice);
customFieldList.add(customFieldMap2);
// Add all Custom Field Maps into Custom Field List
financeCharge.put("custom_fields",customFieldList);
for each id in invoiceIDList
{
updateInvoice = invokeurl
[
url :"https://books.zoho.com/api/v3/invoices/" + id + "?organization_id=" + orgId
type :PUT
parameters:financeCharge + ""
connection:"zohobooks" // Change this to your connection name
];
info updateInvoice;
}
}
We have demonstrated how this works with Zoho Books. Now, we will use another example case for Zoho CRM: You are running an online course business and you would like your teachers to leave a remark on certain students which are exceptional (all students are stored in the Contacts module).
The following connections need to be set up in Creator (Main Dashboard > Account Setup > Extensions > Connections):
Get all Contacts from Zoho CRM, and pull the necessary fields to a subform in Creator. Here, teachers get to view all students in one screen and leave their remarks. The following script needs to be written on load of the Creator form.
running an online course business and you would like your teachers to leave a remark on certain students which are exceptional (all students are stored in the Contacts module).
A pagination iterator is used to get > 200 records (API limit) – read more about API pagination here: https://github.com/TheWorkflowAcademy/api-pagination-zohocrm.
// CONFIG: Name of Zoho CRM record module (Contacts, Leads, Custom Modules, etc.)
zohoCrmModule = "Contacts";
// CONFIG: Number of results to return per page. DO NOT exceed the per_page limit of your API, or this function will not perform correctly.
perPageLimit = 200;
// List of page numbers. This should start with '1' and be much longer than the expected number of pages.
pageIterationList = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
// List to accumulate all records
allRecords = List();
// The 'while' condition for evaluation. While this is 'false', the API requests will continue.
iterationComplete = false;
// Loop over each page in the page list
for each page in pageIterationList
{
// Evaluate whether 'while' condition is satisfied
if(iterationComplete == false)
{
// Get records from Zoho CRM API.
// CONFIG: Name of Zoho CRM API Connection
response = invokeurl
[
url :"https://www.zohoapis.com/crm/v2/" + zohoCrmModule + "?page=" + page + "&per_page=" + perPageLimit
type :GET
connection:"zohocrm" // Change this to your connection name
];
// Get records from API response. Add them to allRecords list.
records = response.get("data");
allRecords.addAll(records);
// Update 'while' condition status
if(records.size() < perPageLimit)
{
iterationComplete = true;
}
}
}
// Check for correctness
info "Number of Records: " + allRecords.size();
n = 0;
for each r in allRecords
{
// Declaring the row
row_n = Student_Review_Form.List_of_Students();
// Assigning values to subform fields in the row
row_n.Student_Name = r.get("First_Name") + " " + r.get("Last_Name");
row_n.Student_ID = r.get("id");
// declare a variable to hold the collection of rows
update = Collection();
update.insert(row_n);
// insert the rows into the subform through the variable
input.List_of_Students.insert(update);
n = n + 1;
}
Note: Change the row names row_n
& field API names r.get("field_name")
based on your requirements.
When the teachers are done reviewing the students, upon submission of the form, the function will then push the remark and update into CRM. The following script needs to be written on submission of the Creator form.
For each student in the subform, if the “Update” Decision Box is ticked, the function will get the remark keyed in by the teacher, and update the similar “Teacher’s Remark” field in CRM accordingly.
for each row in List_of_Students
{
if(row.Update == true)
{
//Create map for update
data = List();
content = Map();
content.put("id", row.Student_ID);
content.put("Teacher_s_Remark",row.Teacher_s_Remark);
data.add(content);
mp = Map();
mp.put("data", data);
//Update record in CRM
response = invokeurl
[
url :"https://www.zohoapis.com/crm/v2/Contacts"
type :PUT
parameters:mp.toString()
connection:"zohocrm" // Change this to your connection name
];
info response;
}
}
Book a free 30-minutes consultation with a Zoho expert or send us an email