Exemple d’implémentation et appel depuis Power Automate
Objectif : finaliser CalculateOpportunityMargin et démontrer son appel depuis Power Automate et Power Apps.
Classe C# (handler) complète
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
namespace Marlk.SalesCore.Plugins
{
public class CalculateOpportunityMarginHandler : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var ctx = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var org = factory.CreateOrganizationService(ctx.UserId);
var input = ctx.InputParameters;
if (!input.Contains("opportunityid"))
throw new InvalidPluginExecutionException("Missing parameter: opportunityid");
var oppId = (Guid)input["opportunityid"];
var applyDiscount = input.Contains("applydiscount") && (bool)input["applydiscount"];
var cols = new ColumnSet("totalamount", "new_totalcost", "discountpercentage");
var opp = org.Retrieve("opportunity", oppId, cols);
var revenue = opp.GetAttributeValue<Money>("totalamount")?.Value ?? 0m;
var cost = opp.GetAttributeValue<Money>("new_totalcost")?.Value ?? 0m;
var discountPct = opp.Contains("discountpercentage") ? (decimal)opp["discountpercentage"] : 0m;
if (applyDiscount && discountPct > 0) revenue *= (1 - discountPct / 100m);
if (revenue < 0 || cost < 0) throw new InvalidPluginExecutionException("Invalid revenue/cost values");
var margin = revenue - cost;
var rate = revenue == 0 ? 0m : margin / revenue;
ctx.OutputParameters["marginamount"] = new Money(margin);
ctx.OutputParameters["marginrate"] = rate;
}
}
}
Points clés :
- Paramètres nominaux
opportunityid,applydiscount. - Sélection minimale de colonnes.
- Gestion d’erreurs explicite.
Enregistrement du handler
- Assembly
Marlk.SalesCore.Plugins.dll. - Step : Message =
mar_custom_CalculateOpportunityMargin, Stage =PostOperation, Mode =Synchronous. - Isolation =
Sandbox.
Appel via Power Automate (cloud flow)
- Déclencheur : Manually trigger a flow ou When a row is added, modified or deleted (opportunity).
- Action Dataverse : Perform an unbound action (ou Call custom action).
- Action name :
mar_custom_CalculateOpportunityMargin. - Body :
- Action name :
{
"opportunityid": "@{triggerOutputs()?['body/opportunityid']}",
"applydiscount": true
}
- Lire la sortie : utiliser Compose pour
outputs('Call_custom_action')?['body/marginamount']et...['body/marginrate']. - Conditionnel : si
marginrate < 0.1, envoyer un e-mail d’alerte ou mettre à jour un champ calculé.
Appel depuis Power Apps (canvas app)
- Ajouter le connecteur Dataverse.
- Appeler l’action via
Dataverse.ExecuteCustomAPI(...)(ou un connecteur personnalisé si nécessaire). - Exemple (pseudo-formule) :
Set(result, Dataverse.ExecuteCustomAPI(
"mar_custom_CalculateOpportunityMargin",
{ opportunityid: GUID(TextInputOppId.Text), applydiscount: true }
));
Notify($"Margin: {result.marginamount} ({Text(result.marginrate, "0.00%")})");
Tests et validation
- Postman : vérifier le schéma et les codes HTTP.
- Power Automate : tester avec données réelles et comparer à un calcul Excel de référence.
- Traçabilité : Plug-in Trace Log sur Exception et Verbose en recette.
Checklist de production
- Solution managed en prod.
- Rôles de sécurité spécifiques à l’action.
- Observabilité : tableaux de bord Application Insights (exceptions, latence, taux d’échec).
- Documentation : contrat API, paramètres, exemples d’appels.
Livrable : API opérationnelle, appelable par flux et apps, gouvernée et observable.