Hi there “Process Automation” fans,
Welcome to a new installment of “Process Automation” tips.
Let me start with an honest statement; I have never used “Business Calendars” in any of my projects…UNTIL NOW! I was also the one always telling we could do without them. That’s indeed true, but with larger business projects, you want to use them calculating business working days, including all the extra free days within a country you craft the solution. And indeed…The world shifts when it gets to public free days, and there isn’t a single rule applicable to all! So, you want to be in control with indeed the power of “Business Calendars”…
OPA
24.3
has an enhancement feature for the ‘Business Calendar’ type of document; Read about it here
Let’s get right into it…
Where to start when your VM of OPA is already operational? Well, jump into your project and directly create a new type of document within the configs
folder of the project:
Yes, you see it correctly…We start with the exceptional days (or public holidays) that we connect to the real ‘Business Calendar’. I do a first implementation like this:
You see also all the public holidays are behind us! It’s now sweating till Christmas! 💦 😅 💦
Save it and move to the next ‘Business Calendar’ implementation:
In the ‘Calendar Exceptions’ tab, you select the exceptions document; Make sure to also set the correct time-zone settings in the final tab:
Do a publication…
…
Now what to do? Indeed, a valid question with a solid answer continuing your read…
The first thing you want to do in your project is adding a new runtime reference from the context menu of your project; Nicely saved in the runtimerefs
folder. It’s of type ‘Web Service Interface’:
You see multiple ‘BusinessCalendar’ method sets; You want “the one” with the red arrow! The other one is legacy from the enhanced version!
Services exploration
Time to explore some service calls (which I cleaned from namespace declarations for readability). First a grip on our crafted calendar:
1 | <SOAP:Envelope> |
With a response of:
1 | <data> |
Next is calculating a start-date based on an end-date.
1 | <SOAP:Envelope> |
Format for date can also be
yyyy/MM/dd
…Just that you know!
The response for this is:
1 | <data> |
Is this correct? Yes! As 2025-06-17
is a Tuesday and the time is exactly 1 hour and 1 minute less!
Now watch this table with the same hours/minutes subtraction:
Input | Output | Explanation |
---|---|---|
2025-06-16T11:00:00.0 |
2025-06-16T09:59:00.0 |
As expected for a Monday morning! |
2025-06-16T09:00:00.0 |
2025-06-16T07:59:00.0 |
Again, expected |
2025-06-16T08:00:00.0 |
2025-06-13T14:59:00.0 |
Interesting, as that’s a Friday; 1 minute before 15.00 u. with respect of the week-end! |
2025-06-13T08:00:00.0 |
2025-06-12T14:59:00.0 |
That’s consistent! |
Ok, why 15.00
as my business days end at 17.00? Does the service call respect my weekdays configuration? Yes it does as when my Friday end at 18.00 I get a return value of ...T15:59:00.0
…So, why a difference of 2 hours!? Well, that’s a time-zone thing where our response is a worldwide UTC/GMT time when I’m in a CEST zone 2 hours later! Let’s not dive into this now…I’ll leave it with you. For me, it still works as expected!
Let’s move on to another service call:
1 | <SOAP:Envelope> |
The response of the call gives the start of the previous day:
1 | <data> |
With
<moveToEndOfPreviousDay>true</moveToEndOfPreviousDay>
it’ll give2025-06-13T15:00:00.0
!! Watch closely as that’s BEFORE the weekend where the 17th is on a Tuesday! So, it’s respecting the configured business days!
…
How about the other way around? Well, calculateEndDate
and calculateEndDateInBusinessDays
works the same…Only calculating forward! Let’s focus on the “What else?” question…
1 | <SOAP:Envelope> |
With an interesting result which is FALSE (for a Tuesday, June 17th 2025 11.00)!? That’s weird…Looks like it’s time for a remote debugging session on a fascinating class com.cordys.businesscalendar.BusinessCalendarRequestHandler
within OPA library %CORDYS_HOME%/components/bpmengine/bpmengine.jar
Only, just before I start my R&D remote debug session I directly see the problem (and that my friends, is eXperience!):
That’s #BUG #SUPPORT
Let’s give it another shot with this SOAP message:
1 | <SOAP:Envelope> |
Now we nicely get a response of TRUE and 2025-06-17T6:00:00.0
is FALSE (not a weekend, but outside business hours)!
What else?
…
What about this one:
1 | <SOAP:Envelope> |
The response is 28800000
!?…Yes, that’s milliseconds! Where 28800000/1000
is 28800
seconds, and 28800/60/60
is 8 hours! Exactly 1 “working” day! 🥳
…
Now for this one:
1 | <SOAP:Envelope> |
Input | Output | Explanation |
---|---|---|
2025-06-17T11:00:00.0 |
2025-06-17T11:00:00.0 |
That’s the same output as we’re in the middle of a working day already! |
2025-06-17T02:00:00.0 |
2025-06-17T07:00:00.0 |
Agree, as our working day will start at 07.00 |
2025-06-15T02:00:00.0 |
2025-06-16T07:00:00.0 |
Agree again, as the 15th is a Sunday in the weekend. 16th 7.00 is Monday morning |
So, it all works as expected! NICEEEE stuff…
The opposite for this service call is
calculateLatestBusinessDate
…One for your own to figure out!
What else? Well, for the service calls we leave it for now…Time to dive into a new section of using BCs.
Use a Business Calendar (in BPMs)
First make sure you have a new BPM available; Just a simple one-activity BPM (saved in the bpms
folder of the project) like this with a selection of your business calendar:
Now attach a ‘User Interface’/‘Entity Layout’ to the activity (from the activity context menu) and have a look at the ‘Duration’ tab using a BC to calculate a due time for the task:
So, starting this process will land a task in the inbox for the current user with a due date of seven business(!) days later.
You can also apply this same setting for a ‘Delay’ construct:
That’s the same for a ‘Time-out’ construct:
These examples are for BPMs…That’s nice, but we are more interested in terms of entities, lifecycles, deadlines, and due-date properties!
Use BCs in entity modelling-land
Create yourself a ‘Case’ entity with a case_name
(as TEXT) and case_completion_date
(as DATE) property and generate the rest. Add the ‘Lifecycle’ BB and have first glimpse on the business calendar settings for a lifecycle:
You can also scope down further with a same setting on ‘Activity’ level:
…
Can we do more?…Yes, please! 😎
Add a ‘Deadline’ building block to the entity with the name dl_for_completion
and do an implementation like this:
Now for the great trick which is setting the ‘Completion date’ to a valid date considering our business day! Aha…Now it gets interesting as that’s (advanced) business logic! 🤔
With “advanced” I mean BPM logic beyond what is out-of-the-box possible with a simple ‘Rule’ BB!
Start with the creation of a ‘Rule’ BB (of type ‘Event - Application UI’) on the entity with name e_opc_set_completion_date
and implemented like this:
I have version
25.2
with the use of client-side action events and multi-action rules
So, when the completion date is empty (you don’t want to set it again!) and the lifecycle has an instance state, we’ll set the completion date property to now
…Do a deployment and check it out! Works like a charm, but that’s not the point. You can even do things like this:
now + 1
today + 7
today + duration(0, 0 , 7)
which is [year, month, day]!today + duration("P7D")
read about this XML duration format here
The only disadvantage is that it’s not respecting our business calendar days AND that’s where the fun starts with a BPM and our previous explained BC webservices knowledge!
So, today is the 20th of June 2025 (a Friday) which makes the next 7 business days land on 1st of July 2025 (a Tuesday) where I see just 7 days down the road:
A BPM implementation calculation date respecting business days
Move back into the ‘Rule’ BB and change the action to start a process/BPM (saved in the bpms
folder of the project!):
I move the global condition of the ‘Rule’ BB to an action specific condition; Why? Because otherwise the BPM does not trigger; it will only fire when changing one of the properties in the condition. I know it has to do with the “advanced” setting “Start the process only when the specified condition changes from false to true”, but it behaves very weird. Only true
is also not working; that’s why I use(item.Lifecycle.InstanceStatus=="New" && item.Properties.case_completion_date==null) || true
This behaves the same but smells different…Weird OPA things!? 🙃 Now it always starts independent of that weird checkmark. Ohwwwww…That global condition is now set the true
…Has it something to do with it?…I continue my life.
Do a first quick deployment to see if the BPM instance (from the PIM perspective) is visible!
…
This BPM requires some steps…It needs to calculate the business days (let’s say 7 for now) from today (when the BPM starts) and it needs to update our ‘Case’ entity instance with a valid completion date!
For this we miss one puzzle piece which is the ‘Web service’ BB on the entity with the exposure of the ‘Update’ operation:
Do a quick publication! AND because of this BB, we also require a new service container of type ‘Application Server’ from the ‘System Resource Manager’ to support this…I leave this task for you; Give a comment if you don’t have a clue.
We continue with the (by default) long-lived BPM implementation like this:
With this consolidated view for the messagemap:
I found this one via my ChatGPT friend:
java.time.Instant.ofEpochMilli(number(instance:instanceProperties/instance:startTime/text()))
See more of these examples here
The BC service call ‘calculateEndDateInBusinessDays’ eventually looks like this resulting in 2025-07-01T15:00:00.0
:
1 | <SOAP:Envelope> |
FYI an interesting observation; A long-lived BPM triggering a client-side ‘Rule’ BB!? That doesn’t make up as client-side has an “on-the-fly update mindset”, so a short-lived BPM would be a better choice. Does it still update runtime on the fly which is the mindset of client-side? Well, NOPE! BUT we can simply update this execution mode in the properties of the BPM…Also, a task for yourself (incl. the deployment of the change)!
It’s time for weekend my friends…We learned our lessons, and we shared some great tricks again…
A great “DONE” where we finally found our use-cases implementing the ‘Business Calendar’ type of document. As I review the post, it’s also a rather simple concept that just needs to snap. Where (as for me), you first need put with your nose onto the facts to see the advantages. Well, the facts are clear now and the business calendars will get back more often at other projects from now on (if requested!). Have a great weekend!
Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The Process Automation guy”?