The script takes a Quote from Zoho CRM, collects the items, extends preview files by fileId, uploads them to WorkDrive using streaming upload, generates rows in Sheet2 of Zoho Sheets (with previews via the formula =IMAGE()), copies the workbook into the target folder WorkDrive under the Quote’s name, attaches the workbook link to the Quote record in CRM, and finally clears the range in the working sheet for the next generation cycle.
Loading Quote data from CRM
Preparing table headers (for future rows in Sheets)
Iterating through Quote Items (Quoted_Items)
For each item, the script extracts:
Product_Name.name, SKU, color, packaging, model/fabric, sizes, print types, quantity, price, total, link, parent ID, and Preview attachments.
Receiving and publishing files preview
Creating a row for Zoho Sheets (Sheet2)
Copying the workbook and renaming it after the Quote
Attaching the workbook link to the Quote in CRM
If DUPLICATE_DATA is received, the script returns a system message; otherwise, it returns Files Generated.
Clearing the working range in Sheet2
Loading Quote data from CRM
- receives a QuoteID and makes GET twice
- https://www.zohoapis.eu/crm/v8/Quotes/{QuoteID}.
- extends key fields:
- Subject, Account_Name, Contact_Name, Owner.name, shipping address, dates, amounts, and the Quoted_Items array.
Preparing table headers (for future rows in Sheets)
- A list row_data and a map header are created with the following columns: “Product Name”, “Description”, “Quantity” and “Price”.
- The header is appended to row_data.
- (Note: the same variable name header is later reused for HTTP headers — a potential source of confusion, see “Remarks” below.)
Iterating through Quote Items (Quoted_Items)
For each item, the script extracts:
Product_Name.name, SKU, color, packaging, model/fabric, sizes, print types, quantity, price, total, link, parent ID, and Preview attachments.
Receiving and publishing files preview
- For each file in Preview, if File_Id__s exists, the following is performed:
- Download file: GET https://www.zohoapis.eu/crm/v8/files?id={fileId}
- Prepare streaming upload to WorkDrive:
- POST https://upload.zoho.eu/workdrive-api/v1/stream/upload headers:
- x-filename: original file name
- x-parent_id: target WorkDrive folder
- upload-id: fileId
- x-streammode: 1.
- From the response, the script retrieves the resource_id of the uploaded file and builds a direct preview link:
- https://previewengine-accl.zoho.eu/image/WD/{resource_id}.
Creating a row for Zoho Sheets (Sheet2)
- A preview formula is built for the cell: =IMAGE("https://previewengine-accl.zoho.eu/image/WD/{resource_id}";1)
- (Note the semicolon; this is the regional setting for the European argument separator.)
- The row is compiled with product details, print attributes, links, project data, and dates, then sent via: zoho.sheet.createRecords(resourceId,"Sheet2", rowsData, ...)
- This process is built for all Quote line items.
Copying the workbook and renaming it after the Quote
- Call POST https://sheet.zoho.eu/api/v2/copy with parameters:
- resource_id: source template workbook
- workbook_name: Quote Subject
- parent_id: target WorkDrive folder
- copy_lock_settings: true
- The workbook_url of the copied workbook is taken from the response.
Attaching the workbook link to the Quote in CRM
- A request is made to POST https://www.zohoapis.eu/crm/v7/Quotes/{QuoteID}/Attachments with attachmentUrl = workbook_url
- title = Subject
If DUPLICATE_DATA is received, the script returns a system message; otherwise, it returns Files Generated.
Clearing the working range in Sheet2
- Finally POST https://sheet.zoho.eu/api/v2/{resourceId}
- with method range.content.clear and range A2:Q50.
- This resets the working area for the next run, ensuring old data doesn’t accumulate.
info QuoteID;
// Get Quote data from Zoho CRM
Quote = invokeurl
[
url :"https://www.zohoapis.eu/crm/v8/Quotes/" + QuoteID
type :GET
connection:"crm_zoho_dev"
];
Quote = Quote.get("data").toMap();
//
// Table
Quote = invokeurl
[
url :"https://www.zohoapis.eu/crm/v8/Quotes/" + QuoteID
type :GET
connection:"crm_zoho_dev"
];
Quote = Quote.get("data").toMap();
Subject = Quote.get("Subject");
Account_Name = Quote.get("Account_Name");
if(Account_Name.isNull() == false)
{
Account_Name = Account_Name.get("name");
}
Contact_Name = Quote.get("Contact_Name");
if(Contact_Name.isNull() == false)
{
Contact_Name = Contact_Name.get("name");
}
Owner = Quote.get("Owner").get("name");
Delivery_address = Quote.get("Delivery_address");
Ready_by_date = Quote.get("Ready_by_date");
Sub_Total = Quote.get("Sub_Total");
Valid_Till = Quote.get("Valid_Till");
Grand_Total = Quote.get("Grand_Total");
Tax = Quote.get("Tax");
Adjustment = Quote.get("Adjustment");
currency_symbol = Quote.get("$currency_symbol");
Quoted_Items = Quote.get("Quoted_Items");
info Quoted_Items;
row_data = list();
// Creating a list of lines
// Headings for the table
header = Map();
header.put("Product Name","Product Name");
header.put("Description","Description");
header.put("Quantity","Quantity");
header.put("Price","Price");
row_data.add(header);
// Filling in the data
resourceId = "m78m951ed261da6564fe898b2892823e9af51";
GrandTotal = 0;
for each rec in Quoted_Items
{
Product_Name = rec.get("Product_Name").get("name");
Article = rec.get("Article");
Color = rec.get("Color");
Packaging = rec.get("Packaging");
Fabric_model = rec.get("Fabric_model");
Print_size = rec.get("Print_size");
Product_size = rec.get("Product_size");
Print_type = rec.get("Print_type");
Quantity = rec.get("Quantity");
List_Price = rec.get("List_Price");
Total = rec.get("Total");
Link = rec.get("Link");
Parent_Id = rec.get("id");
Preview = rec.get("Preview");
for each rec in Preview
{
fileId = rec.get("File_Id__s");
info "fileId: " + fileId;
File_Name__s = rec.get("File_Name__s");
if(rec.get("File_Id__s") != null)
{
// Uploading the file by FileID
fileDownloadUrl = "https://www.zohoapis.eu/crm/v8/files?id=" + fileId;
// Making a GET request
file = invokeurl
[
url :fileDownloadUrl
type :GET
connection:"crm_zoho_dev"
];
info file;
file.setParamName("file");
//
header.put("x-filename",File_Name__s);
header.put("x-parent_id","m78m95115e88cd68f4978895817486547edf4");
header.put("upload-id",fileId);
header.put("x-streammode","1");
response = invokeurl
[
url :"https://upload.zoho.eu/workdrive-api/v1/stream/upload"
type :POST
parameters:file
headers:header
connection:"workdrive"
content-type:"application/octet-stream"
];
info response;
//
resource_id = response.get("data").get(0).get("attributes").get("resource_id");
info resource_id;
Preview = "https://previewengine-accl.zoho.eu/image/WD/" + resource_id;
//
}
}
// Preview = "https://crmsandbox.zoho.eu/crm/devzn/specific/ViewAttachment?fileId=" + fileId + "&module=QuotedItems&fieldId=625426000000542577&parentId=" + Parent_Id + "&name=" + file + "&downLoadMode=default";
Preview = "=IMAGE(\"" + Preview + "\";1)";
info Preview;
//
row = Map();
row.put("Product Name",Product_Name);
row.put("Preview",Preview);
row.put("Q",Quantity);
row.put("Item Price",List_Price);
row.put("Total Price",Total);
row.put("Link",Link);
row.put("Article",Article);
row.put("Color",Color);
row.put("Fabric / model",Fabric_model);
row.put("Packaging",Packaging);
row.put("Product Size",Print_size);
row.put("Print Type",Print_type);
row.put("Print Size",Print_size);
row.put("Project name",Account_Name);
row.put("Account manager",Owner);
row.put("Delivery info",Delivery_address);
row.put("Ready by date",Ready_by_date);
rowsData = List();
rowsData.add(row);
queryData = Map();
response = zoho.sheet.createRecords(resourceId,"Sheet2",rowsData,queryData,"zoho_sheet");
// info response;
}
//
paramMap = Map();
paramMap.put('method','workbook.copy');
paramMap.put('resource_id',resourceId);
paramMap.put('workbook_name',Subject);
paramMap.put('parent_id','hmb7xd57420ae63934e46991c703d67eae9de');
paramMap.put('copy_lock_settings','true');
response = invokeurl
[
url :"https://sheet.zoho.eu/api/v2/copy"
type :POST
parameters:paramMap
connection:"zoho_sheet"
];
info response;
workbook_url = response.get("workbook_url");
info workbook_url;
//
formData = Map();
formData.put("attachmentUrl",workbook_url);
formData.put("title",Subject);
response = invokeurl
[
url :"https://www.zohoapis.eu/crm/v7/Quotes/" + QuoteID + "/Attachments"
type :POST
parameters:formData
connection:"crm_zoho_dev"
];
info response;
//
if(response.get("code").contains("DUPLICATE_DATA") == true)
{
result = response.get("message");
}
else
{
result = "Files Generated";
}
//
paramMap = Map();
paramMap.put('method','range.content.clear');
paramMap.put('worksheet_name','sheet2');
paramMap.put('start_row',2);
paramMap.put('start_column',1);
paramMap.put('end_row',50);
paramMap.put('end_column',17);
response = invokeurl
[
url :"https://sheet.zoho.eu/api/v2/" + resourceId
type :POST
parameters:paramMap
connection:"zoho_sheet"
];
info response;
Key Variables / Identifiers
- resourceId — ID of the template Zoho Sheet workbook from which a copy is made.
- x-parent_id — the WorkDrive folder where preview files are uploaded (and where the workbook copy is also stored).
- parent_id (in copy) — the destination folder for the copied workbook (may match or differ from x-parent_id).
- workbook_url — the link to the copied workbook (attached to the Quote in CRM).
- QuoteID — the target Quotes record in Zoho CRM.
Why do this (practical effect)
- Visualized Quotes: each line item receives a live preview directly inside Zoho Sheets — convenient for sharing with clients or colleagues.
- Single artifact: the resulting workbook with all rows and images is automatically attached to the corresponding Quote record in CRM.
- Auto-cleanup: subsequent generations don’t clutter the template — the defined range is cleared automatically after each run.