Technique7 min de lecture

Rapport SSRS personnalisé D365 F&O : classes RDP et Contract

Créer un état SSRS dans D365 F&O : table temporaire, classe Contract, classe RDP, controller et menu. Étapes, code X++ d'exemple et erreurs fréquentes.

La réponse courte

Un rapport SSRS personnalisé dans Dynamics 365 Finance & Operations repose sur quatre objets : une table temporaire qui porte le jeu de données, une classe Contract qui définit les paramètres saisis par l'utilisateur, une classe RDP (Report Data Provider) qui remplit la table temporaire en X++, et le rapport lui-même, dont le dataset pointe vers la classe RDP. Un controller et un élément de menu de sortie complètent le tout pour lancer l'état depuis l'application.

Pour modifier un état standard, la logique est différente : on ne peut pas étendre directement une classe RDP. On ajoute des champs par extension de la table temporaire, on les alimente par un gestionnaire d'événement et on redirige le menu vers un design personnalisé.

Étape 1 : la table temporaire et la classe Contract

Créez une table (ici MyCustBalanceTmp) avec la propriété TableType à TempDB et les champs que l'état affichera. Microsoft recommande TempDB pour les états qui traitent beaucoup de données (voir l'étape 4).

La classe Contract porte les paramètres. Chaque paramètre est une méthode parm décorée avec DataMemberAttribute ; la classe porte DataContractAttribute. Le framework construit automatiquement la boîte de dialogue à partir de ces membres.

[DataContractAttribute]
class MyCustBalanceContract
{
    CustGroupId custGroupId;

    [DataMemberAttribute('CustGroupId')]
    public CustGroupId parmCustGroupId(CustGroupId _custGroupId = custGroupId)
    {
        custGroupId = _custGroupId;
        return custGroupId;
    }
}

Étape 2 : la classe RDP

La classe RDP hérite de SrsReportDataProviderBase. L'attribut SRSReportParameterAttribute la relie à la classe Contract ; une méthode décorée avec SRSReportDataSetAttribute renvoie la table temporaire au serveur de rapports ; la logique métier va dans processReport, appelée à l'exécution. Si l'état part d'une requête AOT modifiable par l'utilisateur, ajoutez SRSReportQueryAttribute et lisez-la avec parmQuery().

[SRSReportParameterAttribute(classStr(MyCustBalanceContract))]
class MyCustBalanceDP extends SrsReportDataProviderBase
{
    MyCustBalanceTmp custBalanceTmp;

    [SRSReportDataSetAttribute(tableStr(MyCustBalanceTmp))]
    public MyCustBalanceTmp getMyCustBalanceTmp()
    {
        select custBalanceTmp;
        return custBalanceTmp;
    }

    public void processReport()
    {
        MyCustBalanceContract contract = this.parmDataContract() as MyCustBalanceContract;
        CustGroupId           custGroupId = contract.parmCustGroupId();
        CustTable             custTable;

        while select custTable
            where custTable.CustGroup == custGroupId
        {
            custBalanceTmp.clear();
            custBalanceTmp.AccountNum = custTable.AccountNum;
            custBalanceTmp.Balance    = custTable.balanceMST();
            custBalanceTmp.insert();
        }
    }
}

Ici, balanceMST() est appelé ligne à ligne : acceptable pour un groupe de clients, à éviter sur des volumes importants. Préférez alors des opérations ensemblistes (insert_recordset) ou un calcul en requête.

Étape 3 : le rapport, le controller et le menu

  1. Dans Visual Studio, ajoutez un rapport au projet (ici MyCustBalance). Créez un dataset, choisissez le type de source « Report Data Provider » et sélectionnez MyCustBalanceDP : les champs de la table temporaire et les paramètres du Contract apparaissent.
  2. Dessinez le design (ici « Report ») : design automatique pour un état simple, design de précision pour un document mis en page.
  3. Ajoutez un controller si vous devez préparer les arguments ou choisir le design à l'exécution. Le modèle ci-dessous suit l'exemple de Microsoft Learn.
  4. Créez un élément de menu de sortie qui pointe vers le controller (ou directement vers le rapport), ajoutez-le à un privilège, puis déployez le rapport.
class MyCustBalanceController extends SrsReportRunController
{
    public static void main(Args _args)
    {
        MyCustBalanceController controller = new MyCustBalanceController();
        controller.parmReportName(ssrsReportStr(MyCustBalance, Report));
        controller.parmArgs(_args);
        controller.startOperation();
    }
}

Étape 4 : les états longs et la modification d'un état standard

Les connexions interactives sont limitées à 10 minutes. Pour un état qui peut dépasser ce délai, Microsoft Learn décrit la bascule vers un traitement préalable : remplacer SrsReportDataProviderBase par SrsReportDataProviderPreProcessTempDB, passer la table en TempDB, recompiler la classe RDP, restaurer le dataset dans le designer, redéployer, puis faire pointer l'élément de menu vers un controller. Le traitement par lots est l'autre levier.

Pour enrichir un état standard sans over-layering, Learn décrit deux méthodes : un post-handler sur processReport de la classe RDP (mise à jour en masse de la table temporaire, une seule fois) ou un gestionnaire d'événement Inserting sur la table temporaire (calcul ligne à ligne). On duplique le rapport dans son modèle, on restaure le dataset et on redirige l'utilisateur par un PostHandler sur la méthode construct du controller standard.

Erreurs fréquentes

  • Oublier de restaurer le dataset après avoir ajouté un champ à la table temporaire : la colonne n'apparaît pas dans le designer.
  • Lire le contrat sans transtypage vers la bonne classe : utilisez this.parmDataContract() as MaClasseContract.
  • Laisser la table en InMemory pour un gros volume : passez en TempDB.
  • Appeler des méthodes coûteuses ligne à ligne dans processReport sur des milliers d'enregistrements.
  • Oublier le privilège sur l'élément de menu : l'état est déployé mais invisible pour les utilisateurs.
  • Modifier un état standard par over-layering au lieu des gestionnaires d'événements : cela bloque les mises à jour.

Faire générer l'état plutôt que l'écrire

Ce schéma table, Contract, RDP, controller est répétitif : c'est précisément le type de développement que Skalp AI génère à partir de votre besoin. Skalp analyse le contexte ERP, rédige la spécification, produit le code X++ et les tests unitaires, puis livre sur votre Azure DevOps pour validation par votre DSI. Détails et exemples d'états : état SSRS personnalisé D365 F&O. Pour savoir ce que l'IA fait bien ou non en X++ : développer en X++ sans consultant en 2026. Tarifs : offres Basic, Pro et Max, 1 crédit (≈ 400 € en Basic, 200 € en Pro, dégressif) consommé seulement à la génération du code.

Sources

Questions fréquentes

SSRS ou Power BI pour un état D365 F&O ?

SSRS pour les documents mis en page à imprimer ou envoyer (facture, bon, état réglementaire), avec gestion documentaire, envoi par e-mail et exécution planifiée en batch. Power BI pour l'analyse interactive. Voir aussi rapports Power BI D365 F&O.

Peut-on étendre une classe RDP standard ?

Pas directement. Microsoft Learn indique d'utiliser un post-handler sur processReport ou un événement Inserting sur la table temporaire, combinés à une extension de cette table.

Pourquoi mon état SSRS expire-t-il ?

Les connexions interactives sont limitées à 10 minutes. Passez la classe RDP sur SrsReportDataProviderPreProcessTempDB avec une table TempDB et un controller, ou exécutez l'état en batch.

Prêt à transformer votre D365 ?

Rejoignez les DSI qui développent leurs tickets D365 en 1h pour 1 crédit (≈ 400 € en Basic, 200 € en Pro).