By now I am sure most of you have heard about ChatGPT. The AI product is pouring out surprisingly intelligent responses to all sorts of questions that people all around the world have given it lately.
There have been examples of the tool writing papers for school, creating blog posts for people, and helping formulate fairly complex text for webpages and marketers. One thing that someone tipped me off about was the ability to write code, and I was a bit curious as to what that would mean.
So one of the many gaps in my knowledge is specifically regarding Plugins. A plugin is a piece of backend code that runs in real time when triggers occur in Dataverse. I tried doing a little plugin with some help a few years ago and wrote about it on the Company Blog – Plugin in 1 hour.
I was curious how ChatGPT would do with a similar issue, so I took it for a spin😊
Question
First off I started out with a question that you write the same way you would anything Google/Yahoo/AltaVista/Bing/AskJeeves/DuckDuckGo/etc etc etc
The response I get is fairly spot on. Certainly, some will comment about something not being 100% accurate here, but this is more than good enough and quite well-written!
This wasn’t exactly what I was hoping for, so I asked a follow-up question to my original question.
It thought for a few moments before it started spitting out CODE!! 🤯🤯🤯🤯 (above is just a snip of the total code. I put it all in a code box below).
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Linq;
namespace MyPlugins
{
public class SumProductValues : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Obtain the organization service reference which you will need for CRUD operations.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Retrieve the Opportunity record that the plugin is running against.
Entity opportunity = (Entity)context.InputParameters["Target"];
// Create a query to retrieve the related products.
QueryExpression query = new QueryExpression
{
EntityName = "product",
ColumnSet = new ColumnSet("productid", "price"),
Criteria = new FilterExpression
{
Conditions =
{
new ConditionExpression
{
AttributeName = "parent_opportunity_id",
Operator = ConditionOperator.Equal,
Values = { opportunity.Id }
}
}
}
};
// Retrieve the related products.
EntityCollection products = service.RetrieveMultiple(query);
// Sum up the value of the products.
decimal totalPrice = products.Entities.Sum(product => product.GetAttributeValue<Money>("price").Value);
// Update the Total Price field of the Opportunity record.
opportunity["totalprice"] = new Money(totalPrice);
service.Update(opportunity);
}
}
}
🤯🤯🤯🤯
At this point, I was extremely excited to see that the result is pretty darn good. Sure the trigger here is based on Opportunity, and not the opportunity product, but that is beside the point. It seems that I could have formulated my question in a way that I would have understood it correctly. This is actual usable code for a plugin that could run on Opportunity level to update the sum of all Opportunity products.
Not really sure what more to write about this ATM.. Still trying to wrap my head around it all for now.
In the last post, we created a new close dialog, but we didn’t add any logic to the buttons.
Logic – Fields and Buttons
The most important parameter we send in via JavaScript last time was the GUID of the record that we are going to work with.
The first thing we do is add an onload to the app and perform a lookup as the very first step. This will give us all of the data for that given Opportunity that we can use within the Power App. We store the whole record in a variable “varOpportunity”.
A little clever step here is actually the “First(Opportunities)”. For testing purposes, this will open up the first Opportunity in the DB if you open the app without the GUID from Dynamics, and from here you can test the app make.powerapps.com studio without having to pass a parameter to the Custom Page 👍
Fields can now be added via the “varOpportunity” that contains all of the data to the first opportunity in the system.
BUTTONS
The cancel button only has “back()” as a function to close out the dialog, but the “Confirm WIN” has a patch statement for Opportunity.
//Patch the Opportunity fields
Patch(
Opportunities,
LookUp(
Opportunities,
Opportunity = GUID(VarOppportunity.opportunityid)
),
{
'Actual Close Date': EstClosingDate.Value,
'Actual Revenue': Int(EstimatedRevenue.Value)
}
);
//Hide input boxes and show confirmation
Set(
varConfirmdetails,
false
);
Set(
varCongratulations,
true
);
HIDE/SHOW
Because of some challenges I met with multiple screens, I had to use a single Screen with hide/show logic. Therefore I added all the fields to Groups and will hide Show based on groups.
The Congratulations group looks like this.
Closing the Opportunity Challenge
If this were a custom entity we could close the opportunity by setting the Status and Status Reason values. Unfortunately, the Opportunity has a function for closing the Opportunity that will create a Case close dialog. In order for this to work, we have to call a custom service for closing the Case. This does get a bit tricky.
We now have to call an action from Power Automate to close the opportunity as WON. At the moment of writing the blog, the process of calling the Microsoft action in Power Automate wasn’t working, so I created my own action. I will show you how, and honestly maybe even recommend doing it this way for now. It works all of the time and uses the technology that has been working in CRM since 4.0.
Custom Action
Actions work with the same logic as a Workflow, but they can be fired at any time from anywhere. They can receive inputs, and generate outputs. A workflow will only trigger from CRUD events, and work within the context of the record triggering the actual workflow. They are in many ways an underrated function in Dynamics / Dataverse.
It’s a pretty simple step updating the status of the opportunity to “won”, and by doing it this way the system will automatically do the correct calls in the API for Opportunity Close.
This is all you need for the action. After activation, we can go back to the custom page and create a instant flow (Power Automate).
In the Custom Page we now add a line to our “Confirm WIN” button. (Yes, I know we probably should add some logic for success/fail, but that will be a part of the final solution on Github).
//Patch the Opportunity fields
Patch(
Opportunities,
LookUp(
Opportunities,
Opportunity = GUID(VarOppportunity.opportunityid)
),
{
'Actual Close Date': EstClosingDate.Value,
'Actual Revenue': Int(EstimatedRevenue.Value)
}
);
//Hide input boxes and show confirmation
Set(
varConfirmdetails,
false
);
Set(
varCongratulations,
true
);
//Update Opportunity Close entity
CloseOpptyPostTeams.Run(VarOppportunity.Opportunity);
WINNER WINNER 🏆🥇
You should now be able to close the opportunity as won via a custom page. Just remember to publish the custom page AND publish the app again. If not it will now show. Do remember to give it a few moments before refreshing after a change.
The deprecation of Dialogs has been discussed WAAAY too many times, and I still feel there is a gap for simple dialogs that would do lots of magic. A while back Microsoft introduced Custom Pages as one option to solve this missing piece, but simplicity is just not there yet.
But I can’t quite shake the feeling that it’s still pretty tech-intensive to be able to create a Custom Page and call in from Dynamics. You need to have a decent understanding of the following:
Creating a ribbon button in the new app configuration (easy, but adding commands not so easy)
Javascript to actually start the Custom Page (not for everyone)
Canvas App configuration (I am not a front-end type of guy, and hate having to start with a blank slate every time).
Power FX for the showing of a button + updating whatever you are doing in the canvas app back to the model-driven app.
All in all, I would say that this is probably what you can expect a Dynamics/Power Apps consultant to understand, but it is not given that everyone feels comfortable while configuring. To be honest, Ribbon Workbench isn’t easy without a few tutorials either, but one gets better over time. (did anyone ever get the invert of a true/false statement right the first time?😂).
What to do?
Let’s just get to the bottom of the real issue. How to solve the problem of the Custom Page with a button and at the same time created a great way for sales to have a lot of fun!😁
Over the next weeks, I will start to publish a series of Custom Page and Sales, to showcase what you can do to improve Sales morale and adoption
Every post will be shown on the new Sales Page that I have “Win Notification” so stay tuned!!
The full solution will be available for download in the end.
Custom pages can only have one screen… Right? No, actually they can have multiple screens like a normal Canvas App
I was a bit surprised when learning this because I have been told that there only was one screen per Custom Page. Turns out that Microsoft only recommends one screen pr Custom Page, because they want to isolate the pages better, and rather navigate between custom pages.
In some cases, you actually just want a simple screen instead of a new Custom Page.
Enabling multiple screens
This might be old news for many, but I for one did not notice this before recently🤷♂️
I just participated in a 3 day hackathon ACDC 2022 (arcticclouddeveloperchallenge.net) and it was one of the biggest emotional rollercoasters I have had in MANY years.
Let me just paint the picture first.. ACDC is a yearly hackathon where the best of the best in Norway gather to explore the Dynamics/Power Platform/M365/Azure platforms, creating stellar products. What makes it different from other hackathons?
Mandatory physical attendance
Sleepover at the hotel required, even though you live in the city
Surprise challenges with rewards (head to head)
Lunch and Dinner every day at the hotel, mandatory attendance
Mandatory Socializing activities outside of the teams
Amazing Judges Every time
End of the hackathon dinner and party
Great swag 👊
Lots of energy drinks 🔋
Little to no sleep.. Yea.. I felt that one personally 💤💤💤
I know I know.. Many of the hackathons out there have similar setups, but often they only include parts of what we have to offer. I am of course extremely bias, because I am part of the committee. Today I am writing as the participant from the Team Pizza Time. 🍕
Most of the teams participating were senior teams with tons of experience in Dynamics and lots of years experience within the workforce. We did however have a few new teams with us this year, and that usually is always quite the challenge. The Rules can be complex to follow the first times, and most would struggle keeping up.
The judges this year did an extraordinary job keeping everyone in line, and also helping out all of the new teams understanding what was going on.
Day 1
Welcome commetee
After the initial rigging of computers, each team was introduced. Every team presented their initial ideas and small hints on what technology they were planning to use the next 3 days.
Team:
Mikael Svenson, Eivind Berge, Thomas Sandsør and Poja Mofakheri
Business Case:
Build a Turles HQ
Pizza Ordering Store
Pizza Delivery
An ambitions plan involving the following keywords for technology:
Dataverse
Power Apps Portals
Power BI
Canvas App
Model Driven App
Raspberry PI
IOT (proximity, heat)
Motion Sensor Camera
Hue Color Lights
Intranet in Teams
Progress:
Our team had a pre meeting deciding what tech we wanted to work on, and the scenario’s we wanted to solve. Our scenario was to build a Turtles HQ with security notifications and control center functionality. Then we were going to migrate this story into a Pizza Shop having to work with Pizza Orders and Deliveries.
After our first meeting regarding the solution, I think we all had an idea of what we wanted to solve but not necessarily the same one. It is not uncommon for creative people to think differently about one topic even though they think they are on the same page. This is one of the challenges when working with technology. Later on this would prove to be a huge challenge for our team.
After day one we had been picking a solid amount of points. We had our Teams Intranet, Portals for Ordering, Power Apps for Ordering, Power BI report, Raspberry PI, IOT sensors (2 heat, 2 motion sensors, 1 Hue light bulb), Google Nest Hub, Native React app for Pizza inspo etc etc.. We were on fire, and far beyond the other teams in technology!! (personal opinion). 🔥🔥💯💯
We even won a head to head challenge against the other teams. A challenge where the first one to finish received extra points. In the head to head challenge we had to embed a Power App within Power BI report, and read/edit the data in this Power App. The idea was to update Power Bi directly via the embedded Power App. This scored us a solid extra number of points and a new badge for the collection🥇
At this point in time we were seriously kicking some ass and went to bed as potential winners.
Day 2 – WTF happened?
Where to begin…. I woke up happy and proud of all the achievements from day 1. Everything seemed to be going as I had planned. We were geeking BIG TIME and having so much fun putting different technical things together. We were also gathering lots of the extra bonus points for doing the occasional odd “side quest”.
This day we had started to automate processes so that sensors were triggering events, the Power App was connecting to feedback surveys, and the portal for ordering was working with weather API + maps to give estimated delivery times etc etc.
At the end of the day, every team had to deliver a blog post explaining what we had done since day one. We were 9 teams onsite, so it was important for the judges to have something to read through to be able to cover everyone’s updates. We had made some great progress with our technologies and almost all gadgets were functioning in automation as we had planned. We were feeling quite confident in the next round of points.
This is where the rollercoaster of emotions started! 🎢🎢🎢
Announcing the points from day 2, we had moved from point winners to point losers. We were almost dead last in every category that we had been winning the day before. This was not only the case for Pizza Time, but it was also the case for a few of the other senior teams. What had happened we were asking each other. The junior team with almost no experience at all was getting all of the points. This surely must have been some type of error.. Right!??!?. Of course we had a lot of meetings with the judges trying to figure out what the f*** had happened, but their answers were quite simple.
“Thomas, did you answer how you had added more value to the main categories from day one?”.
Judges
I was baffled..
“Answer: I wrote about all of the amazing things we put together of tech ** Check blog day 2**. What we have done is really cool!!”
Thomas
“But how does that relate to the categories where you present business value, user experience etc?”
Judges
“Well………………..Fuck….
Thomas
I had to think about that one. In my mind the business value was obvious. We had put together so much technology that was pretty impressive (given the amount of time). After about 30 minutes of not saying much, and just looking at my screen in despair, I realized they were right. We were not presenting the solution with a value proposition. It even made us wonder if the initial value proposition was good enough.
After dinner and some “bad vibes”, started what I personally felt was an extraordinary journey. A journey that made me extremely proud to be a part of the team we were on.
We sat down for almost 2 hours straight just breaking down every piece of our solution, trying to figure out what the business value was. We compared it to other deliveries that had lots of points, and that’s when we noticed a few key elements. They were better at selling business value, where the technology only was secondary. It was so simple and obvious that it pissed me off that I hadn’t thought of that before.
The principle applies to every real life scenario. If I can’t convince my customer that my technology add value to their business, they will never by my services.
So the seniors put their heads together and pulled an “all nighter”. We completely ripped our business case apart, and revitalized every aspect of our technology. Our mission was no longer about the Turtles HQ and keeping the city safe from monsters, but it was about the city being in a bad state and helping out those in need.
Day 3
I never really know when I started day 3, because I simply didn’t sleep. I was up all night doing adjustments to the tech, having to say yes/no to a few components. It hurt having to trash parts of a solution I had been working on for 1,5 days, but that’s the name of the game!
Our pitch had moved from a crime fighting city with Turtles, to a city in need of help after covid. Unemployment was up and the gaps in poor were even bigger now than ever before. People living on the street needed food, and we had a service that could provide food for the needy. Our mission statement went from being bold and covering a lot of work loads, to simpler “We make pizza for the people, no matter what social status you have”.
You can read more about our final delivery here, and you could even compare it to the first post if curious
The youngsters made us realize what we should have been focusing on all along. What is the problem, and how can we solve it. We were so focused on being geeks and having fun that we lost track of a key element to delivering IT solutions. I am a little angry that I didn’t think of this earlier when delivering, but at the same time it would not have given us the chance to turn around and prove the value of Senior Consultants. When we got hit in the face with reality, we could have just quit.. Instead we pushed through the night and delivered a phenomenal presentation (personal opinion) that we were really proud of.
Eventually we finished 2nd place behind the kids, but I am extremely happy how the team managed to work together and push each other to the limits. We ended up feeling like we won that 2nd place, and next year you better believe that I am coming for the 1st!!!🏆
When Microsoft introduced Azure for the Microsoft public, it was a new way of thinking. We were suddenly paying for what we needed and when we needed it. Amazon had been there for a long while, but for Microsoft customers this was a new way of thinking. After a skeptical start, this model has really become somewhat of a system standard.
As of today Power Platform will be available on Azure subscription! It is being introduced as a “Pay as you go” model. It is important that you don’t mistake this for the same as Azure. In Azure you actually only pay for the compute time used (in most cases), but here you will pay for a license once you use an application.
WOW THIS IS SOOOO COOL … Well, is it really?
Let’s just think about the following first. Just a few weeks ago Microsoft dropped the prices to half of what they used to cost. They are now only 5$ and 20$ for the different plans. When you think about the value you get from a Dataverse OOTB that is a BARGAIN already.
So why am I not overly excited about the “Pay as you Go” PAYGO model? Well, I don’t really see the big impact yet. Most of my customers are on the CSP agreement, and can flex as much as they feel for. Planning ahead for apps is also hard, and is counter intuitive for innovation. By releasing a plan as PAYGO, you essentially need to plan financially for all users that might use an app, while you silently hope that not all users actually use the app that month. For every user that didn’t use the app, you save some money.
I am sure that the plan makes sense for many scenarios, but I just don’t really see them yet. The good thing is that “limitations/possibilities” for the new plan will be monitored closely in the beginning to find the correct levels for all types of use cases. Remember to voice your opinion if you see some great opportunity. Microsoft will be listening😀
The only thing that we know for sure is that licensing will always be a situation where we as consumers want changes. We want more more more, and want to pay less less less. Microsoft will continuously find new license models to adapt to our wishes while finding ways to keep profits. Don’t get me wrong. I am all about Microsoft being able to charge what they want. After all it’s a great product!!! I’m just saying that you need to look behind the shining stuff before you automatically assume that everything new is automatically better.
What you need to do as a customer is get help to assess assess your licensing situation. Not only is licensing complex from a rules perspective, but the applications can be modified to adapt to licensing changes. I am not saying PAYGO is bad, but I’m not jumping on the PAYGO train quite yet. Most of my customers are CSP customers and have a lot of freedom with licensing (Up and Down). Just going to see what happens first 😁
I might also have misunderstood quite a lot in regards to the benefits received from this model, and if so I would love feedback to learn new ways of thinking!👌
In my last post I wrote about Adaptive Cards in Teams, but a vital factor for that adaptive card to be interesting is the content on the card. Dynamics 365 Sales Adaptive Card🚀.
One of the technical bits last time was connecting with an HTTP GET request to the API. I will be using the same information to create a custom connector so that anyone can reuse for the future 😁
Step 2.. Break down the URL from the first picture like this
Step three… If you don’t really know how to do this, ask a friend!! 🙂
Step three again.. Enter the security settings. When entering the security settings and providing something more than blank, you will be prompted with the credentials first time you create a connection to the connector.
I broke the URL down further with the “api_key” as a query, so that it would show in the URL like the example on the first picture.
Step four.. Create a search tag like the one I had in the URL from the first picture
Step five.. Get the URL from the first picture with your API key, and add this to the import sample
Choose the GET in this case, and add the full URL
Your request should look something like this:
Step 6.. Add a connection to the connector and test with a tag. It should return some info like this:
Result
When you are done, you have a custom connector you can reuse from Power Apps, Flow or any other tool that can use custom connectors.
Connector Gallery 🌌
What better thing to do than release this to the https://connector.gallery when you are done creating a new connector?? :😁💪🥇
By now I hope most people know the https://pcf.gallery (run by Guido Preite). A great page for sharing community components (PCF) and exposing awesome contributions to the rest of the world. 🌎
What I like about the PCF Gallery is the simplicity of the site only being about PCF components. This is why I asked Guido if we could create a similar site for other components regarding the Power Platform. He was so kind to share his code for the project, so Matt Beard and I decided to give it a go. 🤗
Connector Gallery
First out in list of future galleries is the CONNECTOR gallery . This site will contain all sorts of custom connectors for Power Platform that you can share with the community. If you want to contribute to this gallery, you only have to share the custom connector file you have on GitHub, and we will post it out!
Launching a new app or launching a new CRM system always leaves the users with the same question. Where do I find the application? At first I didn’t really understand the question, because I thought it was natural to bookmark the URL to your application ie https://www.company.crm4.dynamics.com/***** etc.
Eventually I realized that most users are actually using the waffle menu in office 365 when navigating to applications that they don’t use continuously.
They were expecting to see the application in the list when you clicked the waffle menu, because this would save them time.
Luckily this is not a problem 😊 Open the all apps, and locate the app you are looking for
And just like that you now have a quick navigation to your CRM or Power App application in the Microsoft 365 app launcher👊
My last post described the ACDC hackathon and what it’s all about, but this post is what our company ended up delivering for the Arctic Cloud Developer Challenge after 2 1/2 days of pure geeking 💪
Meet the Team
Area: Microsoft 365, SharePoint, Developer, Power Apps
Areas: Dynamics 365, Power Apps, Developer,
Areas: Microsoft 365, Azure, Developer
Areas: Power BI, Data Platform, Power Apps
Areas: Dynamics 365, Power Apps, Power Platform
Welcome to LEGO CITY
Our idea was to create an interconnected city with bleeding edge technology for monitoring the status quo of the citizens safety. The City is built next to a mountain that recently has been showing signs of activity. Geologist say that it could blow at any time. Luckily the city has invested heavily in technology that could help them save lives ❤
The city has a train track surrounding a lake. The Train track is crucial for transporting the LEGO’s around, and providing transportation for factories producing parts. In the city you have a Mayor’s office, LEGO factory, houses, and THE MOUNTAIN OF DOOM!! 🔥 Based on this drawing, or mission was to create the technology needed to make the city a safe place to live.
On the day of the event we started building right away, and this is what we created within a few hours😅
But since this is a technical blog, I will get into the makings of the Connected Lego City details, that made this project on of the coolest city concepts I have seen in a while!
The technology
Mountain of DOOM!!🔥
Let’s start at the top near themountain. We placed 2 IOT sensors for monitoring temperature, and movement. We used the Azure IOT dev kit sensors for this purpose. Both IOT sensors were pushing data to Azure IOT hub, and then over to Stream Analytics. The constant changes were reported to the Majors office. The impressive part here was
Train Track Switch
On the top left we connected an Arduino device with a servo Switch connected. This was used to change the train track from long track, to short track.
By sending a boolean to the device, it would mechanically change the trains direction. You can barely see the device hidden beneath the track with a wire for power under the blue “water”. To see it in action, just watch the video on top.
Majors Office – Command Central
In the bottom left we had the majors office (aka command central), where the major could minor all thigs happening in his city. This is where we were looking at the output from the city sensors, and reporting via Stream Analytics to Power BI.
We included Dynamcis 365 information on the left to give a status on all ongoing city work orders (fixing problems), and on the right side we had live data from the mountain. One of the charts were showing the constant temperature, and others were measuring movement. Below we connected to the Norwegian weather API, so that we could understand what potential conditions would effect our emergency response the next days.
Train conductor – remote worker
During these Corona times we wanted to give the Train Conductor the possibility to work from home. Therefore we mounted a camera on the train, and connected it to a Raspberry PI. The Raspberry PI was also running a piece of software that could control the USB part of the LEGO Boost. For this we combined projects from: 1: https://motion-project.github.io/motion_config.html 2: https://github.com/virantha/bricknil
We also created a webserver running the live feed of the camera with the controls. The conductor could then log in and power the train in any direction needed 🚆🚂
Citizen Self Service
When there was an issue in the City, the citizens could report this via porta to Dynamics Customer Service. We connected with The Portal Connector for this scenario.
Submitting the case would deliver the case to Dynamics 365 Customer Service, where we used a few PCF components from pcf.gallery for picture rendering in CRM.
LEGO Factory – Field Service
Once the case had been evaluated, we would create a work order for booking our trusted technician for the job. For this case we used Field Service OOTB, and the technician would used the new mobile app for service delivery. We also connected the warehouse for picking parts from the factory based on the initial pictures that the technician would have seen.
Payment – Vipps
The technician fixed the broken houses, he would then send an invoice via the Norwegian payment service Vipps. The awesome thing about this was that it was all done by using a Power Automate Flow for the job! Once the Work Order was complete, we simply created a payment for the Vipps API, and received our money.
Crisis team
If the IOT sensors detected crisis, they would start a flow that the mayor would have to approve.
From this flow we would also trigger sending of SMS notification to the citizens that were in dataverse.