Kaizen #131 - Bulk Write for parent-child records using Scala SDK

Kaizen #131 - Bulk Write for parent-child records using Scala SDK

Hello and welcome back to this week's Kaizen!
Last week, we discussed how to configure and initialize the Zoho CRM Scala SDK. This week, we will be exploring the Bulk Write API and its capabilities. Specifically, we will focus on executing bulk write operations for parent-child records in a single operation, and how to do this using Scala SDK.

Quick Recap of Bulk Write API

Bulk Write API facilitates efficient insertion, updation, or upsertion of large datasets into your CRM account. It operates asynchronously, scheduling jobs to handle data operations. Upon completion, notifications are sent to the specified callback URL or the job status can be checked periodically.

When to use Bulk Write API?

  • When scheduling a job to import a massive volume of data.
  • When needing to process more than 100 records in a single API call.
  • When conducting background processes like migration or initial data sync between Zoho CRM and external services.

Steps to Use Bulk Write API:

  1. Prepare CSV File: Create a CSV file with field API names as the first row and data in subsequent rows.
  2. Upload Zip File: Compress the CSV file into a zip format and upload it via a POST request.
  3. Create Bulk Write Job: Use the uploaded file ID, callback URL, and field API names to create a bulk write job for insertion, update, or upsert operations.
  4. Check Job Status: Monitor job status through polling or callback methods. Status could be ADDED, INPROGRESS, or COMPLETED.
  5. Download Result: Retrieve the result of the bulk write job, typically a CSV file with job details, using the provided download URL.
In our previous Kaizen posts - Bulk Write API Part I and Part II, we have extensively covered the Bulk Write API, complete with examples and sample codes for the PHP SDK. We highly recommend referring to those posts before reading further to gain a better understanding of the Bulk Write API.
With the release of our V6 APIs, we have introduced a significant enhancement to our Bulk Write API functionality. Previously, performing bulk write operations required separate API calls for parent and each child module. But with this enhancement, you can now import them all in a single, operation or API call.

Field Mappings for parent-child records in a single API call

When configuring field mappings for bulk write operations involving parent-child records in a single API call, there are two key aspects to consider: creating the CSV file containing the data and constructing the input JSON for the bulk write job. 

Creating the data CSV file:

To set up the data for a bulk write operation involving parent-child records, you need to prepare separate CSV files - one for the parent module records, and one each for each child module records. In these CSV files, appropriate field mappings for both parent and child records need to be defined. 

The parent CSV file will contain the parent records, while the child CSV file will contain the child records. To make sure that each child record is linked to its respective parent record, we will add an extra column (MappingID in the image below) to both the parent and child CSV files. This column will have a unique identifier value for each parent record. For each record in the child CSV file, the value in the identifier column should match the value of the identifier of the parent record in the parent CSV file. This ensures an accurate relationship between the parent and child records during the bulk write operation.

Please be aware that the mapping of values is solely dependent on the mappings defined in the input JSON. In this case, the column names in the CSV file serve only as a reference for you. Please refer to the notes section towards the end of this document for more details.


Creating the CSV file remains consistent across all types of child records, and we have already discussed how each child record is linked to its respective parent record in the CSV file. To facilitate the same linkage in the input JSON, we have introduced a new key called parent_column_index. This key assists us in specifying which column in the child module's CSV file contains the identifier or index linking it to the parent record. In the upcoming sections, we will explore preparing the input JSON for various types of child records.

Additionally, since we have multiple CSV files in the zip file, we have introduced another new key named file_names in resources array. file_names helps in correctly mapping each CSV file to its corresponding module.

Ensure that when adding parent and child records in a single operation, the parent module details should be listed first, followed by the child module details in the resource array of the input body.

1. Multiselect Lookup Fields

In scenarios involving multiselect lookup fields, the Bulk Write API now allows for the import of both parent and child records in a single operation.
In the context of multiselect lookup fields, the parent module refers to the primary module where the multiselect lookup field is added. For instance, in our example, consider a multiselect lookup field in the Leads module linking to the Products module.

Parent Module : Leads 
Child module : The linking module that establishes the relationship between the parent module and the related records (LeadsXProducts)

Here are the sample files for the "LeadsXProducts" case:

Leads.csv (Parent)

LeadsXProducts.csv (Child)

Given below is a sample input JSON for this bulk write job. Please note that the index of the child linking column should be mapped under the key index, and the index of the parent column index should be mapped under parent_column_index

To map the child records to their corresponding parent records (linking module), you must use the field API name of the lookup field that links to the parent module. For example, in this case, the API name of the lookup field linking to the Leads module from the LeadsXProducts is Leads.

{
"operation": "insert",
"ignore_empty": true,
"callback": {
"method": "post"
},
"resource": [
{
"type": "data",
"module": { 
"api_name": "Leads" //parent module API name
},
"file_id": "4876876000006855001",
"file_names": [
"Leads.csv" //parent records CSV file
],
"field_mappings": [ // field mappings for the parent record fields
{
"api_name": "Company", //field API name
"index": 0 //index in the CSV file
},
{
"api_name": "First_Name",
"index": 1
},
{
"api_name": "Last_Name",
"index": 2
},
{
"api_name": "Email",
"index": 3
},
{
"api_name": "Phone",
"index": 4
}
]
},
{
"type": "data",
"module": { 
"api_name": "LeadsXProducts" //child module API name
},
"file_id": "4876876000006855001",
"file_names": [
"LeadsXProducts.csv" //child records CSV file
],
"field_mappings": [
{
"api_name": "Products",
"find_by": "id",
"index": 0
},
{
"api_name": "Leads", //field API name of the lookup field in the Linking Module
"parent_column_index": 5, // the index of the identifier column in the parent CSV file
"index": 1 //index of the identifier column in the child CSV file
}
]
}
]
}

The following is a sample code snippet for the Scala SDK, to achieve the same functionality. Find the complete code here.

var module = new MinifiedModule() // Create a new instance of MinifiedModule
module.setAPIName(Option("Leads")) // Set the API name for the module to "Leads"
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006899001")) // Set the file ID for the resource instance 
resourceIns.setIgnoreEmpty(Option(true))
var filenames = new ArrayBuffer[String] // Create a new ArrayBuffer to store file names
filenames.addOne("Leads.csv")
resourceIns.setFileNames(filenames) // Set the file names for the resource instance
// Create a new ArrayBuffer to store field mappings
var fieldMappings: ArrayBuffer[FieldMapping] = new ArrayBuffer[FieldMapping]
// Create a new FieldMapping instance for each field
var fieldMapping: FieldMapping = null
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Company"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
.
.
// Set the field mappings for the resource instance
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)
resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("LeadsXProducts"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006899001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("LeadsXProducts.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Products"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Leads")) //Specify the API name of the lookup filed in the Linking Module
fieldMapping.setParentColumnIndex(Option(5)) //Specify the index of the identifier column in the parent CSV file
fieldMapping.setIndex(Option(1)) //Specify the index of the identifier column in the child CSV file
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

2. Multi-User Lookup fields

In case of multi-user lookup fields, the parent module remains the module where the multi-user field is added. The child module is the lookup module created to facilitate this relationship.
For instance, let's consider a scenario where a multi-user field labeled Referred By is added in the Leads module, linking to the Users module.

Parent module : Leads 
Child module : The linking module, LeadsXUsers.

To get more information about the child module, please utilize the Get Modules API. You can get the details of the fields within the child module using the Fields API
Here is a sample CSV for adding a multi-user field records along with the parent records:

LeadsXUsers.csv

Please ensure that you create a zip file containing the corresponding CSV files, upload it to the platform and then initiate the bulk write job using the file ID. The values for index and parent_column_index will vary based on your specific CSV files.

To create a bulk write job using Create Bulk Write job API, add the following code snippet to your resource array.
{
"type": "data",
"module": { 
"api_name": "Leads_X_Users" // child module
},
"file_id": "4876876000006887001",
"file_names": [
"LeadsXUsers.csv" //child records CSV file name
],
"field_mappings": [
{
"api_name": "Referred_User",
"find_by": "id",
"index": 0
},
{
"api_name": "userlookup221_11", //API name of the Leads lookup field in LeadsXUsers module
"parent_column_index": 5, // the index of the identifier column in the parent CSV file
"index": 1 // the index of the identifier column in the child CSV file
}
]
}

To do the same using Scala SDK, add the following code snippet to your code:

resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Leads_X_Users"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006904001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("LeadsXUsers.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Referred_User"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("userlookup221_11"))
fieldMapping.setParentColumnIndex(Option(5))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

3. Subform data

To import subform data along with parent records in a single operation, you must include both the parent and subform CSV files within a zip file and upload it. In this context, the parent module refers to the module where the subform is added, and the child module is the subform module.

For instance, consider a subform named Alternate Address in the Leads module, with fields such as City and State

Parent module : Leads
Child module : Alternate_Address (api name of the Subform module). 

In the subform CSV file (Alternate_Address.csv), in addition to the data columns, include a column to denote the linkage to the parent record.
Once the zip file containing both the parent and subform CSV files is prepared, proceed to upload it to initiate the import process. When you create the bulk write job, ensure to specify the appropriate values for index and parent_column_index based on your specific CSV files in the input.

Here is a sample CSV for the subform data, corresponding to the parent CSV provided earlier.

Alternate_Address.csv

To create a bulk write job using Create Bulk Write job API to import the subform data, add the following code snippet to your resource array.

{
"type": "data",
"module": { 
"api_name": "Alternate_Address" //Subform module API name
},  
"file_id": "4876876000006915001",
"file_names": [
"Alternate_Address.csv" //child (subform) records CSV
],
"field_mappings": [
{
"api_name": "State",
"index": 0
},
{
"api_name": "City",
"index": 1
},
{
"api_name": "Parent_Id", //Leads lookup field in the subform module
"parent_column_index": 5,
"index": 2
}
]
}

To do the same using Scala SDK, add the following code snippet to your code:

resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Alternate_Address"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006920001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("Alternate_Address.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("State"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("City"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Parent_Id"))
fieldMapping.setParentColumnIndex(Option(5))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

4. Line Items

To import line items along with the parent records, an approach similar to handling subform data is used. The parent module is the module housing the parent records, while the child module corresponds to the line item field.

For instance, in the Quotes module, to import product details within the record, the child module should be Quoted_Items. 

Here is a sample CSV for importing the parent records to the Quotes module:

Quotes.csv

Given below is a sample CSV to add the product details in Quoted Items:

Quoted_Items.csv

Now to create a bulk write job for these records, here is a sample input JSON:

{
"operation": "insert",
"ignore_empty": true,
"callback": {
"method": "post"
},
"resource": [
{
"type": "data",
"module": { 
"api_name": "Quotes"
},
"file_id": "4876876000006949001",
"file_names": [
"Quotes.csv"
],
"field_mappings": [
{
"api_name": "Subject",
"index": 0
},
{
"api_name": "Deal_Name",
"find_by" : "id",
"index": 1
},
{
"api_name": "Quote_Stage",
"index": 2
},
{
"api_name": "Account_Name",
"find_by" : "id",
"index": 3
}
]
},
{
"type": "data",
"module": { 
"api_name": "Quoted_Items"
},
"file_id": "4876876000006949001",
"file_names": [
"Quoted_Items.csv"
],
"field_mappings": [
{
"api_name": "Product_Name",
"find_by" : "id",
"index": 0
},
{
"api_name": "Quantity",
"index": 1
},
{
"api_name": "Parent_Id",
"parent_column_index": 4,
"index": 2
}
]
}
]
}

To do the same using Scala SDK, add this code snippet to your file:

val bulkWriteOperations = new BulkWriteOperations
val requestWrapper = new RequestWrapper
val callback = new CallBack
callback.setUrl(Option("https://www.example.com/callback"))
callback.setMethod(new Choice[String]("post"))
requestWrapper.setCallback(Option(callback))
requestWrapper.setCharacterEncoding(Option("UTF-8"))
requestWrapper.setOperation(new Choice[String]("insert"))
requestWrapper.setIgnoreEmpty(Option(true))
val resource = new ArrayBuffer[Resource]
var resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
var module = new MinifiedModule()
module.setAPIName(Option("Quotes"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006953001"))
resourceIns.setIgnoreEmpty(Option(true))
var filenames = new ArrayBuffer[String]
filenames.addOne("Quotes.csv")
resourceIns.setFileNames(filenames)
var fieldMappings: ArrayBuffer[FieldMapping] = new ArrayBuffer[FieldMapping]
var fieldMapping: FieldMapping = null
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Subject"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Deal_Name"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Quote_Stage"))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Account_Name"))
fieldMapping.setIndex(Option(3))
fieldMapping.setFindBy(Option("id"))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)
resourceIns = new Resource
resourceIns.setType(new Choice[String]("data"))
module = new MinifiedModule()
module.setAPIName(Option("Quoted_Items"))
resourceIns.setModule(Option(module))
resourceIns.setFileId(Option("4876876000006953001"))
resourceIns.setIgnoreEmpty(Option(true))
filenames = new ArrayBuffer[String]
filenames.addOne("Quoted_Items.csv")
resourceIns.setFileNames(filenames)
fieldMappings = new ArrayBuffer[FieldMapping]
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Product_Name"))
fieldMapping.setFindBy(Option("id"))
fieldMapping.setIndex(Option(0))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Quantity"))
fieldMapping.setIndex(Option(1))
fieldMappings.addOne(fieldMapping)
fieldMapping = new FieldMapping
fieldMapping.setAPIName(Option("Parent_Id"))
fieldMapping.setParentColumnIndex(Option(4))
fieldMapping.setIndex(Option(2))
fieldMappings.addOne(fieldMapping)
resourceIns.setFieldMappings(fieldMappings)
resource.addOne(resourceIns)
requestWrapper.setResource(resource)

Notes : 

  • When importing a single CSV file (parent or child module records separately), field_mappings is an optional key in the resource array. If you skip this key, the field mappings must be defined using the column names in the CSV file. In such cases, the column names should correspond to the field API names. Additionally, all columns should be mapped with the correct API names, and there should not be any extra unmapped columns.
  • When importing parent and child records in a single API call, field_mappings is a mandatory key.
  • The identifier column in the parent and child CSV can have different column names, as the mapping is done based on the input JSON.

Points to remember

  • An uploaded file can be used for a single bulk write job only. If you want to retry the operation with the same data, upload the file again to generate a new file ID.
  • When adding parent and child records in a single operation, ensure that the parent module comes first, followed by the child module details in the resource array of the input body.
  • The parent and all child CSV files should be zipped into a single file and uploaded. You cannot use more than one zip file in a single bulk write job. 
  • Define appropriate mappings for both parent and child records using the parent_column_index and index key to establish the relationship.
  • Utilize the resources > file_names key to map the correct CSV with the appropriate module
  • For each parent in the parent records file:
    • By default, the limit for Subforms and Line Items is set to 200. While you can configure this limit for subforms in the UI, customization options are not available for Line Items.
    • MultiSelect Lookup fields have a maximum limit of 100. If you have more than 100 associations for a MultiSelect Lookup field, you may schedule additional bulk write jobs for the child records alone, importing 100 records at a time.
    • The maximum limit for Multi-User Lookup fields is restricted to 10
We hope that you found this post useful, and you have gained some insights into using the Bulk Write API effectively. If you have any queries, let us know in the comments below, or feel free to send an email to support@zohocrm.com. We would love to hear from you!

Recommended Reads :


    • Recent Topics

    • can't login Kiosk URGENT

      already try, can't login pls help to support. thanks.
    • 【Zoho CRM】CRM for Everyoneに関するアップデート:関連データ機能

      ユーザーの皆さま、こんにちは。コミュニティチームの中野です。 今回は「Zoho CRM アップデート情報」の中から、CRM for Everyoneの新機能「関連データ機能」をご紹介します。 関連データ機能は、あるタブのデータを別のタブに柔軟に関連付け、異なるタブで管理されている情報を1か所にまとめて表示できます。 たとえば、組織タブとチームタブのデータを関連付けることで、必要な情報に効率よくアクセスでき、顧客理解を深めながら他チームとの連携もスムーズに行えます。 目次 1. 関連データの設定方法
    • Profit / margins on Sales orders / Invoices / Estimates

      When we select an SKU or item name in any of these documents, much info such as invoice.line_items.rate is pulled from the item & filled into the document being worked on. If we had another lineItem DB field (hidden) auto filled at the same time: invoice.line_items.purchase_rate
    • Inventory to Xero Invocie Sync Issues

      Has anyone had an issue with Invoices not syncing to Xero. It seems to be an issue when there is VAT on a shipping cost, but I cannot be 100% as the error is vague: "Unable to export Invoice 'INV-000053' as the account mapped with some items does not
    • How to activate RFQ? What if a price list has ladder price for items?

      Where can I find the option to activate request for quotation? How does it work? If the item has ladder price, does it gets calculated depending on how many items are in the cart?
    • Can't join canal Developers Zoho User

      Hello, I received an invitation to join this channel, but I get an error when I try to join it, and I get the same error when I go to the Zoho Cliq interface > Search for a channel. Is this because I don't have a license linked to this email address?
    • Desk Email reply - set default font / use custom font

      Hello, in our e-mails, which we send to our customers, a certain font must be used (Corporate Design): Segoe UI https://en.wikipedia.org/wiki/Segoe#Segoe_UI How can this be included? How can this be set as the default font to ensure that this font is
    • PDF Templates - Checkbox Borders

      Is there a way to remove the border of a radio/checkbox on a PDF? I'd like to use the function of checkbox but if there's no easy way to remove the border (the PDF form already has a rectangle so it gets cluttered), then I'm forced to create a single
    • Settings Icon No Longer in ZOHO Desk?

      In ZOHO desk, there has been a gear icon for settings. as of yesterday, it is no longer there. I showed up briefly this morning but is gone again. Anybody else experiecing this?
    • Introducing the all-new email parser!

      Greetings, We are pleased to introduce to you, a brand-new, upgraded version of the Zoho CRM Email Parser, which is packed with fresh features and has been completely redesigned to meet latest customers needs and their business requirements. On that note,
    • Tip #43 - Track, Review, and Analyze Your Assist Sessions with Reports-'Insider Insights'

      Did you know you can generate detailed reports for both remote support sessions and unattended access sessions in Zoho Assist? This makes it easy to monitor technician activity, measure efficiency, and review customer interactions. Let us now take a closer
    • Function #20: Custom calculation in item table of invoices

      When you create an invoice in Zoho Books, the 'Amount' of a line item is typically calculated as the product of the "Quantity" and the "Rate" of the item. For instance, if an item has a sales rate of $50 and a quantity of 5 is sold, then the amount would
    • Simplified Call Logging

      Our organization would like to start logging calls in our CRM; however, with 13 fields that can't be removed, our team is finding it extremely cumbersome. For our use case, we only need to record that a call happened theirfor would only need the following
    • Sub form doesn't as formula field

      Is it possible to get formula field in sub form in futures?
    • Week date range in pivot table

      Hello, I need to create a report that breakouts the data by week.  I am using the pivot table report, and breaking out the date by week, however the date is displayed as 'Week 1 2014' format.  Is there anyway to get the actual dates in there? ex. 1/6/2014-1/12/2014 Thanks,
    • How do I get Status History data of my Projects?

      I want to build a table in Zoho Analytics that Groups by Date, when Projects entered a certain status. I cannot find Status History or any such useful data available in the Setup of my Data Source sync. Please advise how I can achieve this?
    • Is it possible to hide fields in a Subform?

      Since layout rules cannot be used with Subforms, is there another way, or is it even possible, to hide fields in a subform based on a picklist fields within said subform? For example, if the Service Provided is Internet, then I do not want to see the
    • Weekly Tips :Instantly find what you need with Attachment Viewer

      Your inbox must be packed with project emails, shared notes, and scattered attachments. You are looking for one specific file—a presentation slide or maybe a media clip from a team update—but don’t want to dig through endless email threads or switch between
    • Missing Zoho Desk integration option for form workflows

      According to the help page "Configure Zoho Desk integration in form workflows" we should be able to select Zoho Desk as an integration target but when I open the integrations list then Zoho Desk is not being listed in it. We are on the Premium plan which should already support Zoho Desk integrations.
    • Gantt for 2 or more projects

      Hello, I'm trying the free version of your produtc. It is veryyy good!!!! I don't know if in the Standard plan, I can overview a Gantt Graph for 2 or more Projects Milestone. This would be very helpfull for managing teams and taking decisions about who I will assign a task to. In the paid plan Do I have this possibility? Thank you.
    • Integrating a Zoho Project Gantt Chart into Reports

      Is is possible to integrate a Zoho Project Gantt Chart into a Zoho Report Dashboard. I am in the process of creating Project Status Dashboards for the projects that we track in Zoho Projects and I would like to incorporate the gantt chart within Reports.  Please let me know! Thanks
    • ZOHO BOOKS - EXCESSIVELY SLOW TODAY

      Dear Zoho Books This is not the first time but it seems to be 3 times per week now that the system is extremely slow. I work on Zoho Books 95% of my day so this is very frustrating. Zoho you need to do something about this. I have had my IT guy check
    • Gantt Chart - Zoho Analytics

      Are there any plans to add Gantt Charts capabilities to Zoho Analytics?
    • Displaying related quotes in sales order and back

      Hi, My colleague liked to see to which sales orders, the quote has been converted. Quote shows Invoices, but not SO. Same, they would like to see the quotes in the sales order, as they can see invoices, packages, shipment, How can we achieve this ? Thank
    • Tip of the Week #71–Auto-move incoming messages to the right inboxes with keywords

      We all know that customer-facing teams, especially your sales and support teams, can’t afford to miss even a single customer conversation. But sometimes, sales queries or support requests can easily get lost in a crowded inbox or even end up in the wrong
    • Clearing Fields using MACROS?

      How would I go about clearing a follow-up field date from my deals? Currently I cannot set the new value as an empty box.
    • Migrating a Zoho Forms form into Zoho Creator

      Hi, How can I migrate my Zoho Forms form into Zoho Creator? Thanks. Truly, Emad
    • Is there any way to recall an email sent using Zoho CRM?

      If an email is sent using Zoho Mail, there is a recall option/functionality that is available to the sender. Is there any way to recall an email if it was sent using Zoho CRM? I can't seem to find that option. Any help would be appreciated.
    • Problem with reports due to "Connected" items change - Yes this IS a problem

      Now that the change has been made to use "connected" items I can no longer run the reporting I need in CRM. I should be able to start with Deals as the parent, connect down to the Account (Account_Name) on the deal as the child, then to any child items
    • Introducing notifications in the vendor portal

      Imagine this: You're a recruiter working with multiple vendors on a high-volume hiring project. You’ve just updated a job description after a last-minute change from the hiring manager. One of your vendors, however, is still working off the older version
    • CRM limit reached: only 2 subforms can be created

      we recently stumbled upon a limit of 2 subforms per module. while we found a workaround on this occasion, only 2 subforms can be quite limiting in an enterprise setting. @Ishwarya SG I've read about imminent increase of other components (e.
    • LESS_THAN_MIN_OCCURANCE - code 2945

      Hi I'm trying to post a customer record to creator API and getting this error message. So cryptic. Can someone please help? Thanks Varun
    • Analytics for notes created

      Is there a way I can see how many notes were created per day? Via reporting or analytics?
    • Cannot update Recurring_Activity on Tasks – RRULE not accepted

      Hello, I am trying to update Tasks in Zoho CRM to make them recurring yearly, but I cannot find the correct recurrence pattern or way to update the Recurring_Activity field via API or Deluge. I have tried: Sending a string like "RRULE:FREQ=YEARLY;INTERVAL=1"
    • Add image to report...

      Greetings, I send a weekly color coded report via Creator email. I would like to add the legend somewhere in the report. Header, footer where ever. I have the legend saved on Google Drive and can access it via shared link. Sure someone has wanted to add
    • More controls for User Fields in CRM

      Dear All, We are here with a minor but crucial enhancement to the user fields—now set accessibility permissions to the records for user field. User field allows you to extend co-ownership of records to your peers. You can collaborate with them for certain
    • Calls to accounts rather than leads or contacts?

      So..... We have a dilemma and I'm hoping someone has encountered this before and figured out a fix. We have just migrated to Zoho. It's great.....expect for how "Calls" are handled.... We are B2B. We do not use the leads module. A "Lead/Prospect" for
    • Image Upload Field | Zoho Canvas

      I'm working on making a custom view for one of our team's modules. It's an image upload field (Placement Photo) that would allow our sales reps to upload a picture of the house their working on. However, I don't see that field as a opinion when building
    • Power of Automation :: Automated 'Delayed & Closed' Status Update Based on Due Date

      Hello Everyone, A custom function is a software code that can be used to automate a process and this allows you to automate a notification, call a webhook, or perform logic immediately after a workflow rule is triggered. This feature helps to automate
    • Lead Blueprint transition in custom list view

      Hi, Is It possible to insert the Blueprint transition label in a custom Canvas list view? I am using Lead module. I see the status, but it would be great if our users could execute the Blueprint right from the list view without having to enter the detailed
    • Next Page