I think I have a similar article on this website but the article below documents the full process to create a button that will map the values/fields from the record into a CRM Mail Merge template and send it off for signing, then return the Signed document attached to the initial record (where the button was).
Why?
If anyone has the envious task of sending a document out for signing by a customer, you will know this takes a while to do:
- You have to find the contact record in CRM for example
- Click on "Send for Zoho Sign"
- Select the template document or upload one
- Add the fields that you will complete, and the ones that other recipients will complete
- Send it for your end-user to complete and sign it
- This comes back to a section called "ZohoSign Documents", download the attachment
- Go back to the contact record, and upload the file to the attachment...
What if I told you we can code a single button on the record which does all of that for you; with only you needing to approve the document before it gets sent to the end user, and when they finish signing it, it attaches automatically back on to the record?... It is possible. The article below documents it but as this is a fair bit of coding, you may want to ask us to build this solution for you. It can take a few days but it will save your staff a ton of time per week!
What your staff see:
How?
So we're going to create a button. Let's use the example of a credit application you want to send to your customer, and when they complete it, the PDF version gets attached to their contact record... all from one click of a button:
Scenario 1: Credit Application: Template exists in ZohoSign
Very quickly, let's go over the implementation plan for this scenario (where you have the template in ZohoSign with fields for the end user to complete):- Add code to button "Send Credit Application" off the contact record
- Sends ZohoSign template off to contact email
- Contact completes and signs the form via ZohoSign
- ZohoSign on completion triggers worklow from within ZohoCRM
- ZohoCRM webhook updates the tracking record (ZohoSign Document) and attaches the signed document to the contact record
/* ******************************************************************************* Function: String fn_SendCreditApplication(Int p_ContactID) Label: Fn - Contact - Send Credit Application Trigger: Off a button on the contact record Purpose: Function used by a button off the contact record to send a credit application form for signing via ZohoSign Inputs: Contact Record ID Outputs: Attachment to the CRM record a ZohoSign Document record in CRM Date Created: 2024-08-06 (Joel Lipman) - Initial release - Tidied up, removed commented code - Added Email and Account mapping to ZohoSign Document record Date Modified: 2024-08-21 (Joel Lipman) - Creates a recipient and event record in CRM More Information: https://www.zoho.com/deluge/help/sign/get-template-by-id.html Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all ******************************************************************************* */ // // hardcoded template ID // check URL https://sign.zoho.com/zs#/template/viewer/<template_id> v_TemplateID = 12345000000678901; v_Template = zoho.sign.getTemplateById(v_TemplateID); v_OutputMessage = ""; // // get the Action ID for SIGN v_SendActionID = 0; if(!isNull(v_Template) && !isNull(v_Template.get("templates"))) { // _ if(!isNull(v_Template.get("templates").get("actions"))) { // get the actions l_Actions = v_Template.get("templates").get("actions").toList(); for each m_Action in l_Actions { if(m_Action.get("action_type") == "SIGN") { v_SendActionId = m_Action.get("action_id").toLong(); } } } } if(v_SendActionID == 0) { v_OutputMessage = "Unable to find appropriate action. If this continues please contact support."; } // // get contact record details r_Contact = zoho.crm.getRecordById("Contacts",p_ContactID); // info r_Contact; // // if email exists then create the ZohoSign Document record for tracking purposes if(!isNull(r_Contact) && !isNull(r_Contact.get("Email"))) { v_RecipientEmail = r_Contact.get("Email"); v_RecipientFullName = r_Contact.get("Full_Name"); // _ m_Parameters = Map(); m_Data = Map(); m_Templates = Map(); m_Actions = Map(); m_FieldData = Map(); m_FieldTextData = Map(); m_FieldBooleanData = Map(); m_FieldDateData = Map(); l_Actions = List(); // m_FieldData.put("field_text_data",m_FieldTextData); m_FieldData.put("field_boolean_data",m_FieldBooleanData); m_FieldData.put("field_date_data",m_FieldDateData); m_Templates.put("field_data",m_FieldData); m_Actions.put("action_id",v_SendActionId); m_Actions.put("action_type","SIGN"); m_Actions.put("private_notes","Please complete the following Credit Application Form or forward to the person within your company responsible for completing this."); m_Actions.put("recipient_phonenumber",""); m_Actions.put("recipient_countrycode",""); m_Actions.put("verify_recipient",false); m_Actions.put("recipient_name",v_RecipientFullName); m_Actions.put("recipient_email",v_RecipientEmail); l_Actions.add(m_Actions); // m_Data.put("templates",m_Templates); m_Templates.put("actions",l_Actions); m_Templates.put("notes",""); m_Parameters.put("data",m_Data); m_Parameters.put("is_quicksend",true); // // Send the Zoho Sign Template with the pre-filled fields to the desired recipient/ recipients r_SignResponse = zoho.sign.createUsingTemplate(v_TemplateID,m_Parameters); // info r_SignResponse; // // get request and document IDs r_SignTemplate = zoho.sign.getTemplateById(v_TemplateID); v_TemplateName = r_SignTemplate.get("templates").get("template_name"); // // Get the Zoho Sign Document ID l_SignRequests = r_SignResponse.get("requests"); l_DocumentIds = l_SignRequests.get("document_ids"); // //Get the Zoho Sign Request ID v_RequestId = l_SignRequests.get("request_id"); m_DocInfo = l_DocumentIds.get(0); v_DocumentId = m_DocInfo.get("document_id"); // // Create Map for CRM Record - ZohoSign Documents m_ZCrm_ZSDoc = Map(); m_ZCrm_ZSDoc.put("Name",v_TemplateName); m_ZCrm_ZSDoc.put("zohosign__Contact",p_ContactID); m_ZCrm_ZSDoc.put("Email",v_RecipientEmail); if(!isNull(r_Contact.get("Account_Name"))) { m_ZCrm_ZSDoc.put("zohosign__Account",r_Contact.get("Account_Name").get("id")); } m_ZCrm_ZSDoc.put("zohosign__Owner",r_Contact.get("Owner").get("id")); m_ZCrm_ZSDoc.put("zohosign__Date_Sent",today); m_ZCrm_ZSDoc.put("zohosign__ZohoSign_Document_ID",v_DocumentId); m_ZCrm_ZSDoc.put("zohosign__Module_Name","Contacts"); m_ZCrm_ZSDoc.put("zohosign__Module_Record_ID",p_ContactID.toString()); m_ZCrm_ZSDoc.put("zohosign__Document_Deadline",zoho.currentdate.addDay(15)); m_ZCrm_ZSDoc.put("zohosign__Document_Status","Out for Signature"); // Request_ID is a custom field added to retrieve the document later from ZohoWriter. m_ZCrm_ZSDoc.put("Request_ID",v_RequestId); r_ZCrm_ZSDoc = zoho.crm.createRecord("zohosign__ZohoSign_Documents",m_ZCrm_ZSDoc); v_OutputMessage = "Credit application sent to " + v_RecipientEmail + " for signing."; // // create CRM zohosign document child records (recipient and event) if(!isNull(r_ZCrm_ZSDoc.get("id"))) { // // get logged in user (who clicked the button) v_LoggedInUserID = 0; r_Users = zoho.crm.getRecords("users"); for each m_User in r_Users.get("users") { if(m_User.get("email").equalsIgnoreCase(zoho.loginuserid)) { v_LoggedInUserID = m_User.get("id"); } } // // create CRM zohosign document recipient m_CreateRecipient = Map(); m_CreateRecipient.put("Name",v_RecipientFullName); m_CreateRecipient.put("Email",v_RecipientEmail); m_CreateRecipient.put("Owner",v_LoggedInUserID); m_CreateRecipient.put("zohosign__Recipient_Order",1); m_CreateRecipient.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id")); m_CreateRecipient.put("zohosign__Recipient_Type","Signer"); m_CreateRecipient.put("zohosign__Recipient_Status","Sent"); m_CreateRecipient.put("zohosign__ZohoSign_Document_ID",v_DocumentId); r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient); // // create CRM zohosign document event m_CreateEvent = Map(); m_CreateEvent.put("Name",v_TemplateName + "-SENT"); m_CreateEvent.put("Owner",v_LoggedInUserID); m_CreateEvent.put("Email",v_RecipientEmail); m_CreateEvent.put("zohosign__Date",zoho.currentdate); m_CreateEvent.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id")); m_CreateEvent.put("zohosign__Description","Sent out for signature"); r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent); } } // // over to webhook to update this record and attach signed document to contact record // see webhook: fn_ZohoSign_Webhook in CRM return v_OutputMessage;
- /* *******************************************************************************
- Function: string fn_SendCreditApplication(Int p_ContactID)
- Label: Fn - Contact - Send Credit Application
- Trigger: Off a button on the contact record
- Purpose: Function used by a button off the contact record to send a credit application form for signing via ZohoSign
- Inputs: Contact Record ID
- Outputs: Attachment to the CRM record
- a ZohoSign Document record in CRM
- Date Created: 2024-08-06 (Joel Lipman)
- - Initial release
- - Tidied up, removed commented code
- - Added Email and Account mapping to ZohoSign Document record
- Date Modified: 2024-08-21 (Joel Lipman)
- - Creates a recipient and event record in CRM
- More Information:
- https://www.zoho.com/deluge/help/sign/get-template-by-id.html
- Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all
- ******************************************************************************* */
- //
- // hardcoded template ID
- // check URL https://sign.zoho.com/zs#/template/viewer/<template_id>
- v_TemplateID = 12345000000678901;
- v_Template = zoho.sign.getTemplateById(v_TemplateID);
- v_OutputMessage = "";
- //
- // get the Action ID for SIGN
- v_SendActionID = 0;
- if(!isNull(v_Template) && !isNull(v_Template.get("templates")))
- {
- // _
- if(!isNull(v_Template.get("templates").get("actions")))
- {
- // get the actions
- l_Actions = v_Template.get("templates").get("actions").toList();
- for each m_Action in l_Actions
- {
- if(m_Action.get("action_type") == "SIGN")
- {
- v_SendActionId = m_Action.get("action_id").toLong();
- }
- }
- }
- }
- if(v_SendActionID == 0)
- {
- v_OutputMessage = "Unable to find appropriate action. If this continues please contact support.";
- }
- //
- // get contact record details
- r_Contact = zoho.crm.getRecordById("Contacts",p_ContactID);
- // info r_Contact;
- //
- // if email exists then create the ZohoSign Document record for tracking purposes
- if(!isNull(r_Contact) && !isNull(r_Contact.get("Email")))
- {
- v_RecipientEmail = r_Contact.get("Email");
- v_RecipientFullName = r_Contact.get("Full_Name");
- // _
- m_Parameters = Map();
- m_Data = Map();
- m_Templates = Map();
- m_Actions = Map();
- m_FieldData = Map();
- m_FieldTextData = Map();
- m_FieldBooleanData = Map();
- m_FieldDateData = Map();
- l_Actions = List();
- //
- m_FieldData.put("field_text_data",m_FieldTextData);
- m_FieldData.put("field_boolean_data",m_FieldBooleanData);
- m_FieldData.put("field_date_data",m_FieldDateData);
- m_Templates.put("field_data",m_FieldData);
- m_Actions.put("action_id",v_SendActionId);
- m_Actions.put("action_type","SIGN");
- m_Actions.put("private_notes","Please complete the following Credit Application Form or forward to the person within your company responsible for completing this.");
- m_Actions.put("recipient_phonenumber","");
- m_Actions.put("recipient_countrycode","");
- m_Actions.put("verify_recipient",false);
- m_Actions.put("recipient_name",v_RecipientFullName);
- m_Actions.put("recipient_email",v_RecipientEmail);
- l_Actions.add(m_Actions);
- //
- m_Data.put("templates",m_Templates);
- m_Templates.put("actions",l_Actions);
- m_Templates.put("notes","");
- m_Parameters.put("data",m_Data);
- m_Parameters.put("is_quicksend",true);
- //
- // Send the Zoho Sign Template with the pre-filled fields to the desired recipient/ recipients
- r_SignResponse = zoho.sign.createUsingTemplate(v_TemplateID,m_Parameters);
- // info r_SignResponse;
- //
- // get request and document IDs
- r_SignTemplate = zoho.sign.getTemplateById(v_TemplateID);
- v_TemplateName = r_SignTemplate.get("templates").get("template_name");
- //
- // Get the Zoho Sign Document ID
- l_SignRequests = r_SignResponse.get("requests");
- l_DocumentIds = l_SignRequests.get("document_ids");
- //
- //Get the Zoho Sign Request ID
- v_RequestId = l_SignRequests.get("request_id");
- m_DocInfo = l_DocumentIds.get(0);
- v_DocumentId = m_DocInfo.get("document_id");
- //
- // Create Map for CRM Record - ZohoSign Documents
- m_ZCrm_ZSDoc = Map();
- m_ZCrm_ZSDoc.put("Name",v_TemplateName);
- m_ZCrm_ZSDoc.put("zohosign__Contact",p_ContactID);
- m_ZCrm_ZSDoc.put("Email",v_RecipientEmail);
- if(!isNull(r_Contact.get("Account_Name")))
- {
- m_ZCrm_ZSDoc.put("zohosign__Account",r_Contact.get("Account_Name").get("id"));
- }
- m_ZCrm_ZSDoc.put("zohosign__Owner",r_Contact.get("Owner").get("id"));
- m_ZCrm_ZSDoc.put("zohosign__Date_Sent",today);
- m_ZCrm_ZSDoc.put("zohosign__ZohoSign_Document_ID",v_DocumentId);
- m_ZCrm_ZSDoc.put("zohosign__Module_Name","Contacts");
- m_ZCrm_ZSDoc.put("zohosign__Module_Record_ID",p_ContactID.toString());
- m_ZCrm_ZSDoc.put("zohosign__Document_Deadline",zoho.currentdate.addDay(15));
- m_ZCrm_ZSDoc.put("zohosign__Document_Status","Out for Signature");
- // Request_ID is a custom field added to retrieve the document later from ZohoWriter.
- m_ZCrm_ZSDoc.put("Request_ID",v_RequestId);
- r_ZCrm_ZSDoc = zoho.crm.createRecord("zohosign__ZohoSign_Documents",m_ZCrm_ZSDoc);
- v_OutputMessage = "Credit application sent to " + v_RecipientEmail + " for signing.";
- //
- // create CRM zohosign document child records (recipient and event)
- if(!isNull(r_ZCrm_ZSDoc.get("id")))
- {
- //
- // get logged in user (who clicked the button)
- v_LoggedInUserID = 0;
- r_Users = zoho.crm.getRecords("users");
- for each m_User in r_Users.get("users")
- {
- if(m_User.get("email").equalsIgnoreCase(zoho.loginuserid))
- {
- v_LoggedInUserID = m_User.get("id");
- }
- }
- //
- // create CRM zohosign document recipient
- m_CreateRecipient = Map();
- m_CreateRecipient.put("Name",v_RecipientFullName);
- m_CreateRecipient.put("Email",v_RecipientEmail);
- m_CreateRecipient.put("Owner",v_LoggedInUserID);
- m_CreateRecipient.put("zohosign__Recipient_Order",1);
- m_CreateRecipient.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id"));
- m_CreateRecipient.put("zohosign__Recipient_Type","Signer");
- m_CreateRecipient.put("zohosign__Recipient_Status","Sent");
- m_CreateRecipient.put("zohosign__ZohoSign_Document_ID",v_DocumentId);
- r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient);
- //
- // create CRM zohosign document event
- m_CreateEvent = Map();
- m_CreateEvent.put("Name",v_TemplateName + "-SENT");
- m_CreateEvent.put("Owner",v_LoggedInUserID);
- m_CreateEvent.put("Email",v_RecipientEmail);
- m_CreateEvent.put("zohosign__Date",zoho.currentdate);
- m_CreateEvent.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id"));
- m_CreateEvent.put("zohosign__Description","Sent out for signature");
- r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent);
- }
- }
- //
- // over to webhook to update this record and attach signed document to contact record
- // see webhook: fn_ZohoSign_Webhook in CRM
- return v_OutputMessage;
On Sign Completion: Attach the signed document to the contact record
[DEPRECATED: Please use Generic Webhook at the bottom of this page]
For this, we'll create the webhook function first (this one I've called Fn - ZohoSign - Document Completed) and then make it into a REST API function for ZohoSign to send the data to:
/* ******************************************************************************* Function: String fn_ZohoSign_DocumentCompleted(string crmAPIRequest) Label: Fn - ZohoSign - Document Completed Trigger: Webhook when ZohoSign sees a completed document Purpose: This function is used as a webhook when ZohoSign detects a document has been completed Inputs: crmAPIRequest Outputs: crmAPIResponse Date Created: 2024-08-06 (Joel Lipman) - Initial release - Modified to attach the signed document to the originating Contact Record More Information: https://www.zoho.com/deluge/help/sign-tasks.html https://www.zoho.com/deluge/help/sign/get-document-by-id.html https://www.zoho.com/deluge/help/sign/download-document.html Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all ******************************************************************************* */ // // crmAPIRequest v_DebugMessage = ""; v_RequestID = 0; m_Body = ifnull(crmAPIRequest.get("body"),Map()); v_DebugMessage = "Body:<br /><br />" + m_Body + "<hr />"; // // determine type of document done if(!isNull(m_Body.get("requests"))) { v_RequestName = ifnull(m_Body.get("requests").get("request_name"),"-"); if(v_RequestName.containsIgnoreCase("credit application")) { v_ZohoSign_DocumentType = "CreditApplication"; } v_DebugMessage = v_DebugMessage + "Request Type: <br /><br />" + v_ZohoSign_DocumentType + "<hr />"; } // // update the ZohoSign Document record for templates in ZohoSign // NB: if your document is NOT in ZohoSign but is a mail merge template in CRM, then skip this if statement if(v_ZohoSign_DocumentType == "CreditApplication") { v_RequestID = ifnull(m_Body.get("requests").get("request_id"),"0").toLong(); l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","Request_ID:equals:" + v_RequestID); v_DebugMessage = v_DebugMessage + "Search Result(s): <br /><br />" + l_SearchResults + "<hr />"; for each m_ZS_Doc in l_SearchResults { if(m_ZS_Doc.get("Request_ID") == v_RequestID) { // updates the CRM ZohoSign Document Record v_ZS_DocRecordID = m_ZS_Doc.get("id"); m_SignDocument = zoho.sign.getDocumentById(v_RequestID); v_SignDate = m_SignDocument.get("requests").get("action_time"); v_SignDate = v_SignDate.toDate("yyyy-MM-dd"); r_Update = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZS_DocRecordID,{"zohosign__Document_Status":"SIGNED","zohosign__Date_Completed":v_SignDate}); v_DebugMessage = v_DebugMessage + "ZS Doc Update: <br /><br />" + r_Update + "<hr />"; } } // // now attach to CRM Contact if(v_RequestID != 0) { r_ZS_DocumentDetails = zoho.sign.getDocumentById(v_RequestID); m_Requests = ifnull(r_ZS_DocumentDetails.get("requests"),Map()); l_Actions = ifnull(m_Requests.get("actions"),List()); for each m_Action in l_Actions { if(!isNull(m_Action.get("recipient_email"))) { info "Action Type: " + m_Action.get("action_type"); info "Action ID: " + m_Action.get("action_id"); info "Action Status: " + m_Action.get("action_status"); // // match to contact in CRM l_ContactResults = zoho.crm.searchRecords("Contacts","Email:equals:" + m_Action.get("recipient_email")); for each m_Contact in l_ContactResults { if(m_Contact.get("Email").equalsIgnoreCase(m_Action.get("recipient_email"))) { r_ZS_Download = zoho.sign.downloadDocument(v_RequestID); r_ZS_Download.setFileName(m_Requests.get("request_name") + "_SIGNED.pdf"); r_AttachFile = zoho.crm.attachFile("Contacts",m_Contact.get("id"),r_ZS_Download); if(!isNull(r_AttachFile.get("message"))) { v_DebugMessage = v_DebugMessage + "CRM Attachment: <br /><br />" + r_AttachFile.get("message") + "<hr />"; } } } } } } } v_DebugMessage = v_DebugMessage + "Date/Time: <br /><br />" + zoho.currenttime; // return "Webhook received";
- /* *******************************************************************************
- Function: string fn_ZohoSign_DocumentCompleted(string crmAPIRequest)
- Label: Fn - ZohoSign - Document Completed
- Trigger: Webhook when ZohoSign sees a completed document
- Purpose: This function is used as a webhook when ZohoSign detects a document has been completed
- Inputs: crmAPIRequest
- Outputs: crmAPIResponse
- Date Created: 2024-08-06 (Joel Lipman)
- - Initial release
- - Modified to attach the signed document to the originating Contact Record
- More Information:
- https://www.zoho.com/deluge/help/sign-tasks.html
- https://www.zoho.com/deluge/help/sign/get-document-by-id.html
- https://www.zoho.com/deluge/help/sign/download-document.html
- Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all
- ******************************************************************************* */
- //
- // crmAPIRequest
- v_DebugMessage = "";
- v_RequestID = 0;
- m_Body = ifnull(crmAPIRequest.get("body"),Map());
- v_DebugMessage = "Body:<br /><br />" + m_Body + "<hr />";
- //
- // determine type of document done
- if(!isNull(m_Body.get("requests")))
- {
- v_RequestName = ifnull(m_Body.get("requests").get("request_name"),"-");
- if(v_RequestName.containsIgnoreCase("credit application"))
- {
- v_ZohoSign_DocumentType = "CreditApplication";
- }
- v_DebugMessage = v_DebugMessage + "Request type: <br /><br />" + v_ZohoSign_DocumentType + "<hr />";
- }
- //
- // update the ZohoSign Document record for templates in ZohoSign
- // NB: if your document is NOT in ZohoSign but is a mail merge template in CRM, then skip this if statement
- if(v_ZohoSign_DocumentType == "CreditApplication")
- {
- v_RequestID = ifnull(m_Body.get("requests").get("request_id"),"0").toLong();
- l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","Request_ID:equals:" + v_RequestID);
- v_DebugMessage = v_DebugMessage + "Search Result(s): <br /><br />" + l_SearchResults + "<hr />";
- for each m_ZS_Doc in l_SearchResults
- {
- if(m_ZS_Doc.get("Request_ID") == v_RequestID)
- {
- // updates the CRM ZohoSign Document Record
- v_ZS_DocRecordID = m_ZS_Doc.get("id");
- m_SignDocument = zoho.sign.getDocumentById(v_RequestID);
- v_SignDate = m_SignDocument.get("requests").get("action_time");
- v_SignDate = v_SignDate.toDate("yyyy-MM-dd");
- r_Update = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZS_DocRecordID,{"zohosign__Document_Status":"SIGNED","zohosign__Date_Completed":v_SignDate});
- v_DebugMessage = v_DebugMessage + "ZS Doc Update: <br /><br />" + r_Update + "<hr />";
- }
- }
- //
- // now attach to CRM Contact
- if(v_RequestID != 0)
- {
- r_ZS_DocumentDetails = zoho.sign.getDocumentById(v_RequestID);
- m_Requests = ifnull(r_ZS_DocumentDetails.get("requests"),Map());
- l_Actions = ifnull(m_Requests.get("actions"),List());
- for each m_Action in l_Actions
- {
- if(!isNull(m_Action.get("recipient_email")))
- {
- info "Action type: " + m_Action.get("action_type");
- info "Action ID: " + m_Action.get("action_id");
- info "Action Status: " + m_Action.get("action_status");
- //
- // match to contact in CRM
- l_ContactResults = zoho.crm.searchRecords("Contacts","Email:equals:" + m_Action.get("recipient_email"));
- for each m_Contact in l_ContactResults
- {
- if(m_Contact.get("Email").equalsIgnoreCase(m_Action.get("recipient_email")))
- {
- r_ZS_Download = zoho.sign.downloadDocument(v_RequestID);
- r_ZS_Download.setFileName(m_Requests.get("request_name") + "_SIGNED.pdf");
- r_AttachFile = zoho.crm.attachFile("Contacts",m_Contact.get("id"),r_ZS_Download);
- if(!isNull(r_AttachFile.get("message")))
- {
- v_DebugMessage = v_DebugMessage + "CRM Attachment: <br /><br />" + r_AttachFile.get("message") + "<hr />";
- }
- }
- }
- }
- }
- }
- }
- v_DebugMessage = v_DebugMessage + "Date/Time: <br /><br />" + zoho.currenttime;
- //
- return "Webhook received";
Setup the webhook in ZohoSign
Now we need the webhook added to ZohoSign so that when a document is completed, it tells ZohoCRM. First, let's create an endpoint for the webhook in ZohoCRM:
- Login to ZohoCRM > Setup > Functions > and hover the mouse over the function you just created above (eg. Fn - ZohoSign - Document Completed)
- Hover the mouse over the ellipsis that appears and select "REST API"
- Then click on the API switch to enable it and copy the resulting URL to your clipboard
- Now login to ZohoSign
- In the left sidebar, go to > Settings > Developer Settings > Webhooks
- Copy and paste the URL and set the callback events (triggers) to "Completed by all"
- Now whenever a document is completed in ZohoSign, it will send the data of the request to ZohoCRM
Done!
So the above is good for a credit application form where the template exists in Zoho Sign. But now how do we do this using simply a Mail Merge template held in ZohoCRM? Let's give it a go:
Scenario 2: Custom Module Mail Merge: Template exists in ZohoCRM
For this scenario, the use-case is a little more complex:- Login to ZohoCRM, go to custom module, in this case "Maintenance"
- Click on Button to send a document for the engineer to complete
- Engineer to complete notes / description / additional info
- Engineer to sign
- Then the ZohoSign document gets sent to a line manager to Approve the document
- Then the document gets sent to the end user
- The signed version gets attached to the custom module record
- a ZohoSign Document record needs to be created to track the progress of the document. I know this exists in ZohoSign already but we don't expect staff to go to another app to check on this and would rather see it directly in ZohoCRM on the relevant record.
So the more observant among you will have noted that I'm recording the module name and module record ID on the ZohoSign Document record. Doing this at the point of the request means that I can have a generic webhook that handles every ZohoSign completion and attach the signed PDF accordingly.
The button for the custom module
For this I go the custom module, in this example called "Maintenance", and add a button:
/* ******************************************************************************* Function: String fn_MailMerge_Maintenance(String p_MaintenanceID) Label: Fn - Mail Merge - Maintenance Trigger: Off a button on the maintenance record Purpose: Function used by button off maintenance record to send a Maintenance Report to the customer contact. Inputs: Record ID Outputs: Attachment to the CRM record Date Created: 2024-08-07 (Joel Lipman) - Initial release Date Modified: 2024-08-22 (Joel Lipman) - Creates ZohoSign Document records in ZohoCRM (for tracking progress of e-sign process) More Information: https://www.joellipman.com/articles/crm/zoho/zoho-crm-zoho-writer-button-to-merge-template,-send,-and-attach.html https://www.zoho.com/deluge/help/writer/merge-and-sign.html https://www.zoho.com/deluge/help/script/sign/create-using-template.html ErrorCode: R6006 Message: Invalid signer info. Please try again with proper signer info. Solution: Recipients list was incorrect and I'd assigned the recipient twice. Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all Also note that the document already exists as a mail merge template in CRM. ******************************************************************************* */ // b_Debug = true; v_ModuleName = "Maintenance"; v_OutputMessage = ""; r_RecordDetails = zoho.crm.getRecordById(v_ModuleName,p_MaintenanceID); //info r_RecordDetails; v_AttachmentDate = zoho.currentdate.toString("dd-MMM-yyyy"); v_SignType = "Maintenance Report"; v_FileNameWithouExt = v_SignType; // // Specify template ID // check URL https://sign.zoho.com/zs#/template/viewer/<template_id> v_TemplateID = "abcdefghijklmnopqrstuvwxyz01234567890"; // // get merge field names (for reference - not used later in this fuction) // r_Fields = zoho.writer.getMergeFields(v_TemplateID,"my_writer_connection"); //info r_Fields; // // map data to these fields m_Data = Map(); // // get reference number for filename if(!isNull(r_RecordDetails.get("Name"))) { v_SetFilename = v_SignType + " " + r_RecordDetails.get("Name"); } // // get maintenance record item lookup and map values if(!isNull(r_RecordDetails.get("Lookup_Serial_Number"))) { r_CustomerAsset = zoho.crm.getRecordById("Assets",r_RecordDetails.get("Lookup_Serial_Number").get("id")); if(!isNull(r_CustomerAsset.get("Account_Name"))) { m_Data.put("Lookup_Serial_Number.Account_Name",r_CustomerAsset.get("Account_Name").get("name")); } // .. MAP ALL OTHER FIELDS } // // get customer contact record v_EndCustomerFullName = ""; v_EndCustomerEmail = ""; v_EndCustomerAccountID = 0; v_EndCustomerContactID = 0; if(!isNull(r_RecordDetails.get("Customer_Contact"))) { v_EndCustomerContactID = r_RecordDetails.get("Customer_Contact").get("id").toLong(); r_CustomerContact = zoho.crm.getRecordById("Contacts",v_EndCustomerContactID); if(!isNull(r_CustomerContact.get("Full_Name"))) { v_EndCustomerFullName = r_CustomerContact.get("Full_Name"); m_Data.put("Customer_Contact.Full_Name",v_EndCustomerFullName); } if(!isNull(r_CustomerContact.get("Phone"))) { m_Data.put("Customer_Contact.Phone",r_CustomerContact.get("Phone")); } if(!isNull(r_CustomerContact.get("Email"))) { v_EndCustomerEmail = r_CustomerContact.get("Email"); m_Data.put("Customer_Contact.Email",v_EndCustomerEmail); } if(!isNull(r_CustomerContact.get("Account_Name"))) { v_EndCustomerAccountID = r_CustomerContact.get("Account_Name").get("id").toLong(); } } // // get organization phone number m_OrgDetails = Map(); r_Response = zoho.crm.invokeConnector("crm.getorg",m_OrgDetails); if(!isnull(r_Response.get("status_code"))) { if(r_Response.get("status_code") == 200) { l_OrgDetails = r_Response.get("response").get("org"); for each r_Org in l_OrgDetails { m_Data.put("org.phone",r_Org.get("phone")); } } } // // map other values from this record v_OwnerID = "0"; if(!isNull(r_RecordDetails.get("Attending_Engineer"))) { m_Data.put("Attending_Engineer",r_RecordDetails.get("Attending_Engineer").get("name")); } if(!isNull(r_RecordDetails.get("Service_Start_Time"))) { m_Data.put("Service_Start_Time",r_RecordDetails.get("Service_Start_Time").replaceAll("T"," ",true).getPrefix("+").toTime().toString("dd-MMM-yyyy HH:mm","Europe/London")); } if(!isNull(r_RecordDetails.get("Service_End_Time"))) { m_Data.put("Service_End_Time",r_RecordDetails.get("Service_End_Time").replaceAll("T"," ",true).getPrefix("+").toTime().toString("dd-MMM-yyyy HH:mm","Europe/London")); } // ... MAP FURTHER VALUES // // merge the data into the template (for ZohoWriter) m_MergedData = Map(); m_MergedData.put("merge_data",{"data":m_Data}); //info m_MergedData; // // *************************************** // default first recipient to record owner l_Recipients = List(); v_EngineerID = r_RecordDetails.get("Owner").get("id"); v_EngineerFullName = r_RecordDetails.get("Owner").get("name"); v_EngineerEmail = r_RecordDetails.get("Owner").get("email"); // // get first recipient (engineer) if(!isNull(r_RecordDetails.get("Attending_Engineer"))) { v_User_EngineerID = r_RecordDetails.get("Attending_Engineer").get("id"); r_Users = zoho.crm.getRecords("users"); for each m_User in r_Users.get("users") { if(m_User.get("id").equalsIgnoreCase(v_User_EngineerID)) { v_EngineerID = m_User.get("id"); v_EngineerFullName = m_User.get("full_name"); v_EngineerEmail = m_User.get("email"); } // // get manager approver while we're here (where manager name = Joel Lipman) if(m_User.get("full_name").equalsIgnoreCase("Joel Lipman")) { v_ManagerID = m_User.get("id"); v_ManagerFullName = m_User.get("full_name"); v_ManagerEmail = m_User.get("email"); } } } // // OVERRIDES: for testing purposes if(b_Debug) { v_EngineerFullName = "Engineering Joel"; v_EngineerEmail = "This email address is being protected from spambots. You need JavaScript enabled to view it."; v_ManagerFullName = "Approving Joel"; v_ManagerEmail = "This email address is being protected from spambots. You need JavaScript enabled to view it."; v_EndCustomerFullName = "Customer Joel"; v_EndCustomerEmail = "This email address is being protected from spambots. You need JavaScript enabled to view it."; } // // engineer recipient (job notes to add - A4 size) m_RecipientSigner = Map(); m_RecipientSigner.put("recipient_1",v_EngineerEmail); m_RecipientSigner.put("recipient_name",v_EngineerFullName); m_RecipientSigner.put("action_type","sign"); m_RecipientSigner.put("private_notes","Please complete and sign the document before it is sent for manager approval: " + v_ManagerFullName); l_Recipients.add(m_RecipientSigner); // // manager recipient (approver) m_RecipientCopy = Map(); m_RecipientCopy.put("recipient_2",v_ManagerEmail); m_RecipientCopy.put("recipient_name",v_ManagerFullName); m_RecipientCopy.put("action_type","approve"); m_RecipientCopy.put("private_notes","The engineer has completed this document. Please check and approve this document before I send this to the customer: " + v_EndCustomerFullName); l_Recipients.add(m_RecipientCopy); // // end user recipient (approver) m_RecipientCopy = Map(); m_RecipientCopy.put("recipient_3",v_EndCustomerEmail); m_RecipientCopy.put("recipient_name",v_EndCustomerFullName); m_RecipientCopy.put("action_type","approve"); m_RecipientCopy.put("private_notes","Please read and confirm you approve of this document. You will receive a copy for your records once completed."); l_Recipients.add(m_RecipientCopy); //info l_Recipients; // // some signing options v_DaysUntilExpiry = 3; m_Options = Map(); m_Options.put("sign_in_order","true"); m_Options.put("set_expire",v_DaysUntilExpiry.toString()); m_Options.put("reminder_period",v_DaysUntilExpiry); // // send for signature v_Filename = v_FileNameWithouExt + ".pdf"; r_ZohoSignRequest = zoho.writer.mergeAndSign(v_TemplateID,m_MergedData,v_Filename,l_Recipients,m_Options,"my_writer_connection"); // info r_ZohoSignRequest; // // track in CRM Zoho Sign (need request ID) l_ZohoSignResponses = ifnull(r_ZohoSignRequest.get("records"),List()); for each m_ZohoSignResponse in l_ZohoSignResponses { if(!isNull(m_ZohoSignResponse.get("sign_request_id"))) { // // Create CRM Record ZohoSign Documents for tracking progress m_ZCrm_ZSDoc = Map(); m_ZCrm_ZSDoc.put("Name",v_FileNameWithouExt); m_ZCrm_ZSDoc.put("zohosign__Contact",v_EndCustomerContactID); m_ZCrm_ZSDoc.put("Email",v_EndCustomerEmail); if(v_EndCustomerAccountID != 0) { m_ZCrm_ZSDoc.put("zohosign__Account",v_EndCustomerAccountID); } m_ZCrm_ZSDoc.put("zohosign__Owner",v_ZCRM_DocOwnerID); m_ZCrm_ZSDoc.put("zohosign__Date_Sent",zoho.currentdate); m_ZCrm_ZSDoc.put("zohosign__Module_Name",v_ModuleName); m_ZCrm_ZSDoc.put("zohosign__Module_Record_ID",p_MaintenanceID.toString()); m_ZCrm_ZSDoc.put("zohosign__Document_Deadline",zoho.currentdate.addDay(v_DaysUntilExpiry)); m_ZCrm_ZSDoc.put("zohosign__Document_Status","Out for Signature"); // Request_ID is a custom field added to retrieve the document later from ZohoWriter. m_ZCrm_ZSDoc.put("Request_ID",m_ZohoSignResponse.get("sign_request_id")); r_ZCrm_ZSDoc = zoho.crm.createRecord("zohosign__ZohoSign_Documents",m_ZCrm_ZSDoc); // // create CRM zohosign document child records (recipient and event) if(!isNull(r_ZCrm_ZSDoc.get("id"))) { // // get logged in user (who clicked the button) v_LoggedInUserID = 0; r_Users = zoho.crm.getRecords("users"); for each m_User in r_Users.get("users") { if(m_User.get("email").equalsIgnoreCase(zoho.loginuserid)) { v_LoggedInUserID = m_User.get("id"); } } // // create CRM zohosign document recipient(s) v_RecipientIndex = 0; for each m_Recipient in l_Recipients { v_RecipientIndex = v_RecipientIndex + 1; m_CreateRecipient = Map(); m_CreateRecipient.put("Name",m_Recipient.get("recipient_name")); m_CreateRecipient.put("Email",m_Recipient.get("recipient_" + v_RecipientIndex)); m_CreateRecipient.put("Owner",v_LoggedInUserID); m_CreateRecipient.put("zohosign__Recipient_Order",v_RecipientIndex); m_CreateRecipient.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id")); v_RecipientType = if(m_Recipient.get("action_type") == "sign","Signer","Approver"); m_CreateRecipient.put("zohosign__Recipient_Type",v_RecipientType); m_CreateRecipient.put("zohosign__Recipient_Status","Sent"); r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient); } // // create CRM zohosign document event (1st to engineer) m_CreateEvent = Map(); m_CreateEvent.put("Name",v_SignType + "-SENT"); m_CreateEvent.put("Owner",v_LoggedInUserID); m_CreateEvent.put("Email",zoho.loginuserid); m_CreateEvent.put("zohosign__Date",zoho.currentdate); m_CreateEvent.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id")); m_CreateEvent.put("zohosign__Description","Sent out for signature"); r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent); } // // output result to user v_OutputMessage = v_SignType + " sent to " + v_EngineerFullName + " (" + v_EngineerEmail + ") for signing."; } } // // return response to user return v_OutputMessage;
- /* *******************************************************************************
- Function: string fn_MailMerge_Maintenance(String p_MaintenanceID)
- Label: Fn - Mail Merge - Maintenance
- Trigger: Off a button on the maintenance record
- Purpose: Function used by button off maintenance record to send a Maintenance Report to the customer contact.
- Inputs: Record ID
- Outputs: Attachment to the CRM record
- Date Created: 2024-08-07 (Joel Lipman)
- - Initial release
- Date Modified: 2024-08-22 (Joel Lipman)
- - Creates ZohoSign Document records in ZohoCRM (for tracking progress of e-sign process)
- More Information:
- https://www.joellipman.com/articles/crm/zoho/zoho-crm-zoho-writer-button-to-merge-template,-send,-and-attach.html
- https://www.zoho.com/deluge/help/writer/merge-and-sign.html
- https://www.zoho.com/deluge/help/script/sign/create-using-template.html
- ErrorCode: R6006
- message: Invalid signer info. Please try again with proper signer info.
- Solution: Recipients list was incorrect and I'd assigned the recipient twice.
- Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all
- Also note that the document already exists as a mail merge template in CRM.
- ******************************************************************************* */
- //
- b_Debug = true;
- v_ModuleName = "Maintenance";
- v_OutputMessage = "";
- r_RecordDetails = zoho.crm.getRecordById(v_ModuleName,p_MaintenanceID);
- //info r_RecordDetails;
- v_AttachmentDate = zoho.currentdate.toString("dd-MMM-yyyy");
- v_SignType = "Maintenance Report";
- v_FileNameWithouExt = v_SignType;
- //
- // Specify template ID
- // check URL https://sign.zoho.com/zs#/template/viewer/<template_id>
- v_TemplateID = "abcdefghijklmnopqrstuvwxyz01234567890";
- //
- // get merge field names (for reference - not used later in this fuction)
- // r_Fields = zoho.writer.getMergeFields(v_TemplateID,"my_writer_connection");
- //info r_Fields;
- //
- // map data to these fields
- m_Data = Map();
- //
- // get reference number for filename
- if(!isNull(r_RecordDetails.get("Name")))
- {
- v_SetFilename = v_SignType + " " + r_RecordDetails.get("Name");
- }
- //
- // get maintenance record item lookup and map values
- if(!isNull(r_RecordDetails.get("Lookup_Serial_Number")))
- {
- r_CustomerAsset = zoho.crm.getRecordById("Assets",r_RecordDetails.get("Lookup_Serial_Number").get("id"));
- if(!isNull(r_CustomerAsset.get("Account_Name")))
- {
- m_Data.put("Lookup_Serial_Number.Account_Name",r_CustomerAsset.get("Account_Name").get("name"));
- }
- // .. MAP ALL OTHER FIELDS
- }
- //
- // get customer contact record
- v_EndCustomerFullName = "";
- v_EndCustomerEmail = "";
- v_EndCustomerAccountID = 0;
- v_EndCustomerContactID = 0;
- if(!isNull(r_RecordDetails.get("Customer_Contact")))
- {
- v_EndCustomerContactID = r_RecordDetails.get("Customer_Contact").get("id").toLong();
- r_CustomerContact = zoho.crm.getRecordById("Contacts",v_EndCustomerContactID);
- if(!isNull(r_CustomerContact.get("Full_Name")))
- {
- v_EndCustomerFullName = r_CustomerContact.get("Full_Name");
- m_Data.put("Customer_Contact.Full_Name",v_EndCustomerFullName);
- }
- if(!isNull(r_CustomerContact.get("Phone")))
- {
- m_Data.put("Customer_Contact.Phone",r_CustomerContact.get("Phone"));
- }
- if(!isNull(r_CustomerContact.get("Email")))
- {
- v_EndCustomerEmail = r_CustomerContact.get("Email");
- m_Data.put("Customer_Contact.Email",v_EndCustomerEmail);
- }
- if(!isNull(r_CustomerContact.get("Account_Name")))
- {
- v_EndCustomerAccountID = r_CustomerContact.get("Account_Name").get("id").toLong();
- }
- }
- //
- // get organization phone number
- m_OrgDetails = Map();
- r_Response = zoho.crm.invokeConnector("crm.getorg",m_OrgDetails);
- if(!isnull(r_Response.get("status_code")))
- {
- if(r_Response.get("status_code") == 200)
- {
- l_OrgDetails = r_Response.get("response").get("org");
- for each r_Org in l_OrgDetails
- {
- m_Data.put("org.phone",r_Org.get("phone"));
- }
- }
- }
- //
- // map other values from this record
- v_OwnerID = "0";
- if(!isNull(r_RecordDetails.get("Attending_Engineer")))
- {
- m_Data.put("Attending_Engineer",r_RecordDetails.get("Attending_Engineer").get("name"));
- }
- if(!isNull(r_RecordDetails.get("Service_Start_Time")))
- {
- m_Data.put("Service_Start_Time",r_RecordDetails.get("Service_Start_Time").replaceAll("T"," ",true).getPrefix("+").toTime().toString("dd-MMM-yyyy HH:mm","Europe/London"));
- }
- if(!isNull(r_RecordDetails.get("Service_End_Time")))
- {
- m_Data.put("Service_End_Time",r_RecordDetails.get("Service_End_Time").replaceAll("T"," ",true).getPrefix("+").toTime().toString("dd-MMM-yyyy HH:mm","Europe/London"));
- }
- // ... MAP FURTHER VALUES
- //
- // merge the data into the template (for ZohoWriter)
- m_MergedData = Map();
- m_MergedData.put("merge_data",{"data":m_Data});
- //info m_MergedData;
- //
- // ***************************************
- // default first recipient to record owner
- l_Recipients = List();
- v_EngineerID = r_RecordDetails.get("Owner").get("id");
- v_EngineerFullName = r_RecordDetails.get("Owner").get("name");
- v_EngineerEmail = r_RecordDetails.get("Owner").get("email");
- //
- // get first recipient (engineer)
- if(!isNull(r_RecordDetails.get("Attending_Engineer")))
- {
- v_User_EngineerID = r_RecordDetails.get("Attending_Engineer").get("id");
- r_Users = zoho.crm.getRecords("users");
- for each m_User in r_Users.get("users")
- {
- if(m_User.get("id").equalsIgnoreCase(v_User_EngineerID))
- {
- v_EngineerID = m_User.get("id");
- v_EngineerFullName = m_User.get("full_name");
- v_EngineerEmail = m_User.get("email");
- }
- //
- // get manager approver while we're here (where manager name = Joel Lipman)
- if(m_User.get("full_name").equalsIgnoreCase("Joel Lipman"))
- {
- v_ManagerID = m_User.get("id");
- v_ManagerFullName = m_User.get("full_name");
- v_ManagerEmail = m_User.get("email");
- }
- }
- }
- //
- // OVERRIDES: for testing purposes
- if(b_Debug)
- {
- v_EngineerFullName = "Engineering Joel";
- v_EngineerEmail = "me+This email address is being protected from spambots. You need JavaScript enabled to view it.";
- v_ManagerFullName = "Approving Joel";
- v_ManagerEmail = "me+This email address is being protected from spambots. You need JavaScript enabled to view it.";
- v_EndCustomerFullName = "Customer Joel";
- v_EndCustomerEmail = "me+This email address is being protected from spambots. You need JavaScript enabled to view it.";
- }
- //
- // engineer recipient (job notes to add - A4 size)
- m_RecipientSigner = Map();
- m_RecipientSigner.put("recipient_1",v_EngineerEmail);
- m_RecipientSigner.put("recipient_name",v_EngineerFullName);
- m_RecipientSigner.put("action_type","sign");
- m_RecipientSigner.put("private_notes","Please complete and sign the document before it is sent for manager approval: " + v_ManagerFullName);
- l_Recipients.add(m_RecipientSigner);
- //
- // manager recipient (approver)
- m_RecipientCopy = Map();
- m_RecipientCopy.put("recipient_2",v_ManagerEmail);
- m_RecipientCopy.put("recipient_name",v_ManagerFullName);
- m_RecipientCopy.put("action_type","approve");
- m_RecipientCopy.put("private_notes","The engineer has completed this document. Please check and approve this document before I send this to the customer: " + v_EndCustomerFullName);
- l_Recipients.add(m_RecipientCopy);
- //
- // end user recipient (approver)
- m_RecipientCopy = Map();
- m_RecipientCopy.put("recipient_3",v_EndCustomerEmail);
- m_RecipientCopy.put("recipient_name",v_EndCustomerFullName);
- m_RecipientCopy.put("action_type","approve");
- m_RecipientCopy.put("private_notes","Please read and confirm you approve of this document. You will receive a copy for your records once completed.");
- l_Recipients.add(m_RecipientCopy);
- //info l_Recipients;
- //
- // some signing options
- v_DaysUntilExpiry = 3;
- m_Options = Map();
- m_Options.put("sign_in_order","true");
- m_Options.put("set_expire",v_DaysUntilExpiry.toString());
- m_Options.put("reminder_period",v_DaysUntilExpiry);
- //
- // send for signature
- v_Filename = v_FileNameWithouExt + ".pdf";
- r_ZohoSignRequest = zoho.writer.mergeAndSign(v_TemplateID,m_MergedData,v_Filename,l_Recipients,m_Options,"my_writer_connection");
- // info r_ZohoSignRequest;
- //
- // track in CRM Zoho Sign (need request ID)
- l_ZohoSignResponses = ifnull(r_ZohoSignRequest.get("records"),List());
- for each m_ZohoSignResponse in l_ZohoSignResponses
- {
- if(!isNull(m_ZohoSignResponse.get("sign_request_id")))
- {
- //
- // Create CRM Record ZohoSign Documents for tracking progress
- m_ZCrm_ZSDoc = Map();
- m_ZCrm_ZSDoc.put("Name",v_FileNameWithouExt);
- m_ZCrm_ZSDoc.put("zohosign__Contact",v_EndCustomerContactID);
- m_ZCrm_ZSDoc.put("Email",v_EndCustomerEmail);
- if(v_EndCustomerAccountID != 0)
- {
- m_ZCrm_ZSDoc.put("zohosign__Account",v_EndCustomerAccountID);
- }
- m_ZCrm_ZSDoc.put("zohosign__Owner",v_ZCRM_DocOwnerID);
- m_ZCrm_ZSDoc.put("zohosign__Date_Sent",zoho.currentdate);
- m_ZCrm_ZSDoc.put("zohosign__Module_Name",v_ModuleName);
- m_ZCrm_ZSDoc.put("zohosign__Module_Record_ID",p_MaintenanceID.toString());
- m_ZCrm_ZSDoc.put("zohosign__Document_Deadline",zoho.currentdate.addDay(v_DaysUntilExpiry));
- m_ZCrm_ZSDoc.put("zohosign__Document_Status","Out for Signature");
- // Request_ID is a custom field added to retrieve the document later from ZohoWriter.
- m_ZCrm_ZSDoc.put("Request_ID",m_ZohoSignResponse.get("sign_request_id"));
- r_ZCrm_ZSDoc = zoho.crm.createRecord("zohosign__ZohoSign_Documents",m_ZCrm_ZSDoc);
- //
- // create CRM zohosign document child records (recipient and event)
- if(!isNull(r_ZCrm_ZSDoc.get("id")))
- {
- //
- // get logged in user (who clicked the button)
- v_LoggedInUserID = 0;
- r_Users = zoho.crm.getRecords("users");
- for each m_User in r_Users.get("users")
- {
- if(m_User.get("email").equalsIgnoreCase(zoho.loginuserid))
- {
- v_LoggedInUserID = m_User.get("id");
- }
- }
- //
- // create CRM zohosign document recipient(s)
- v_RecipientIndex = 0;
- for each m_Recipient in l_Recipients
- {
- v_RecipientIndex = v_RecipientIndex + 1;
- m_CreateRecipient = Map();
- m_CreateRecipient.put("Name",m_Recipient.get("recipient_name"));
- m_CreateRecipient.put("Email",m_Recipient.get("recipient_" + v_RecipientIndex));
- m_CreateRecipient.put("Owner",v_LoggedInUserID);
- m_CreateRecipient.put("zohosign__Recipient_Order",v_RecipientIndex);
- m_CreateRecipient.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id"));
- v_RecipientType = if(m_Recipient.get("action_type") == "sign","Signer","Approver");
- m_CreateRecipient.put("zohosign__Recipient_Type",v_RecipientType);
- m_CreateRecipient.put("zohosign__Recipient_Status","Sent");
- r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient);
- }
- //
- // create CRM zohosign document event (1st to engineer)
- m_CreateEvent = Map();
- m_CreateEvent.put("Name",v_SignType + "-SENT");
- m_CreateEvent.put("Owner",v_LoggedInUserID);
- m_CreateEvent.put("Email",zoho.loginuserid);
- m_CreateEvent.put("zohosign__Date",zoho.currentdate);
- m_CreateEvent.put("zohosign__ZohoSign_Document",r_ZCrm_ZSDoc.get("id"));
- m_CreateEvent.put("zohosign__Description","Sent out for signature");
- r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent);
- }
- //
- // output result to user
- v_OutputMessage = v_SignType + " sent to " + v_EngineerFullName + " (" + v_EngineerEmail + ") for signing.";
- }
- }
- //
- // return response to user
- return v_OutputMessage;
Caveat
Genericizing the webhookIf your subscription plan doesn't allow more than 2 webhooks, then you can't use a different webhook for each event. Instead I've created the one webhook to rule them all which triggers on any event:
/* *******************************************************************************
Function: String fn_ZohoSign_Webhook(string crmAPIRequest)
Label: Fn - ZohoSign - Document Approved
Trigger: Webhook when ZohoSign sees an approved document
Purpose: This function is used as a webhook when ZohoSign detects an event
Inputs: crmAPIRequest
Outputs: crmAPIResponse
Date Created: 2024-08-06 (Joel Lipman)
- Initial release
Date Modified: 2024-08-07 (Joel Lipman)
- Modified to attach the signed document to the originating Contact Record
Date Modified: 2024-08-21 (Joel Lipman)
- Modified to allow for any event from ZohoSign (as Subscription Plan only allowed 2 webhooks)
Date Modified: 2024-08-22 (Joel Lipman)
- Handles forwarded and declined events
More Information:
https://www.zoho.com/deluge/help/sign-tasks.html
https://www.zoho.com/deluge/help/sign/get-document-by-id.html
https://www.zoho.com/deluge/help/sign/download-document.html
Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all
******************************************************************************* */
//
// initialize
b_DebugMode = true;
v_DebugMessage = "";
v_ZS_RequestName = "";
v_ZS_RequestID = 0;
v_ActionType = "Viewed";
b_UpdateRecipient = false;
v_DocStatusSuffix = "UNKNOWN";
v_ZCRM_DocCreated = null;
v_ZCRM_DocRecordID = 0;
v_ZCRM_DocRecordOwnerID = 0;
v_ZCRM_DocRecordAccountID = 0;
v_RecipientEmail = "";
//
// parse webhook body
m_Body = ifnull(crmAPIRequest.get("body"),Map());
if(b_DebugMode)
{
v_DebugMessage = "Body:<br /><br />" + m_Body + "<hr />";
}
//
// parse webhook requests
if(!isNull(m_Body.get("requests")))
{
m_Request = m_Body.get("requests");
v_ZS_RequestID = ifnull(m_Request.get("request_id"),"0").toLong();
v_ZS_RequestName = ifnull(m_Request.get("request_name"),"");
v_ZCRM_DocRecordName = v_ZS_RequestName;
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "Request: <br /><br />" + v_ZS_RequestID + " :: " + v_ZS_RequestName + "<hr />";
}
//
// get the ZohoSign Document record in CRM
if(v_ZS_RequestID != 0)
{
//
// find the CRM "ZohoSign Documents" record
l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","Request_ID:equals:" + v_ZS_RequestID);
for each m_ZCRM_Doc in l_SearchResults
{
//
// check we have the right one
if(m_ZCRM_Doc.get("Request_ID") == v_ZS_RequestID)
{
//
// retrieve the CRM "ZohoSign Documents" record ID and owner
v_ZCRM_DocRecordName = m_ZCRM_Doc.get("Name");
v_ZCRM_DocRecordID = m_ZCRM_Doc.get("id").toLong();
v_ZCRM_DocRecordOwnerID = m_ZCRM_Doc.get("Owner").get("id").toLong();
v_ZCRM_DocRecordAccountID = m_ZCRM_Doc.get("zohosign__Account").get("id").toLong();
v_RecipientEmail = m_ZCRM_Doc.get("Email");
v_ZCRM_DocCreated = m_ZCRM_Doc.get("Created_Time");
}
}
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "Document: <br /><br />" + v_ZCRM_DocRecordID + " :: " + v_ZCRM_DocRecordOwnerID + "<br />If this is zero then no matching record was found.<hr />";
}
//
// get ZohoSign Document ID (only if template exists in ZohoSign)
v_ZS_DocID = 0;
for each m_Document in m_Request.get("document_ids")
{
if(!isNull(m_Document.get("document_id")))
{
v_ZS_DocID = m_Document.get("document_id").toLong();
}
}
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "ZS Document: <br /><br />" + v_ZS_DocID + "<hr />";
}
//
//
// ****************************************
// capture different events
if(v_ZCRM_DocRecordID != 0)
{
//
// only create document events for the following
l_CreateEventsFor = {"RequestViewed","RequestSigningSuccess","RequestApproved","RequestForwarded","RequestCompleted","RequestRejected"};
//
// check notifications
if(!isNull(m_Body.get("notifications")))
{
m_UpdateDoc = Map();
m_Notification = m_Body.get("notifications");
//
// evaluate values for CRM zohosign document event
if(l_CreateEventsFor.contains(m_Notification.get("operation_type")))
{
if(m_Notification.get("operation_type") == "RequestViewed")
{
v_DocStatusSuffix = "VIEWED";
b_UpdateRecipient = true;
v_RecipientEmail = m_Notification.get("performed_by_email");
}
else if(m_Notification.get("operation_type") == "RequestApproved")
{
v_DocStatusSuffix = "APPROVED";
b_UpdateRecipient = true;
v_RecipientEmail = m_Notification.get("performed_by_email");
}
else if(m_Notification.get("operation_type") == "RequestSigningSuccess")
{
v_DocStatusSuffix = "SIGNED";
b_UpdateRecipient = true;
v_RecipientEmail = m_Notification.get("performed_by_email");
}
else if(m_Notification.get("operation_type") == "RequestCompleted")
{
v_DocStatusSuffix = "COMPLETED";
b_UpdateRecipient = true;
//
// time to complete
if(!isNull(v_ZCRM_DocCreated))
{
v_DaysBetween = v_ZCRM_DocCreated.getPrefix("T").toDate().daysBetween(zoho.currentdate);
v_DaysBetweenStr = v_DaysBetween + if(v_DaysBetween == 1," day"," days");
m_UpdateDoc.put("zohosign__Time_to_complete",v_DaysBetweenStr);
}
//
m_UpdateDoc.put("zohosign__Date_Completed",zoho.currentdate);
}
else if(m_Notification.get("operation_type") == "RequestForwarded")
{
v_DocStatusSuffix = "FORWARDED";
//
// create a new/use existing CRM contact
v_MatchedContactID = 0;
v_RecipientEmail = m_Notification.get("beneficiary_email");
l_SearchContacts = zoho.crm.searchRecords("Contacts","Email:equals:" + m_Notification.get("beneficiary_email"));
for each m_MatchedContact in l_SearchContacts
{
if(!isNull(m_MatchedContact.get("id")))
{
v_MatchedContactID = m_MatchedContact.get("id").toLong();
}
}
if(v_MatchedContactID == 0)
{
v_FullName = ifnull(m_Notification.get("beneficiary_name"),"").trim();
m_CreateContact = Map();
if(v_FullName.contains(" "))
{
v_Forenames = v_FullName.subString(0,v_FullName.lastIndexOf(" "));
v_LastName = v_FullName.subString(v_FullName.lastIndexOf(" "));
m_CreateContact.put("First_Name",v_Forenames);
m_CreateContact.put("Last_Name",v_LastName);
}
else
{
m_CreateContact.put("First_Name",v_FullName);
}
m_CreateContact.put("Email",m_Notification.get("beneficiary_email"));
m_CreateContact.put("Account_Name",v_ZCRM_DocRecordAccountID);
m_CreateContact.put("Contact_Status","Active");
m_CreateContact.put("Lead_Source_Detail","Created as a forwarded signee in ZohoSign");
r_CreateContact = zoho.crm.createRecord("Contacts",m_CreateContact);
if(!isNull(r_CreateContact.get("id")))
{
v_MatchedContactID = r_CreateContact.get("id").toLong();
}
}
//
m_UpdateDoc.put("Email",m_Notification.get("beneficiary_email"));
m_UpdateDoc.put("zohosign__Contact",v_MatchedContactID);
}
else if(m_Notification.get("operation_type") == "RequestRejected")
{
v_DocStatusSuffix = "DECLINED";
b_UpdateRecipient = true;
v_RecipientEmail = m_Notification.get("performed_by_email");
//
m_UpdateDoc.put("zohosign__Date_Declined",zoho.currentdate);
m_UpdateDoc.put("zohosign__Declined_Reason",m_Notification.get("reason"));
}
//
// finish updating the ZohoSign Document record
m_UpdateDoc.put("zohosign__Document_Status",v_DocStatusSuffix.proper());
r_UpdateDoc = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID,m_UpdateDoc);
//
// create CRM zohosign document event
m_CreateEvent = Map();
m_CreateEvent.put("Name",v_ZCRM_DocRecordName + " -" + v_DocStatusSuffix);
m_CreateEvent.put("Owner",v_ZCRM_DocRecordOwnerID);
if(m_Notification.get("performed_by_email") != "System Generated")
{
m_CreateEvent.put("Email",m_Notification.get("performed_by_email"));
}
m_CreateEvent.put("zohosign__Date",zoho.currentdate);
m_CreateEvent.put("zohosign__ZohoSign_Document",v_ZCRM_DocRecordID);
m_CreateEvent.put("zohosign__Description",m_Notification.get("activity"));
//
// create the event record
r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent);
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "ZCRM Event Record: <br /><br />" + r_CreateEvent + "<hr />";
}
//
// Fix for ZohoSign: if forwarded to another signee then completed, webhook on completed is not triggered???
if(m_Request.get("request_status") == "completed")
{
m_UpdateDoc = Map();
//
// time to complete
if(!isNull(v_ZCRM_DocCreated))
{
v_DaysBetween = v_ZCRM_DocCreated.getPrefix("T").toDate().daysBetween(zoho.currentdate);
v_DaysBetweenStr = if(v_DaysBetween == 1," day","days");
m_UpdateDoc.put("zohosign__Time_to_complete",v_DaysBetweenStr);
}
r_DocDetails = zoho.crm.getRecordById("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID);
v_ExistingNotes = ifnull(r_DocDetails.get("zohosign__Document_Note"),"");
l_ExistingNotes = v_ExistingNotes.toList("\n");
l_ExistingNotes.add("Completed: " + zoho.currenttime.toString("yyyy-MM-dd HH:mm:ss","Europe/London"));
m_UpdateDoc.put("zohosign__Document_Status","Completed");
m_UpdateDoc.put("zohosign__Document_Note",l_ExistingNotes.toString("\n"));
m_UpdateDoc.put("zohosign__Date_Completed",zoho.currentdate);
r_UpdateDoc = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID,m_UpdateDoc);
}
//
// if we want to update the recipient record
if(b_UpdateRecipient)
{
//
// find the relevant recipient record
for each m_Action in m_Request.get("actions")
{
if(!isNull(m_Action.get("action_status")) && v_RecipientEmail != "")
{
v_ZCRM_RecipientRecordID = 0;
l_SearchRecipients = zoho.crm.searchRecords("zohosign__ZohoSign_Recipients","(Email:equals:" + v_RecipientEmail + ")and(zohosign__ZohoSign_Document:equals:" + v_ZCRM_DocRecordID + ")");
for each m_Recipient in l_SearchRecipients
{
if(!isNull(m_Recipient.get("id")))
{
v_ZCRM_RecipientRecordID = m_Recipient.get("id").toLong();
}
}
if(v_ZCRM_RecipientRecordID == 0 && !m_Action.get("action_status").equalsIgnoreCase("FORWARDED"))
{
//
// create CRM zohosign document recipient record
m_CreateRecipient = Map();
m_CreateRecipient.put("Name",m_Action.get("recipient_name"));
m_CreateRecipient.put("Email",m_Action.get("recipient_email"));
m_CreateRecipient.put("Owner",v_ZCRM_DocRecordOwnerID);
m_CreateRecipient.put("zohosign__Recipient_Order",m_Action.get("signing_order"));
if(v_DocStatusSuffix == "COMPLETED")
{
m_CreateRecipient.put("zohosign__Date_Completed",zoho.currentdate);
}
else if(v_DocStatusSuffix == "DECLINED")
{
m_CreateRecipient.put("zohosign__Date_Declined",zoho.currentdate);
}
else
{
m_CreateRecipient.put("zohosign__Date_Delivered",zoho.currentdate);
}
m_CreateRecipient.put("zohosign__ZohoSign_Document",v_ZCRM_DocRecordID);
v_RecipientType = "CC";
if(m_Action.get("action_type").equalsIgnoreCase("APPROVE"))
{
v_RecipientType = "Approver";
}
else if(m_Action.get("action_type").equalsIgnoreCase("SIGN"))
{
v_RecipientType = "Signer";
}
m_CreateRecipient.put("zohosign__Recipient_Type",v_RecipientType);
v_RecipientStatus = if(v_DocStatusSuffix == "SIGNED" || v_DocStatusSuffix == "APPROVED" || v_DocStatusSuffix == "FORWARDED" || v_DocStatusSuffix == "VIEWED","Delivered",v_DocStatusSuffix.proper());
m_CreateRecipient.put("zohosign__Recipient_Status",v_RecipientStatus);
if(v_ZS_DocID != 0)
{
m_CreateRecipient.put("zohosign__ZohoSign_Document_ID",v_ZS_DocID.toString());
}
//
// create the recipient record
r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient);
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "ZCRM Recipient Record - CREATE: <br />" + m_Action.get("recipient_name") + "<br />" + r_CreateRecipient + "<hr />";
}
}
else if(v_ZCRM_RecipientRecordID != 0 && m_Action.get("recipient_email").equalsIgnoreCase(m_Notification.get("performed_by_email")))
{
//
// update CRM zohosign document recipient record
m_UpdateRecipient = Map();
m_UpdateRecipient.put("zohosign__Recipient_Order",m_Action.get("signing_order"));
v_RecipientType = "CC";
if(m_Action.get("action_type").equalsIgnoreCase("APPROVE"))
{
v_RecipientType = "Approver";
}
else if(m_Action.get("action_type").equalsIgnoreCase("SIGN"))
{
v_RecipientType = "Signer";
}
m_UpdateRecipient.put("zohosign__Recipient_Type",v_RecipientType);
v_RecipientStatus = if(v_DocStatusSuffix == "SIGNED" || v_DocStatusSuffix == "APPROVED" || v_DocStatusSuffix == "FORWARDED" || v_DocStatusSuffix == "VIEWED","Delivered",v_DocStatusSuffix.proper());
m_UpdateRecipient.put("zohosign__Recipient_Status",v_RecipientStatus);
if(v_DocStatusSuffix == "COMPLETED")
{
m_UpdateRecipient.put("zohosign__Date_Completed",zoho.currentdate);
}
else if(v_DocStatusSuffix == "DECLINED")
{
m_UpdateRecipient.put("zohosign__Date_Declined",zoho.currentdate);
}
else
{
m_UpdateRecipient.put("zohosign__Date_Delivered",zoho.currentdate);
}
if(v_ZS_DocID != 0)
{
m_UpdateRecipient.put("zohosign__ZohoSign_Document_ID",v_ZS_DocID.toString());
}
r_UpdateRecipient = zoho.crm.updateRecord("zohosign__ZohoSign_Recipients",v_ZCRM_RecipientRecordID,m_UpdateRecipient);
if(b_DebugMode)
{
v_DebugMessage = v_DebugMessage + "ZCRM Recipient Record - UPDATE: <br /><br />" + r_UpdateRecipient + "<hr />";
}
}
}
}
}
}
}
}
//
// now attach to CRM Record if completed
if(v_ZCRM_DocRecordID != 0 && v_DocStatusSuffix == "COMPLETED")
{
r_ZCRM_DocumentDetails = zoho.crm.getRecordById("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID);
if(!isNull(r_ZCRM_DocumentDetails.get("zohosign__Module_Record_ID")))
{
//
// get module and record ID
v_ModuleName = ifnull(r_ZCRM_DocumentDetails.get("zohosign__Module_Name"),"-");
v_ModuleRecordID = r_ZCRM_DocumentDetails.get("zohosign__Module_Record_ID");
v_ZS_DocumentName = ifnull(r_ZCRM_DocumentDetails.get("Name"),v_ModuleName);
//
// download file
r_ZS_Download = zoho.sign.downloadDocument(v_ZS_RequestID);
v_Filename = v_ZS_DocumentName;
if(!isNull(v_ZS_RequestName))
{
v_Filename = v_ZS_RequestName;
}
if(v_Filename.lastIndexOf(".") > 0)
{
v_Filename = v_Filename.subString(0,v_Filename.lastIndexOf("."));
}
r_ZS_Download.setFileName(v_Filename + "_SIGNED.pdf");
//
// attach file to record of module
r_AttachFile = zoho.crm.attachFile(v_ModuleName,v_ModuleRecordID,r_ZS_Download);
//
// for debug purposes but completely unnecessary for the function of this function
if(!isNull(r_AttachFile.get("message")))
{
v_DebugMessage = v_DebugMessage + "CRM Attachment: <br /><br />" + r_AttachFile.get("message") + "<hr />";
}
}
}
}
}
v_DebugMessage = v_DebugMessage + "Date/Time: <br /><br />" + zoho.currenttime;
//
if(b_DebugMode)
{
sendmail
[
from :zoho.adminuserid
to :"This email address is being protected from spambots. You need JavaScript enabled to view it."
subject :"My ZohoSign Webhook - ANY EVENT"
message :v_DebugMessage
]
}
return "";
- /* *******************************************************************************
- Function: string fn_ZohoSign_Webhook(string crmAPIRequest)
- Label: Fn - ZohoSign - Document Approved
- Trigger: Webhook when ZohoSign sees an approved document
- Purpose: This function is used as a webhook when ZohoSign detects an event
- Inputs: crmAPIRequest
- Outputs: crmAPIResponse
- Date Created: 2024-08-06 (Joel Lipman)
- - Initial release
- Date Modified: 2024-08-07 (Joel Lipman)
- - Modified to attach the signed document to the originating Contact Record
- Date Modified: 2024-08-21 (Joel Lipman)
- - Modified to allow for any event from ZohoSign (as Subscription Plan only allowed 2 webhooks)
- Date Modified: 2024-08-22 (Joel Lipman)
- - Handles forwarded and declined events
- More Information:
- https://www.zoho.com/deluge/help/sign-tasks.html
- https://www.zoho.com/deluge/help/sign/get-document-by-id.html
- https://www.zoho.com/deluge/help/sign/download-document.html
- Scope(s): ZohoSign.documents.ALL, ZohoSign.account.ALL, ZohoSign.templates.ALL, ZohoWriter.documentEditor.ALL, ZohoWriter.Merge.ALL, ZohoSign.setup.READ, WorkDrive.workspace.ALL, WorkDrive.files.ALL, ZohoCRM.modules.attachments.all
- ******************************************************************************* */
- //
- // initialize
- b_DebugMode = true;
- v_DebugMessage = "";
- v_ZS_RequestName = "";
- v_ZS_RequestID = 0;
- v_ActionType = "Viewed";
- b_UpdateRecipient = false;
- v_DocStatusSuffix = "UNKNOWN";
- v_ZCRM_DocCreated = null;
- v_ZCRM_DocRecordID = 0;
- v_ZCRM_DocRecordOwnerID = 0;
- v_ZCRM_DocRecordAccountID = 0;
- v_RecipientEmail = "";
- //
- // parse webhook body
- m_Body = ifnull(crmAPIRequest.get("body"),Map());
- if(b_DebugMode)
- {
- v_DebugMessage = "Body:<br /><br />" + m_Body + "<hr />";
- }
- //
- // parse webhook requests
- if(!isNull(m_Body.get("requests")))
- {
- m_Request = m_Body.get("requests");
- v_ZS_RequestID = ifnull(m_Request.get("request_id"),"0").toLong();
- v_ZS_RequestName = ifnull(m_Request.get("request_name"),"");
- v_ZCRM_DocRecordName = v_ZS_RequestName;
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "Request: <br /><br />" + v_ZS_RequestID + " :: " + v_ZS_RequestName + "<hr />";
- }
- //
- // get the ZohoSign Document record in CRM
- if(v_ZS_RequestID != 0)
- {
- //
- // find the CRM "ZohoSign Documents" record
- l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","Request_ID:equals:" + v_ZS_RequestID);
- for each m_ZCRM_Doc in l_SearchResults
- {
- //
- // check we have the right one
- if(m_ZCRM_Doc.get("Request_ID") == v_ZS_RequestID)
- {
- //
- // retrieve the CRM "ZohoSign Documents" record ID and owner
- v_ZCRM_DocRecordName = m_ZCRM_Doc.get("Name");
- v_ZCRM_DocRecordID = m_ZCRM_Doc.get("id").toLong();
- v_ZCRM_DocRecordOwnerID = m_ZCRM_Doc.get("Owner").get("id").toLong();
- v_ZCRM_DocRecordAccountID = m_ZCRM_Doc.get("zohosign__Account").get("id").toLong();
- v_RecipientEmail = m_ZCRM_Doc.get("Email");
- v_ZCRM_DocCreated = m_ZCRM_Doc.get("Created_Time");
- }
- }
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "Document: <br /><br />" + v_ZCRM_DocRecordID + " :: " + v_ZCRM_DocRecordOwnerID + "<br />If this is zero then no matching record was found.<hr />";
- }
- //
- // get ZohoSign Document ID (only if template exists in ZohoSign)
- v_ZS_DocID = 0;
- for each m_Document in m_Request.get("document_ids")
- {
- if(!isNull(m_Document.get("document_id")))
- {
- v_ZS_DocID = m_Document.get("document_id").toLong();
- }
- }
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "ZS Document: <br /><br />" + v_ZS_DocID + "<hr />";
- }
- //
- //
- // ****************************************
- // capture different events
- if(v_ZCRM_DocRecordID != 0)
- {
- //
- // only create document events for the following
- l_CreateEventsFor = {"RequestViewed","RequestSigningSuccess","RequestApproved","RequestForwarded","RequestCompleted","RequestRejected"};
- //
- // check notifications
- if(!isNull(m_Body.get("notifications")))
- {
- m_UpdateDoc = Map();
- m_Notification = m_Body.get("notifications");
- //
- // evaluate values for CRM zohosign document event
- if(l_CreateEventsFor.contains(m_Notification.get("operation_type")))
- {
- if(m_Notification.get("operation_type") == "RequestViewed")
- {
- v_DocStatusSuffix = "VIEWED";
- b_UpdateRecipient = true;
- v_RecipientEmail = m_Notification.get("performed_by_email");
- }
- else if(m_Notification.get("operation_type") == "RequestApproved")
- {
- v_DocStatusSuffix = "APPROVED";
- b_UpdateRecipient = true;
- v_RecipientEmail = m_Notification.get("performed_by_email");
- }
- else if(m_Notification.get("operation_type") == "RequestSigningSuccess")
- {
- v_DocStatusSuffix = "SIGNED";
- b_UpdateRecipient = true;
- v_RecipientEmail = m_Notification.get("performed_by_email");
- }
- else if(m_Notification.get("operation_type") == "RequestCompleted")
- {
- v_DocStatusSuffix = "COMPLETED";
- b_UpdateRecipient = true;
- //
- // time to complete
- if(!isNull(v_ZCRM_DocCreated))
- {
- v_DaysBetween = v_ZCRM_DocCreated.getPrefix("T").toDate().daysBetween(zoho.currentdate);
- v_DaysBetweenStr = v_DaysBetween + if(v_DaysBetween == 1," day"," days");
- m_UpdateDoc.put("zohosign__Time_to_complete",v_DaysBetweenStr);
- }
- //
- m_UpdateDoc.put("zohosign__Date_Completed",zoho.currentdate);
- }
- else if(m_Notification.get("operation_type") == "RequestForwarded")
- {
- v_DocStatusSuffix = "FORWARDED";
- //
- // create a new/use existing CRM contact
- v_MatchedContactID = 0;
- v_RecipientEmail = m_Notification.get("beneficiary_email");
- l_SearchContacts = zoho.crm.searchRecords("Contacts","Email:equals:" + m_Notification.get("beneficiary_email"));
- for each m_MatchedContact in l_SearchContacts
- {
- if(!isNull(m_MatchedContact.get("id")))
- {
- v_MatchedContactID = m_MatchedContact.get("id").toLong();
- }
- }
- if(v_MatchedContactID == 0)
- {
- v_FullName = ifnull(m_Notification.get("beneficiary_name"),"").trim();
- m_CreateContact = Map();
- if(v_FullName.contains(" "))
- {
- v_Forenames = v_FullName.subString(0,v_FullName.lastIndexOf(" "));
- v_LastName = v_FullName.subString(v_FullName.lastIndexOf(" "));
- m_CreateContact.put("First_Name",v_Forenames);
- m_CreateContact.put("Last_Name",v_LastName);
- }
- else
- {
- m_CreateContact.put("First_Name",v_FullName);
- }
- m_CreateContact.put("Email",m_Notification.get("beneficiary_email"));
- m_CreateContact.put("Account_Name",v_ZCRM_DocRecordAccountID);
- m_CreateContact.put("Contact_Status","Active");
- m_CreateContact.put("Lead_Source_Detail","Created as a forwarded signee in ZohoSign");
- r_CreateContact = zoho.crm.createRecord("Contacts",m_CreateContact);
- if(!isNull(r_CreateContact.get("id")))
- {
- v_MatchedContactID = r_CreateContact.get("id").toLong();
- }
- }
- //
- m_UpdateDoc.put("Email",m_Notification.get("beneficiary_email"));
- m_UpdateDoc.put("zohosign__Contact",v_MatchedContactID);
- }
- else if(m_Notification.get("operation_type") == "RequestRejected")
- {
- v_DocStatusSuffix = "DECLINED";
- b_UpdateRecipient = true;
- v_RecipientEmail = m_Notification.get("performed_by_email");
- //
- m_UpdateDoc.put("zohosign__Date_Declined",zoho.currentdate);
- m_UpdateDoc.put("zohosign__Declined_Reason",m_Notification.get("reason"));
- }
- //
- // finish updating the ZohoSign Document record
- m_UpdateDoc.put("zohosign__Document_Status",v_DocStatusSuffix.proper());
- r_UpdateDoc = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID,m_UpdateDoc);
- //
- // create CRM zohosign document event
- m_CreateEvent = Map();
- m_CreateEvent.put("Name",v_ZCRM_DocRecordName + " -" + v_DocStatusSuffix);
- m_CreateEvent.put("Owner",v_ZCRM_DocRecordOwnerID);
- if(m_Notification.get("performed_by_email") != "System Generated")
- {
- m_CreateEvent.put("Email",m_Notification.get("performed_by_email"));
- }
- m_CreateEvent.put("zohosign__Date",zoho.currentdate);
- m_CreateEvent.put("zohosign__ZohoSign_Document",v_ZCRM_DocRecordID);
- m_CreateEvent.put("zohosign__Description",m_Notification.get("activity"));
- //
- // create the event record
- r_CreateEvent = zoho.crm.createRecord("zohosign__ZohoSign_Document_Events",m_CreateEvent);
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "ZCRM Event Record: <br /><br />" + r_CreateEvent + "<hr />";
- }
- //
- // Fix for ZohoSign: if forwarded to another signee then completed, webhook on completed is not triggered???
- if(m_Request.get("request_status") == "completed")
- {
- m_UpdateDoc = Map();
- //
- // time to complete
- if(!isNull(v_ZCRM_DocCreated))
- {
- v_DaysBetween = v_ZCRM_DocCreated.getPrefix("T").toDate().daysBetween(zoho.currentdate);
- v_DaysBetweenStr = if(v_DaysBetween == 1," day","days");
- m_UpdateDoc.put("zohosign__Time_to_complete",v_DaysBetweenStr);
- }
- r_DocDetails = zoho.crm.getRecordById("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID);
- v_ExistingNotes = ifnull(r_DocDetails.get("zohosign__Document_Note"),"");
- l_ExistingNotes = v_ExistingNotes.toList("\n");
- l_ExistingNotes.add("Completed: " + zoho.currenttime.toString("yyyy-MM-dd HH:mm:ss","Europe/London"));
- m_UpdateDoc.put("zohosign__Document_Status","Completed");
- m_UpdateDoc.put("zohosign__Document_Note",l_ExistingNotes.toString("\n"));
- m_UpdateDoc.put("zohosign__Date_Completed",zoho.currentdate);
- r_UpdateDoc = zoho.crm.updateRecord("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID,m_UpdateDoc);
- }
- //
- // if we want to update the recipient record
- if(b_UpdateRecipient)
- {
- //
- // find the relevant recipient record
- for each m_Action in m_Request.get("actions")
- {
- if(!isNull(m_Action.get("action_status")) && v_RecipientEmail != "")
- {
- v_ZCRM_RecipientRecordID = 0;
- l_SearchRecipients = zoho.crm.searchRecords("zohosign__ZohoSign_Recipients","(Email:equals:" + v_RecipientEmail + ")and(zohosign__ZohoSign_Document:equals:" + v_ZCRM_DocRecordID + ")");
- for each m_Recipient in l_SearchRecipients
- {
- if(!isNull(m_Recipient.get("id")))
- {
- v_ZCRM_RecipientRecordID = m_Recipient.get("id").toLong();
- }
- }
- if(v_ZCRM_RecipientRecordID == 0 && !m_Action.get("action_status").equalsIgnoreCase("FORWARDED"))
- {
- //
- // create CRM zohosign document recipient record
- m_CreateRecipient = Map();
- m_CreateRecipient.put("Name",m_Action.get("recipient_name"));
- m_CreateRecipient.put("Email",m_Action.get("recipient_email"));
- m_CreateRecipient.put("Owner",v_ZCRM_DocRecordOwnerID);
- m_CreateRecipient.put("zohosign__Recipient_Order",m_Action.get("signing_order"));
- if(v_DocStatusSuffix == "COMPLETED")
- {
- m_CreateRecipient.put("zohosign__Date_Completed",zoho.currentdate);
- }
- else if(v_DocStatusSuffix == "DECLINED")
- {
- m_CreateRecipient.put("zohosign__Date_Declined",zoho.currentdate);
- }
- else
- {
- m_CreateRecipient.put("zohosign__Date_Delivered",zoho.currentdate);
- }
- m_CreateRecipient.put("zohosign__ZohoSign_Document",v_ZCRM_DocRecordID);
- v_RecipientType = "CC";
- if(m_Action.get("action_type").equalsIgnoreCase("APPROVE"))
- {
- v_RecipientType = "Approver";
- }
- else if(m_Action.get("action_type").equalsIgnoreCase("SIGN"))
- {
- v_RecipientType = "Signer";
- }
- m_CreateRecipient.put("zohosign__Recipient_Type",v_RecipientType);
- v_RecipientStatus = if(v_DocStatusSuffix == "SIGNED" || v_DocStatusSuffix == "APPROVED" || v_DocStatusSuffix == "FORWARDED" || v_DocStatusSuffix == "VIEWED","Delivered",v_DocStatusSuffix.proper());
- m_CreateRecipient.put("zohosign__Recipient_Status",v_RecipientStatus);
- if(v_ZS_DocID != 0)
- {
- m_CreateRecipient.put("zohosign__ZohoSign_Document_ID",v_ZS_DocID.toString());
- }
- //
- // create the recipient record
- r_CreateRecipient = zoho.crm.createRecord("zohosign__ZohoSign_Recipients",m_CreateRecipient);
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "ZCRM Recipient Record - CREATE: <br />" + m_Action.get("recipient_name") + "<br />" + r_CreateRecipient + "<hr />";
- }
- }
- else if(v_ZCRM_RecipientRecordID != 0 && m_Action.get("recipient_email").equalsIgnoreCase(m_Notification.get("performed_by_email")))
- {
- //
- // update CRM zohosign document recipient record
- m_UpdateRecipient = Map();
- m_UpdateRecipient.put("zohosign__Recipient_Order",m_Action.get("signing_order"));
- v_RecipientType = "CC";
- if(m_Action.get("action_type").equalsIgnoreCase("APPROVE"))
- {
- v_RecipientType = "Approver";
- }
- else if(m_Action.get("action_type").equalsIgnoreCase("SIGN"))
- {
- v_RecipientType = "Signer";
- }
- m_UpdateRecipient.put("zohosign__Recipient_Type",v_RecipientType);
- v_RecipientStatus = if(v_DocStatusSuffix == "SIGNED" || v_DocStatusSuffix == "APPROVED" || v_DocStatusSuffix == "FORWARDED" || v_DocStatusSuffix == "VIEWED","Delivered",v_DocStatusSuffix.proper());
- m_UpdateRecipient.put("zohosign__Recipient_Status",v_RecipientStatus);
- if(v_DocStatusSuffix == "COMPLETED")
- {
- m_UpdateRecipient.put("zohosign__Date_Completed",zoho.currentdate);
- }
- else if(v_DocStatusSuffix == "DECLINED")
- {
- m_UpdateRecipient.put("zohosign__Date_Declined",zoho.currentdate);
- }
- else
- {
- m_UpdateRecipient.put("zohosign__Date_Delivered",zoho.currentdate);
- }
- if(v_ZS_DocID != 0)
- {
- m_UpdateRecipient.put("zohosign__ZohoSign_Document_ID",v_ZS_DocID.toString());
- }
- r_UpdateRecipient = zoho.crm.updateRecord("zohosign__ZohoSign_Recipients",v_ZCRM_RecipientRecordID,m_UpdateRecipient);
- if(b_DebugMode)
- {
- v_DebugMessage = v_DebugMessage + "ZCRM Recipient Record - UPDATE: <br /><br />" + r_UpdateRecipient + "<hr />";
- }
- }
- }
- }
- }
- }
- }
- }
- //
- // now attach to CRM Record if completed
- if(v_ZCRM_DocRecordID != 0 && v_DocStatusSuffix == "COMPLETED")
- {
- r_ZCRM_DocumentDetails = zoho.crm.getRecordById("zohosign__ZohoSign_Documents",v_ZCRM_DocRecordID);
- if(!isNull(r_ZCRM_DocumentDetails.get("zohosign__Module_Record_ID")))
- {
- //
- // get module and record ID
- v_ModuleName = ifnull(r_ZCRM_DocumentDetails.get("zohosign__Module_Name"),"-");
- v_ModuleRecordID = r_ZCRM_DocumentDetails.get("zohosign__Module_Record_ID");
- v_ZS_DocumentName = ifnull(r_ZCRM_DocumentDetails.get("Name"),v_ModuleName);
- //
- // download file
- r_ZS_Download = zoho.sign.downloadDocument(v_ZS_RequestID);
- v_Filename = v_ZS_DocumentName;
- if(!isNull(v_ZS_RequestName))
- {
- v_Filename = v_ZS_RequestName;
- }
- if(v_Filename.lastIndexOf(".") > 0)
- {
- v_Filename = v_Filename.subString(0,v_Filename.lastIndexOf("."));
- }
- r_ZS_Download.setFileName(v_Filename + "_SIGNED.pdf");
- //
- // attach file to record of module
- r_AttachFile = zoho.crm.attachFile(v_ModuleName,v_ModuleRecordID,r_ZS_Download);
- //
- // for debug purposes but completely unnecessary for the function of this function
- if(!isNull(r_AttachFile.get("message")))
- {
- v_DebugMessage = v_DebugMessage + "CRM Attachment: <br /><br />" + r_AttachFile.get("message") + "<hr />";
- }
- }
- }
- }
- }
- v_DebugMessage = v_DebugMessage + "Date/Time: <br /><br />" + zoho.currenttime;
- //
- if(b_DebugMode)
- {
- sendmail
- [
- from :zoho.adminuserid
- to :"me+This email address is being protected from spambots. You need JavaScript enabled to view it."
- subject :"My ZohoSign Webhook - ANY EVENT"
- message :v_DebugMessage
- ]
- }
- return "";
Related List for Custom Module
Just for good measure (and because it took me an hour to write this), here's the code to generate a related list on a custom module to the related ZohoSign Documents in ZohoCRM:
/* ******************************************************************************* Function: String fn_Maintenance_ZohoSignRelatedList(Int p_ThisRecordID) Label: Fn - Maintenance - Related List - Zoho Sign Documents Trigger: On load of a maintenance record Purpose: Function used to generate a related list of ZohoSign Documents Inputs: Record ID Outputs: XML related list Date Created: 2024-08-29 (Joel Lipman) - Initial release Date Modified: ??? - ??? ******************************************************************************* */ // // initialize v_Index = 0; v_RelatedListXML = ""; v_ModuleName = "Maintenance"; v_CrmOrgID = "org123456789"; v_ZohoSignDocModuleName = "CustomModule12"; v_DateFormat = "dd MMM, yyyy"; v_TimeFormat = v_DateFormat + " HH:mm:ss"; // // search in CRM for ZohoSign Documents l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","(zohosign__Module_Name:equals:" + v_ModuleName + ")and(zohosign__Module_Record_ID:equals:" + p_ThisRecordID + ")"); // // if found records if(l_SearchResults.size() > 0 && l_SearchResults.toString().contains("zohosign__ZohoSign_Document_ID")) { v_RelatedListXML = "<record>"; for each m_Result in l_SearchResults { // init v_Index = v_Index + 1; v_RelatedListXML = v_RelatedListXML + "<row no=\"" + v_Index + "\">"; // // retrieve/transform values from record v_ZohoSignDoc_ID = m_Result.get("id"); v_ZohoSignDoc_Name = m_Result.get("Name"); v_LinkName1 = "https://crm.zoho.com/crm/" + v_CrmOrgID + "/tab/" + v_ZohoSignDocModuleName + "/" + v_ZohoSignDoc_ID; if(!isNull(m_Result.get("zohosign__Contact"))) { v_ZohoSignDoc_ContactID = m_Result.get("zohosign__Contact").get("id"); v_ZohoSignDoc_ContactName = m_Result.get("zohosign__Contact").get("name"); v_LinkName2 = "https://crm.zoho.com/crm/" + v_CrmOrgID + "/tab/Contacts/" + v_ZohoSignDoc_ContactID; } else { v_ZohoSignDoc_ContactName = m_Result.get("Email"); v_LinkName2 = "mailto:" + m_Result.get("Email"); } v_ZohoSignDoc_Status = ifnull(m_Result.get("zohosign__Document_Status"),"-"); v_ZohoSignDoc_DateSent = if(!isNull(m_Result.get("zohosign__Date_Sent")),m_Result.get("zohosign__Date_Sent").toString(v_DateFormat),"-"); v_ZohoSignDoc_DateCompleted = if(!isNull(m_Result.get("zohosign__Date_Completed")),m_Result.get("zohosign__Date_Completed").toString(v_DateFormat),"-"); v_ZohoSignDoc_DateDeclined = if(!isNull(m_Result.get("zohosign__Date_Declined")),m_Result.get("zohosign__Date_Declined").toString(v_DateFormat),"-"); v_ZohoSignDoc_LastActivityTime = if(!isNull(m_Result.get("Last_Activity_Time")),m_Result.get("Last_Activity_Time").replaceAll("T"," ").getPrefix("+").toString(v_TimeFormat),"-"); // // generate XML related list response // don't forget to escape quote name with CDATA in case of XML banned characters v_RelatedListXML = v_RelatedListXML + "<FL val=\"Document Name\" link=\"true\" url=\"" + v_LinkName1 + "\"><![CDATA[" + v_ZohoSignDoc_Name + "]]></FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Contact\" link=\"true\" url=\"" + v_LinkName2 + "\"><![CDATA[" + v_ZohoSignDoc_ContactName + "]]></FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Document Status\">" + v_ZohoSignDoc_Status + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Sent\">" + v_ZohoSignDoc_DateSent + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Completed\">" + v_ZohoSignDoc_DateCompleted + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Declined\">" + v_ZohoSignDoc_DateDeclined + "</FL>"; v_RelatedListXML = v_RelatedListXML + "<FL val=\"Last Activity Time\">" + v_ZohoSignDoc_LastActivityTime + "</FL>"; v_RelatedListXML = v_RelatedListXML + "</row>"; } 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;
- /* *******************************************************************************
- Function: string fn_Maintenance_ZohoSignRelatedList(Int p_ThisRecordID)
- Label: Fn - Maintenance - Related List - Zoho Sign Documents
- Trigger: On load of a maintenance record
- Purpose: Function used to generate a related list of ZohoSign Documents
- Inputs: Record ID
- Outputs: XML related list
- Date Created: 2024-08-29 (Joel Lipman)
- - Initial release
- Date Modified: ???
- - ???
- ******************************************************************************* */
- //
- // initialize
- v_Index = 0;
- v_RelatedListXML = "";
- v_ModuleName = "Maintenance";
- v_CrmOrgID = "org123456789";
- v_ZohoSignDocModuleName = "CustomModule12";
- v_DateFormat = "dd MMM, yyyy";
- v_TimeFormat = v_DateFormat + " HH:mm:ss";
- //
- // search in CRM for ZohoSign Documents
- l_SearchResults = zoho.crm.searchRecords("zohosign__ZohoSign_Documents","(zohosign__Module_Name:equals:" + v_ModuleName + ")and(zohosign__Module_Record_ID:equals:" + p_ThisRecordID + ")");
- //
- // if found records
- if(l_SearchResults.size() > 0 && l_SearchResults.toString().contains("zohosign__ZohoSign_Document_ID"))
- {
- v_RelatedListXML = "<record>";
- for each m_Result in l_SearchResults
- {
- // init
- v_Index = v_Index + 1;
- v_RelatedListXML = v_RelatedListXML + "<row no=\"" + v_Index + "\">";
- //
- // retrieve/transform values from record
- v_ZohoSignDoc_ID = m_Result.get("id");
- v_ZohoSignDoc_Name = m_Result.get("Name");
- v_LinkName1 = "https://crm.zoho.com/crm/" + v_CrmOrgID + "/tab/" + v_ZohoSignDocModuleName + "/" + v_ZohoSignDoc_ID;
- if(!isNull(m_Result.get("zohosign__Contact")))
- {
- v_ZohoSignDoc_ContactID = m_Result.get("zohosign__Contact").get("id");
- v_ZohoSignDoc_ContactName = m_Result.get("zohosign__Contact").get("name");
- v_LinkName2 = "https://crm.zoho.com/crm/" + v_CrmOrgID + "/tab/Contacts/" + v_ZohoSignDoc_ContactID;
- }
- else
- {
- v_ZohoSignDoc_ContactName = m_Result.get("Email");
- v_LinkName2 = "mailto:" + m_Result.get("Email");
- }
- v_ZohoSignDoc_Status = ifnull(m_Result.get("zohosign__Document_Status"),"-");
- v_ZohoSignDoc_DateSent = if(!isNull(m_Result.get("zohosign__Date_Sent")),m_Result.get("zohosign__Date_Sent").toString(v_DateFormat),"-");
- v_ZohoSignDoc_DateCompleted = if(!isNull(m_Result.get("zohosign__Date_Completed")),m_Result.get("zohosign__Date_Completed").toString(v_DateFormat),"-");
- v_ZohoSignDoc_DateDeclined = if(!isNull(m_Result.get("zohosign__Date_Declined")),m_Result.get("zohosign__Date_Declined").toString(v_DateFormat),"-");
- v_ZohoSignDoc_LastActivityTime = if(!isNull(m_Result.get("Last_Activity_Time")),m_Result.get("Last_Activity_Time").replaceAll("T"," ").getPrefix("+").toString(v_TimeFormat),"-");
- //
- // generate XML related list response
- // don't forget to escape quote name with CDATA in case of XML banned characters
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Document Name\" link=\"true\" url=\"" + v_LinkName1 + "\"><![CDATA[" + v_ZohoSignDoc_Name + "]]></FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Contact\" link=\"true\" url=\"" + v_LinkName2 + "\"><![CDATA[" + v_ZohoSignDoc_ContactName + "]]></FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Document Status\">" + v_ZohoSignDoc_Status + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Sent\">" + v_ZohoSignDoc_DateSent + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Completed\">" + v_ZohoSignDoc_DateCompleted + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Date Declined\">" + v_ZohoSignDoc_DateDeclined + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "<FL val=\"Last Activity Time\">" + v_ZohoSignDoc_LastActivityTime + "</FL>";
- v_RelatedListXML = v_RelatedListXML + "</row>";
- }
- 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;