This article is meant to serve as a how-to guide for building a Liquid Markup statement that can be uside in a webhook body for setting due date. The general principles could be used to create the statement to be used for other use cases as well, but our focus will be on our primay use case. The companion article for this guide is on How to use a Webhook to Set Due Date Field via Trigger or Automation, but that guide does not take business hours or holidays into account.
Liquid Markup can fairly easily be used to add a period of time to a given date, such as add 7 days to the current date, and then the resulting value can be sent via webhook to update the ticket. We have explained the same in the article referenced above; however, this does not take the schedules configured on a Zendesk account into consideration. In order to make the period of time consider business hours and holidays, we need to add some additional processing logic. For our example, we will still be using 7 days notification period, but it should not include weekends or holidays.
In order to help test out our Liquid Markup logic, we have used the Liquid Sandbox website here. We have also found this Liquid markup for date and time article provided by Sweethawk to be a valuable reference. Now for the explanation.
The first thing we have to do is create a reference point for our holidays and business hours. At this time, the Liquid processing engine available to us that is used by Zendesk business rules is not able to directly access the Schedules set on an account, so we have to create a new reference value. We have decided to use Dynamic Content to store the values in order to make it easier to cross-reference in triggers.**
** Dynamic Content is not available on Team plans. If you are on a team plan, you can do the same thing, but you will have to create the business hours and holiday schedules in the triggers directly rather than using Dynamic Content.
For our business hours, we are using a standard Monday - Friday, with Saturday and Sunday being rest periods. Because we are basing our logic solely on days, we do not need to add in specific hours. For the dynamic content, we simply list out the days we are working, capitalizing the first letter of the day and leaving a space in between. This is important as it has to match exactly when we use it in the liquid engine. So our dynamic content piece would be:
Monday Tuesday Wednesday Thursday Friday
Make sure to note down the placeholder value as it will be needed in the trigger. In our case, it is `{{dc.business_days}}`. Also of note, you can create multiple different schedules for different teams, and then use them in separate triggers.
Next, we will create the holiday schedule. The dates must be written as YYYY-MM-DD, and as above, there must be a space between each holiday. So our resultant list for 2025 would look like the following:
2025-01-01 2025-01-20 2025-02-17 2025-05-26 2025-06-19 2025-07-04 2025-09-01 2025-10-13 2025-11-11 2025-11-27 2025-12-25
As above, make sure to note down the placeholder value as it will be needed in the trigger. In our case, it is `{{dc.holidays}}`. You can also create multiple different holiday schedules for different teams, and then use them in separate triggers.
Next up, we will create our Liquid Markup statement. The full statement we are currently using for this example is below. Of note, we are setting the due date to be 14 business days in the future, so we can consider the holiday in our logic. You can adjust your timing as needed.
{% assign holidays = dc.holidays | split: " " %}
{% assign business_days = dc.business_days | split: " " %}
{% assign time = 'now' | date: '%s' %}
{% assign days = 0 %}
{% for counter in (0..30) %}
{% assign is_holiday = 0 %}
{% assign is_business_day = 0 %}
{% assign time = time | plus: 86400 %}
{% assign d = time | date: '%Y-%m-%d' %}
{% assign t = time | date: '%A' %}
{% for holiday in holidays %}
{% if d == holiday %}
{% assign is_holiday = 1 %}
{% break %}
{% endif %}
{% endfor %}
{% for day in business_days %}
{% if t == day %}
{% assign is_business_day = 1 %}
{% break %}
{% endif %}
{% endfor %}
{% if is_holiday == 0 and is_business_day == 1 %}
{% assign days = days | plus: 1 %}
{% endif %}
{% if days == 14 %}
{% break %}
{% endif %}
{% endfor %}
{
"ticket": {
"due_at": "{{ time | date: '%Y-%m-%d' }}"
}
}
We will explain each line in detail below:
{% assign holidays = dc.holidays | split: " " %}} - This grabs the holiday schedule from our dynamic content and turns it into an array for use in our function to check if any of the upcoming days are holidays. If creating multiple schedules for different teams, change the dc.holidays component to match the Dynamic Content placeholder of the correct holiday.
{% assign business_days = dc.business_days | split: " " %}} - This grabs the business days schedule from our dynamic content and turns it into an array for use in our function to check if any of the upcoming days are outside of business hours. If creating multiple schedules for different teams, change the dc.business_days component to match the Dynamic Content placeholder of the correct schedule.
{% assign time = 'now' | date: '%s' %} - This gets the current time and changes it into a value in seconds to ease in comparison, conversion, and math in our Liquid functions. This line should be copied as is.
{% assign days = 0 %} - This is used as a counter to see when we have reached the correct number of days in the future to set the due date value. This line should be copied as is.
{% for counter in (0..30) %} - This is our main liquid function to help check each day and see if it is a business day, a holiday, or a working day. Due to how loop functions work in Liquid Markup, we have to provide a pre-set number of loops. We have chosen 30, but you may have to increase if you want to set the due date to much farther in the future or have a large number of non-working days. Please not, this number is not for the number of days in the future to set, but is used as a control number.
{% assign is_holiday = 0 %} - This is used to mark whether the day being checked is a holiday, and will be reset on each iteration. This line should be copied as is.
{% assign is_business_day = 0 %} - This is used to mark whether the day being checked is a business day, and will be reset on each iteration. This line should be copied as is.
{% assign time = time | plus: 86400 %} - This is used to advance the day forward by one, which will then be checked against the holidays and business schedules. This line should be copied as is.
{% assign d = time | date: '%Y-%m-%d' %} - This is used to convert the time value into a date, which can then be compared against the holiday schedule. This line should be copied as is.
{% assign t = time | date: '%A' %} - This is used to convert the time value into a day, which can then be compared against the business days schedule. This line should be copied as is.
{% for holiday in holidays %}
{% if d == holiday %}
{% assign is_holiday = 1 %}
{% break %}
{% endif %}
{% endfor %}
This will check each day in the holidays list and see if it matches the day in question. If so, it will mark as a positive match. This block should be copied as is.
{% for day in business_days %}
{% if t == day %}
{% assign is_business_day = 1 %}
{% break %}
{% endif %}
{% endfor %}
This will check each day in the business days list and see if it matches the day in question. If so, it will mark as a positive match. This block should be copied as is.
{% if is_holiday == 0 and is_business_day == 1 %}
{% assign days = days | plus: 1 %}
{% endif %}
This block will check will increment the number of days if it is not a holiday and it is a business day. Meaning it will help to determine if we have reached 14 business days in the future for setting our due date. If the day is not a business day or is a holiday, then the counter will not increment. This block should be copied as is.
{% if days == 14 %}
{% break %}
{% endif %}
This block will check will if we have reached 14 business days in the future. If so, it will end the for loop and the value of our due date will be ready to use. The 14 should be adjusted to whatever value is needed for your use case.
{% endfor %} - This is used to end the forloop. This line should be copied as is.
{
"ticket": {
"due_at": "{{ time | date: '%Y-%m-%d' }}"
}
}
This block will be used to create the payload to update the due date of the ticket. It will convert our final time value into a date of the format required by Zendesk. This line should be copied as is, unless a field other than Due Date is being used.
After you have added this block of code to your trigger payload, you are ready to test it out. As always, we recommend using an inactive email address or adding an additional condition to the trigger such as Subject line contains X string, and only removing it and making it a live trigger once you are confident it is working as expected.
Our test result is below. We sent in the message on 10-January-2025, which is a Friday. We have set up US Federal holidays, which the next one is 20-January-2025. We have set our working hours to Monday - Friday. Our due date is configured to be set to 14 business days in the future.
As you can see below, the due date is set to 31-January-2025, which is 14 business days from today. Test successful!
The above is quite the block of code to be added to the trigger, but we have done our best to make it concise and effective. We have tested it out and it has worked well so far. We are quite happy that we are able to provide this workaround, and we would be happy for any feedback.
Comments
0 comments
Please sign in to leave a comment.