Sélectionner une page

Implémentation pas à pas (exemple complet)

Objectif : créer une API personnalisée CalculateOpportunityMargin qui calcule la marge d’une opportunité à partir du montant, du coût et d’options de remise.

Pré requis

  • Rôle avec droits de personnalisation Dataverse.
  • Solution non gérée dédiée (ex. Marlk_SalesCore).
  • SDK et Plugin Registration Tool installés.
  • Projet C# .NET 6+ avec Microsoft.CrmSdk.CoreAssemblies.

Définir l’API dans la solution

  1. Dans Power Apps > Solutions, ouvrir Marlk_SalesCore.
  2. Nouvel élément > API personnalisée.
  3. Paramètres principaux :
    • Nom logique: mar_custom_CalculateOpportunityMargin
    • Display name: Calculate Opportunity Margin
    • Binding type: Global
    • Execution mode: Synchronous
    • Allowed custom processing step type: SyncOnly
    • Is Function: false (action)
  4. Paramètres d’entrée :
    • opportunityid (Guid, Required)
    • applydiscount (Boolean, Optional)
  5. Paramètres de sortie :
    • marginamount (Money)
    • marginrate (Decimal)
  6. Enregistrer.

Implémenter la logique métier (plug-in handler)

Créer une classe C# qui lit l’opportunité, calcule la marge, et alimente la réponse.

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

public class CalculateOpportunityMarginHandler : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        var service = factory.CreateOrganizationService(context.UserId);

        // Lecture des paramètres d’entrée
        var input = context.InputParameters;
        if (!input.Contains("opportunityid"))
            throw new InvalidPluginExecutionException("opportunityid is required");

        var oppId = (Guid)input["opportunityid"];
        var applyDiscount = input.Contains("applydiscount") && (bool)input["applydiscount"];

        // Récupère l’opportunité
        var cols = new ColumnSet("totalamount", "new_totalcost", "discountpercentage");
        var opp = service.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 = revenue * (1 - (discountPct / 100m));

        if (revenue < 0 || cost < 0)
            throw new InvalidPluginExecutionException("Invalid revenue/cost values");

        var margin = revenue - cost;
        var rate = revenue == 0 ? 0 : margin / revenue;

        // Sorties
        context.OutputParameters["marginamount"] = new Money(margin);
        context.OutputParameters["marginrate"] = rate;
    }
}

Bonnes pratiques implémentées : validation stricte des entrées, sélection minimale de colonnes, erreurs explicites.

Enregistrer le handler sur l’API

  1. Compiler l’assembly. Versionner (ex. 1.0.0.0).
  2. Ouvrir Plugin Registration Tool > se connecter.
  3. Register > Register New Assembly > sélectionner le DLL.
  4. Add Step > cibler le Message = mar_custom_CalculateOpportunityMargin (Custom API) > Stage = PostOperation > Synchronous.
  5. Enregistrer.

Tester avec Postman

  1. Authentification OAuth 2.0 sur l’API Dataverse.
  2. Requête POST :
POST https://<org>.crm.dynamics.com/api/data/v9.2/mar_custom_CalculateOpportunityMargin
Content-Type: application/json

{
  "opportunityid": "GUID-OPP",
  "applydiscount": true
}
  1. Réponse attendue :
{
  "marginamount": 1250.0,
  "marginrate": 0.22
}

Tester avec Power Automate

  1. Créer un cloud flow instantané.
  2. Étape HTTP with Dataverse ou Action personnalisée > sélectionner Calculate Opportunity Margin.
  3. Fournir opportunityid, applydiscount.
  4. Ajouter un Compose pour afficher marginamount, marginrate.

Sécurité et gouvernance

  • Créer un rôle de sécurité spécifique autorisant l’exécution de l’API.
  • Journaliser via Plug-in Trace Log et exporter vers Application Insights si nécessaire.
  • Noms et schéma : préfixe d’éditeur Marlk_, noms logiques en anglais, affichage localisé.

Check-list de validation

  • L’API est dans une solution avec dépendances résolues.
  • Les paramètres sont typés et documentés.
  • Le handler gère les erreurs et retourne des messages clairs.
  • Les tests Postman et Power Automate passent.
  • Les droits de sécurité sont en place.
  • Traçabilité activée et contrôlée.

Industrialisation (extrait pipeline)

  • pac solution pack pour générer les artefacts.
  • Power Platform Build Tools: Export Solution (unmanaged) > tests > Import Solution (managed) en recette.
  • Gate qualité : règles statiques (StyleCop), tests unitaires sur la logique C# (calcul marge), tests d’intégration via flows.

Ce parcours donne un flux bout en bout reproductible, du design à l’appel API, prêt pour l’ALM et l’audit.