Dynamics 365 CE with PSA version 3.7
The idea for this blog post came from a conversation on the D365 CE Partner Connect Yammer. Kerry Burn with The 848 Group and CIM had a good question about syncing Project Task information with Bookable Resource Bookings to a user’s calendar in Exchange. Syncing information about Project Tasks has never been supported OOTB and the whole sync feature seems to be deprecated for PSA and Field Service. So what Kerry was looking for is not supported OOTB but my thought is that Flow should be able to glue all the pieces together. Let’s see what happens!
The objective and some background info
The objective is to sync information about Project Tasks to a user’s Exchange calendar. As bookings and assignments are only loosely coupled in PSA V3, achieving the objective is only possible when Resource Assignments (later RA) are used. This is because an RA has a lookup to a Project Task but a Bookable Resource Booking (later BRB) doesn’t. An RA also has a lookup to a Project Team Member (later PTM) and it also holds the from/to dates of an assignment. It’s safe to say that an RA is our fiend in this scenario.
So the Resource Assignment entity is our friend and we’ll use that as the entity for the Flow’s create/update current environment trigger. When a Flow is in a solution, it’s possible to use the CDS current environment trigger, which can be used for both create and update. Another option would be to use Project Team Member but we’ll go with Resource Assignment this time. A related PTM will still be referenced in the Flow. When either a booking or an assignment is created, a PTM record is either created or modified – depending on the scenario. A PTM record holds information about Hard Booked Hours and Assigned Hours and the fields containing those pieces of information will be used as condition in the Flow.
Time zones and the OOTB code and logic
By now we have established that we’re syncing Resource Assignments to Exchange, when a Resource Assignment is created or modified. As we’re talking about date and time related information, time zones will need to be taken into account in the Flow. What I found out during testing was that if date fields on a Resource Assignment record are edited manually, the dates that are synced to Exchange will differ from a scenario where information is edited by using PSA’s user interface (the reactive grids under a Project’s Schedule tab and Resource Assignments tab). This happens because there will be a difference in how data is saved to the database. As I’m writing this blog post, I’m waiting for some feedback from the Product Group about my findings. For now I recommend editing task and assignment related information through the Project entity’s reactive grids.
I spent a good amount of time banging my head against the wall with time zones, while experiencing different results depending on my approach. As we’re talking about a Microsoft 1st party app, there is a fair bit of code in the background. The OOTB logic may cause the Flow to fire off twice when changes to effort or from/to dates are made from the Schedule tab or the Resource Assignments tab. If this occurs, a double calendar entry in Exchange may be created if an entry does not already exist for the specific Resource Assignment in question. If an entry is found in Exchange, the Flow simply updates the calendar entry with the latest changes. Seeing as the issue with a double entry in Exchange is not critical, I’m not diagnosing this “bug” further. I think this is a good example of something you can expect to run into when extending the 1st party apps.
A prerequisite for the Flow is an Azure AD App, just like in my post about Creating a Planner plan from a D365 PSA Project with Flow. That post will get you forward with AAD Apps, if you’re not familiar with them. I also advise you to consider the consequences of creating and editing events in users’ calendars, before creating and using this Flow. The Flow can be downloaded from the TDG Power Platform Bank and the download link can be found at the end of the blog post.
The first step consists of the trigger and the Compose actions for app ID, secret and tenant ID. We also need to access the PTM record so a get action is needed. If an event is created to a user’s default calendar, then the compose action should state Calendar. The Flow is built in a solution and is using the latest Common Data Service (current environment) trigger. This trigger either creates or updates a record. In this example, a record is updated when either the hours, from or to field changes.
Step 2’s Scope – Get Records is all about checking that Assigned Hours and Hard Booked Hours contain data and then getting the related Project, Project Task, Role, Bookable Resource and User records. User record gets us access to a user’s O365 user profile, so that we can get a user’s User Principal Name (UPN). The condition’s Configure run after has been set to include both is successful and has failed. This way the Flow won’t fail if there is no Project Team Member on a Resource Assignment. An example of such a case is when a new Project Task is created from a Project’s Schedule tab.
In step 3’s Scope – Exchange Actions, the work around calendars begins. The first action will be to define what the subject of a new event in a calendar will be. For this example, I’ve used dynamic content from Project name, Project Task name and Role. Next, we’ll get a user’s calendar with the HTTP – Get Calendars action. We can then parse the JSON and filter the results with a Filter array action. We want to see if Name equals the value set in the Compose – Default Calendar name action. In this example the value is Calendar. The JSON schema is included in the zip file that contains this Flow.
After the Filter array action, we have our hands on the specific calendar we’re interested in. Calendar ID is needed so that we can get, post and patch events so a Compose action is used after the Filter array. This automatically creates an Apply to each loop. Next we’ll use an HTTP action to get all events with a subject that matches what we composed for subject earlier. We should only have a single event in Exchange that matches, however if there are duplicates for some reason, the Flow will still update all events where the subject matches. Next we’ll use parse JSON for the previous HTTP action’s content. The schema is included in the zip file that contains this Flow.
After the parse JSON it’s compose time again. I want events in the calendar to start at 8 AM so I’m adding 8 hours to an event’s start and end time. The expressions are:
The outputs of the start and end time compose actions are used in the next action, which is used to build the event body. Dynamic content is used for subject, start and end. Note the time zone: For this example I’ve set it to FLE Standard Time in the compose action. The JSON schema in the compose is included in the zip file that contains this Flow.
The final and 5th step is all about either updating an existing event or creating a new event in a user’s calendar. The condition checks if Parse JSON – Get events returns a subject that equals the subject we defined in the Compose subject for Exchange calendar event action. If a match is found, an existing calendar event is updated. For this, an event ID needs to be composed. We will get our hands on the ID from the previous step’s Parse JSON – Get Events action. If a match for the subject is not found, a new event will be created in a user’s calendar. For both the true and false side, the body of the HTTP PATCH/POST is based on the Compose – Event body action.
That’s all folks! I hope this blog post helps you pull Resource Assignments that are also tied to Bookable Resource Bookings to a user’s calendar in Exchange. If you want to try this Flow out, you can download both a managed and an unmanaged solution from the TDG Power Platform Bank here.