For Zoho Services only:


I'm actually part of something bigger at Ascent Business Solutions recognized as the top Zoho Premium Solutions Partner in the United Kingdom.

Ascent Business Solutions offer support for smaller technical fixes and projects for larger developments, such as migrating to a ZohoCRM.  A team rather than a one-man-band is always available to ensure seamless progress and address any concerns. You'll find our competitive support rates with flexible, no-expiration bundles at https://ascentbusiness.co.uk/zoho-services/uk-zoho-support.  For larger projects, talk to our experts and receive dedicated support from our hands-on project consultants at https://ascentbusiness.co.uk/zoho-services/zoho-crm-implementation.

The team I manage specializes in coding API integrations between Zoho and third-party finance/commerce suites such as Xero, Shopify, WooCommerce, and eBay; to name but a few.  Our passion lies in creating innovative solutions where others have fallen short as well as working with new businesses, new sectors, and new ideas.  Our success is measured by the growth and ROI we deliver for clients, such as transforming a garden shed hobby into a 250k monthly turnover operation or generating a +60% return in just three days after launch through online payments and a streamlined e-commerce solution, replacing a paper-based system.

If you're looking for a partner who can help you drive growth and success, we'd love to work with you.  You can reach out to us on 0121 392 8140 (UK) or info@ascentbusiness.co.uk.  You can also visit our website at https://ascentbusiness.co.uk.

Zoho Inventory & eBay Picture Services: UploadSiteHostedPictures

What?
This is an article documenting the process of publishing a Zoho Inventory image to eBay's Picture Hosting Services (EPS).

Why?
Because I couldn't find any other article in the whole world wide web that had a working solution. My use-case here is that I have built an eBay integration between Zoho Inventory and... eBay. Out-of-the-box, and at-time-of-print, Zoho Inventory only syncs eBay one way, in other words, listings on eBay get downloaded to Zoho Inventory but not vice-versa. Then there's an added delay of 4 hours. Then item specifics in eBay's listings don't get parsed into custom fields in Zoho Inventory... and the list goes on. So in my job, we tend to create a few custom functions which will download any item from eBay to Zoho Inventory and vice-versa. Easy to make the function to push an item to an eBay listing (see my other articles for this). But we also want to push an image from Zoho Inventory to eBay.

How?
Again, there is a caveat in that the subscription you have or your client has, needs to be Zoho One. Because we're going to use Zoho Creator as a middleware. Just to add to the pain, I'm going to make my function in Zoho CRM:

Overview
  1. Create a REST API CRM function that can return the ebay URL of the image.
  2. Done

High Level Overview
  1. Create a REST API CRM function
  2. Get Zoho CRM to create a Zoho Creator record by passing it the Inventory ID
  3. Get Zoho Creator to accept this ID, download the file, and upload it to a "File Upload" field
  4. Get Zoho Creator to generate a published / public URL of the file
  5. Get Zoho CRM to scan Creator for the public URL and retrieve this
  6. Get Zoho CRM to generate an XML request to upload the photo to eBay's Hosted Picture Services
  7. Get Zoho CRM to parse the eBay response and return the eBay hosted URL

Detailed Step-by-step
  1. Add Zoho Creator to your Zoho One
    1. Login to Zoho One
    2. Go to Settings (cog in top right)
    3. Click on Applications i the sidebar
    4. Click on the Add Application button
    5. Select Creator by clicking the Add button below it
    6. Link it if applicable to your super admin account
  2. Create an app, a form and publish it in Zoho Creator
    1. Create an app by clicking on Create App
    2. then go into the app and Create a form, I'm calling mine Inventory Photo
    3. Add 3 fields to this form
      • Zoho Inventory ID which is a single-line/text field
      • Creator File which is a file upload field
      • Public URL which is a URL field
    4. Publish it by going to Settings > Publish > Publish Component > and select the REPORT (eg. "Inventory Photo Report"). Note the embed code, specifically the long alphanumeric string.
  3. Create a connection from Zoho Creator to Zoho Inventory
    1. 3 lines icon in the top-left of your Creator (in edit this application mode)
    2. Then go to Setup > Connections > Add Connection
    3. Select Zoho OAuth and specify the scope(s) ZohoInventory.items.READ (add some more if you're unsure...)
    4. Give it a connection name and note down the connection link name. I'm calling mine joel_zoho
    5. Authorize it, etc.
  4. Make a workflow which does the clever bit in Zoho Creator:
    1. Go to Workflow > Form Workflows > New Workflow
    2. Choose the form > Run when Created or Edited > Trigger on Successful form submission > and name it OnSubmit > click on Create Workflow
    3. Select you want to run some Deluge Script and plug in the following code
      copyraw
      if(!isnull(input.Zoho_Inventory_ID))
      {
      	//
      	// specify your own Inventory/Books organization ID
      	v_BooksOrgID = 20221234567;
      	//
      	// determine URL of file to download (note the DC here is EU but yours might be COM)
      	v_Url = "https://inventory.zoho.eu/api/v1/items/" + input.Zoho_Inventory_ID + "/image?organization_id=" + v_BooksOrgID + "";
      	r_File = invokeurl
      	[
      		url :v_Url
      		type :GET
      		connection:"joel_zoho"
      	];
      	r_File.setParamName("file");
      	//
      	// store this file in the field "Creator File"
      	input.Creator_File = r_File;
      	//
      	// use publish key of the report
      	v_PublishKey = "AAAAABBBBBCCCCDDDDEEEFFFGGGGHHHIIIJJJKKLLLMMMNNOOOPPPQQWRRRSSTTUUVVWWXXYYZZ122345567890";
      	//
      	// determine the public URL of the file on this record
      	v_PublicUrl = "https://creatorapp.zohopublic.eu/file" + zoho.appuri + "Inventory_Photo_Report/" + input.ID + "/Creator_File/download/" + v_PublishKey + "?filepath=/" + input.Creator_File;
      	//
      	// add it to the public URL field
      	input.Public_URL = v_PublicUrl;
      }
      1.  if(!isnull(input.Zoho_Inventory_ID)) 
      2.  { 
      3.      // 
      4.      // specify your own Inventory/Books organization ID 
      5.      v_BooksOrgID = 20221234567
      6.      // 
      7.      // determine URL of file to download (note the DC here is EU but yours might be COM) 
      8.      v_Url = "https://inventory.zoho.eu/api/v1/items/" + input.Zoho_Inventory_ID + "/image?organization_id=" + v_BooksOrgID + ""
      9.      r_File = invokeUrl 
      10.      [ 
      11.          url :v_Url 
      12.          type :GET 
      13.          connection:"joel_zoho" 
      14.      ]
      15.      r_File.setParamName("file")
      16.      // 
      17.      // store this file in the field "Creator File" 
      18.      input.Creator_File = r_File; 
      19.      // 
      20.      // use publish key of the report 
      21.      v_PublishKey = "AAAAABBBBBCCCCDDDDEEEFFFGGGGHHHIIIJJJKKLLLMMMNNOOOPPPQQWRRRSSTTUUVVWWXXYYZZ122345567890"
      22.      // 
      23.      // determine the public URL of the file on this record 
      24.      v_PublicUrl = "https://creatorapp.zohopublic.eu/file" + zoho.appuri + "Inventory_Photo_Report/" + input.ID + "/Creator_File/download/" + v_PublishKey + "?filepath=/" + input.Creator_File; 
      25.      // 
      26.      // add it to the public URL field 
      27.      input.Public_URL = v_PublicUrl; 
      28.  } 
  5. Create a workflow to tidy up the records daily in Zoho Creator
    1. Go to Workflow > Schedules > New Workflow
    2. Set the Start date and time to tomorrow's date at 2:00am
    3. Run Daily
    4. Name the workflow Daily Delete Record
    5. Click on Create Workflow
    6. Give it the following code:
      copyraw
      for each  r_ApplicableRecord in Inventory_Photo[Added_Time <= zoho.currenttime.subDay(1)]
      {
      	delete from Inventory_Photo[ID == r_ApplicableRecord.ID];
      }
      1.  for each  r_ApplicableRecord in Inventory_Photo[Added_Time <= zoho.currenttime.subDay(1)] 
      2.  { 
      3.      delete from Inventory_Photo[ID == r_ApplicableRecord.ID]
      4.  } 
  6. Create a CRM connection to Zoho Creator
    1. Login to ZohoCRM
    2. Go to Setup > Developer Space > Connections
    3. Create Connection
    4. Give it the scope(s): ZohoCreator.form.CREATE and ZohoCreator.report.READ (more if this doesn't work properly)
    5. Give it a name, I'm calling mine joel_creator
    6. Authorize it, etc.
  7. Create a REST API CRM Function
    1. Login to ZohoCRM
    2. Go to Setup > Functions > New Function
    3. Give it a name and such, I'm doing the following
      • Function Name: fn_eBay_UploadPhoto
      • Display Name: Fn - eBay - Upload Photo
      • Description: What it says on the tin
      • Category: Standalone
      • Click on Create
      • Give it the parameter/argument p_InventoryitemID as an Integer/Long/Number datatype
    4. As the first part of your code, enter the following as code (you'll need to speify your own App Owner and App Name):
      copyraw
      //
      // ************************************************** CREATOR **************************************************
      v_ItemId = ifnull(p_InventoryItemID,0);
      v_PublicUrl = "";
      //
      // send Zoho Creator the inventory ID
      v_AppOwner = "JoelGoHappy";
      v_AppName = "ZohoInventory_eBayPictureServices";
      v_FormName = "Inventory_Photo";
      v_ReportName = "Inventory_Photo_Report";
      m_Blank = Map();
      m_CreatorParams = Map();
      m_CreatorParams.put("Zoho_Inventory_ID",v_ItemId);
      r_Creator = zoho.creator.createRecord(v_AppOwner,v_AppName,v_FormName,m_CreatorParams,m_Blank,"joel_creator");
      if(!isnull(r_Creator.get("data")))
      {
      	if(!isnull(r_Creator.get("data").get("ID")))
      	{
      		r_CreatorDetails = zoho.creator.getRecordById(v_AppOwner,v_AppName,v_ReportName,r_Creator.get("data").get("ID").toLong(),"joel_creator");
      		if(!isnull(r_CreatorDetails.get("data")))
      		{
      			if(!isnull(r_CreatorDetails.get("data").get("Public_URL").get("url")))
      			{
      				v_PublicUrl = r_CreatorDetails.get("data").get("Public_URL").get("url");
      			}
      		}
      	}
      }
      info r_Creator;
      1.  // 
      2.  // ************************************************** CREATOR ************************************************** 
      3.  v_ItemId = ifnull(p_InventoryItemID,0)
      4.  v_PublicUrl = ""
      5.  // 
      6.  // send Zoho Creator the inventory ID 
      7.  v_AppOwner = "JoelGoHappy"
      8.  v_AppName = "ZohoInventory_eBayPictureServices"
      9.  v_FormName = "Inventory_Photo"
      10.  v_ReportName = "Inventory_Photo_Report"
      11.  m_Blank = Map()
      12.  m_CreatorParams = Map()
      13.  m_CreatorParams.put("Zoho_Inventory_ID",v_ItemId)
      14.  r_Creator = zoho.creator.createRecord(v_AppOwner,v_AppName,v_FormName,m_CreatorParams,m_Blank,"joel_creator")
      15.  if(!isnull(r_Creator.get("data"))) 
      16.  { 
      17.      if(!isnull(r_Creator.get("data").get("ID"))) 
      18.      { 
      19.          r_CreatorDetails = zoho.creator.getRecordById(v_AppOwner,v_AppName,v_ReportName,r_Creator.get("data").get("ID").toLong(),"joel_creator")
      20.          if(!isnull(r_CreatorDetails.get("data"))) 
      21.          { 
      22.              if(!isnull(r_CreatorDetails.get("data").get("Public_URL").get("url"))) 
      23.              { 
      24.                  v_PublicUrl = r_CreatorDetails.get("data").get("Public_URL").get("url")
      25.              } 
      26.          } 
      27.      } 
      28.  } 
      29.  info r_Creator; 
    5. And here's the 2nd part of the function in CRM
      copyraw
      //
      // ************************************************** EBAY **************************************************
      // init
      v_EbayImageURL = "";
      //
      // eval
      v_Endpoint = "https://api.ebay.com/ws/api.dll";
      v_ApiCall = "UploadSiteHostedPictures";
      //
      // a CRM record that holds my API connection details
      v_IntegrationRecordID = 123456789012345678;
      r_CrmRecord = zoho.crm.getRecordById("Integrations",v_IntegrationRecordID);
      v_TradingAPIVersion = r_CrmRecord.get("Compatibility_Version");
      //
      // Another REST API CRM function which generates an eBay Access Token for me
      r_Response = getUrl("https://www.zohoapis.eu/crm/v2/functions/fn_ebay_getaccesstoken/actions/execute?auth_type=apikey&zapikey=1003.<REST_OF_YOUR_ZAPIKEY>");
      if(!isnull(r_Response.toMap().get("details")))
      {
      	if(!isnull(r_Response.toMap().get("details").get("output")))
      	{
      		v_AccessToken = r_Response.toMap().get("details").get("output");
      	}
      }
      info v_AccessToken;
      //
      // build header
      m_Headers = Map();
      m_Headers.put("X-EBAY-API-SITEID",3);
      m_Headers.put("X-EBAY-API-COMPATIBILITY-LEVEL",v_TradingAPIVersion);
      m_Headers.put("X-EBAY-API-CALL-NAME",v_ApiCall);
      m_Headers.put("X-EBAY-API-IAF-TOKEN",v_AccessToken);
      //
      // build params
      m_Params = Map();
      m_Params.put("WarningLevel","High");
      m_Params.put("ErrorLanguage","en_GB");
      m_Params.put("ExternalPictureURL",v_PublicUrl);
      m_Params.put("PictureName","OhBeautifulMe");
      m_Params.put("PictureSet","Supersize");
      //
      // convert to xml and replace root nodes
      x_Params = m_Params.toXML();
      x_Params = x_Params.toString().replaceFirst("<root>","<?xml version=\"1.0\" encoding=\"utf-8\"?><" + v_ApiCall + "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">");
      x_Params = x_Params.toString().replaceFirst("</root>","</" + v_ApiCall + "Request>");
      info x_Params;
      //
      // send the request XML as a string
      r_ResponseXML = invokeurl
      [
      	url :v_Endpoint
      	type :POST
      	parameters:x_Params
      	headers:m_Headers
      ];
      info r_ResponseXML;
      //
      // parse response and retrieve the ebay URL of the hosted image
      if(r_ResponseXML.containsIgnoreCase("<Ack>Success</Ack>") || r_ResponseXML.containsIgnoreCase("<Ack>Warning</Ack>"))
      {
      	v_BiggestHeight = 0;
      	x_RespondedXML = r_ResponseXML.replaceFirst("xmlns=\"urn:ebay:apis:eBLBaseComponents\"","",true);
      	x_PictureSets = x_RespondedXML.executeXPath("/"+v_ApiCall+"Response/SiteHostedPictureDetails/*").toXmlList();
      	for each  r_PictureSet in x_PictureSets
      	{
      		if(r_PictureSet.contains("PictureSetMember"))
      		{
      			// get image that is the biggest/tallest
      			v_ThisHeight = r_PictureSet.executeXPath("/PictureSetMember/PictureHeight/text()").toLong();
      			if(v_ThisHeight > v_BiggestHeight)
      			{
      				v_BiggestHeight = v_ThisHeight;
      				v_EbayImageURL = r_PictureSet.executeXPath("/PictureSetMember/MemberURL/text()");
      			}
      		}
      	}
      }
      return v_EbayImageURL;
      1.  // 
      2.  // ************************************************** EBAY ************************************************** 
      3.  // init 
      4.  v_EbayImageURL = ""
      5.  // 
      6.  // eval 
      7.  v_Endpoint = "https://api.ebay.com/ws/api.dll"
      8.  v_ApiCall = "UploadSiteHostedPictures"
      9.  // 
      10.  // a CRM record that holds my API connection details 
      11.  v_IntegrationRecordID = 123456789012345678
      12.  r_CrmRecord = zoho.crm.getRecordById("Integrations",v_IntegrationRecordID)
      13.  v_TradingAPIVersion = r_CrmRecord.get("Compatibility_Version")
      14.  // 
      15.  // Another REST API CRM function which generates an eBay Access Token for me 
      16.  r_Response = getUrl("https://www.zohoapis.eu/crm/v2/functions/fn_ebay_getaccesstoken/actions/execute?auth_type=apikey&zapikey=1003.<REST_OF_YOUR_ZAPIKEY>")
      17.  if(!isnull(r_Response.toMap().get("details"))) 
      18.  { 
      19.      if(!isnull(r_Response.toMap().get("details").get("output"))) 
      20.      { 
      21.          v_AccessToken = r_Response.toMap().get("details").get("output")
      22.      } 
      23.  } 
      24.  info v_AccessToken; 
      25.  // 
      26.  // build header 
      27.  m_Headers = Map()
      28.  m_Headers.put("X-EBAY-API-SITEID",3)
      29.  m_Headers.put("X-EBAY-API-COMPATIBILITY-LEVEL",v_TradingAPIVersion)
      30.  m_Headers.put("X-EBAY-API-CALL-NAME",v_ApiCall)
      31.  m_Headers.put("X-EBAY-API-IAF-TOKEN",v_AccessToken)
      32.  // 
      33.  // build params 
      34.  m_Params = Map()
      35.  m_Params.put("WarningLevel","High")
      36.  m_Params.put("ErrorLanguage","en_GB")
      37.  m_Params.put("ExternalPictureURL",v_PublicUrl)
      38.  m_Params.put("PictureName","OhBeautifulMe")
      39.  m_Params.put("PictureSet","Supersize")
      40.  // 
      41.  // convert to xml and replace root nodes 
      42.  x_Params = m_Params.toXML()
      43.  x_Params = x_Params.toString().replaceFirst("<root>","<?xml version=\"1.0\" encoding=\"utf-8\"?><" + v_ApiCall + "Request xmlns=\"urn:ebay:apis:eBLBaseComponents\">")
      44.  x_Params = x_Params.toString().replaceFirst("</root>","</" + v_ApiCall + "Request>")
      45.  info x_Params; 
      46.  // 
      47.  // send the request XML as a string 
      48.  r_ResponseXML = invokeUrl 
      49.  [ 
      50.      url :v_Endpoint 
      51.      type :POST 
      52.      parameters:x_Params 
      53.      headers:m_Headers 
      54.  ]
      55.  info r_ResponseXML; 
      56.  // 
      57.  // parse response and retrieve the ebay URL of the hosted image 
      58.  if(r_ResponseXML.containsIgnoreCase("<Ack>Success</Ack>") || r_ResponseXML.containsIgnoreCase("<Ack>Warning</Ack>")) 
      59.  { 
      60.      v_BiggestHeight = 0
      61.      x_RespondedXML = r_ResponseXML.replaceFirst("xmlns=\"urn:ebay:apis:eBLBaseComponents\"","",true)
      62.      x_PictureSets = x_RespondedXML.executeXPath("/"+v_ApiCall+"Response/SiteHostedPictureDetails/*").toXmlList()
      63.      for each  r_PictureSet in x_PictureSets 
      64.      { 
      65.          if(r_PictureSet.contains("PictureSetMember")) 
      66.          { 
      67.              // get image that is the biggest/tallest 
      68.              v_ThisHeight = r_PictureSet.executeXPath("/PictureSetMember/PictureHeight/text()").toLong()
      69.              if(v_ThisHeight > v_BiggestHeight) 
      70.              { 
      71.                  v_BiggestHeight = v_ThisHeight; 
      72.                  v_EbayImageURL = r_PictureSet.executeXPath("/PictureSetMember/MemberURL/text()")
      73.              } 
      74.          } 
      75.      } 
      76.  } 
      77.  return v_EbayImageURL; 
    6. Save the CRM function
    7. Hover your mouse cursor over it and click on the ellipsis/3 dots
    8. Select the REST API
    9. Enable REST API
    10. Note the REST API function and you can now call it from wherever.
  8. Done

Additional Caveat(s)
  • This currently does one image from Zoho Inventory. I'll need to add to the code to retrieve the other photos from Zoho Inventory
  • Still to run a few tests but if I'm right in my guesses, if you edit the listing in eBay's interface, it may get confused as to where the photo came from and will error when displaying it. I think it will be fine.

Source(s)
Category: Zoho :: Article: 811

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: Please note that the information provided on this website is intended for informational purposes only and does not represent a warranty. The opinions expressed are those of the author only. We recommend testing any solutions in a development environment before implementing them in production. The articles are based on our good faith efforts and were current at the time of writing, reflecting our practical experience in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com

Related Articles

Joes Revolver Map

Accreditation

Badge - Certified Zoho Creator Associate
Badge - Certified Zoho Creator Associate

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin bc1qf6elrdxc968h0k673l2djc9wrpazhqtxw8qqp4

Ethereum:
Donate to Joel Lipman with Ethereum 0xb038962F3809b425D661EF5D22294Cf45E02FebF
© 2024 Joel Lipman .com. All Rights Reserved.