Skip to main content

Notifications

Announcements

No record found.

Customer experience | Sales, Customer Insights,...
Suggested answer

open record after its line items have been created via web api

Posted on by 75

hi I have some javascript code which is used to take contract pieces of information and items and create an invoice with those very items.

Though I am not quite sure whether this approach is the best for creating a new record from one entity into another.

My code:

    var currentYear = new Date().getFullYear();
    var currentStart = new Date(currentYear, 0, 1);
    //currentStart.setHours(0,0,0,0);
    var currentEnd = new Date(currentYear, 11, 31);
    //currentEnd.setHours(0,0,0,0);
function start() {
  var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37); 
    var fetchxml = `














   










`;

    var encodedFetchXML = encodeURIComponent(fetchxml);
    var queryPath = "/api/data/v8.2/contractdetails?fetchXml="   encodedFetchXML;
    var requestPath = parent.Xrm.Page.context.getClientUrl()   queryPath;

    var req = new XMLHttpRequest();
    req.open("GET", requestPath, true);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.onreadystatechange = function ()

    {

        if (this.readyState === 4)

        {

            this.onreadystatechange = null;
            if (this.status === 200)

            {
                var returned = JSON.parse(this.responseText);
                var results = returned.value;
                
                getContractInfo(results);
            } else

            {

                alert(this.statusText);

            }

        }

    };

    req.send();
}

function test(data, newInvoiceID) {
    var data = data;
    var ID = newInvoiceID;

    for (var i = 0; i < data.length; i  ) {
        var existingProduct = data[i];
        
       if(Date.parse(existingProduct.activeon) < Date.parse(currentStart)) {
           
           if(Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
               var lineitem = {};
        lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
        lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
        lineitem["new_contractactiveon"] = currentStart;
        lineitem["new_contractexpireson"] = currentEnd;
        lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
        lineitem.quantity = existingProduct.initialquantity;
        lineitem["invoiceid@odata.bind"] = "/invoices("  ID  ")";
        lineitem["manualdiscountamount"] = existingProduct.discount;
        test3(lineitem, ID);
           }
           
           if(Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
               var lineitem = {};
        lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
        lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
        lineitem["new_contractactiveon"] = currentStart;
        lineitem["new_contractexpireson"] = existingProduct.expireson;
        lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
        lineitem.quantity = existingProduct.initialquantity;
        lineitem["invoiceid@odata.bind"] = "/invoices("  ID  ")";
        test3(lineitem, ID);
           }
           
       } else if(Date.parse(existingProduct.activeon) > Date.parse(currentStart)) {
           
           if(Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
                var lineitem = {};
        lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
        lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
        lineitem["new_contractactiveon"] = existingProduct.activeon;
        lineitem["new_contractexpireson"] = currentEnd;
        lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
        lineitem.quantity = existingProduct.initialquantity;
        lineitem["invoiceid@odata.bind"] = "/invoices("  ID  ")";
        lineitem["manualdiscountamount"] = existingProduct.discount;
        test3(lineitem, ID);
           }
           
           if(Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
                var lineitem = {};
        lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
        lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
        lineitem["new_contractactiveon"] = existingProduct.activeon;
        lineitem["new_contractexpireson"] = existingProduct.expireson;
        lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
        lineitem.quantity = existingProduct.initialquantity;
        lineitem["invoiceid@odata.bind"] = "/invoices("  ID  ")";
        test3(lineitem, ID);
           }
           
       }
            
            
            
        
        }
    }         

function test3(data, invoiceID) {
    var req = new XMLHttpRequest();
req.open("POST", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/invoicedetails", false);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.onreadystatechange = function() {
    if (this.readyState === 4) {
        req.onreadystatechange = null;
        if (this.status === 204) {
            var uri = this.getResponseHeader("OData-EntityId");
            var regExp = /\(([^)] )\)/;
            var matches = regExp.exec(uri);
            var newEntityId = matches[1];
        } else {
            parent.Xrm.Utility.alertDialog(this.statusText);
        }
    }
};
req.send(JSON.stringify(data));
setTimeout(50000, Xrm.Utility.openEntityForm("invoice", invoiceID).then(
    function (success) {
        console.log(success);
    },
    function (error) {
        console.log(error);
    }));
}



//info from contract that is going to be used in the invoice
function getContractInfo(data) {
    var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37);

    var req = new XMLHttpRequest();
    req.open("GET", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/contracts("   ID   ")?$select=activeon,_customerid_value,expireson,_serviceaddress_value,title&$expand=contract_line_items($select=activeon,expireson,initialquantity,price,title,new_thisstart, new_thisend)", true);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                var result = JSON.parse(this.response);
                var activeon = result["new_thisstart"];
                var _customerid_value = result["_customerid_value"];
                var expireson = result["new_thisend"];
                var title = result["title"];

                createInvoice(_customerid_value, title, data, activeon, expireson, ID);
            } else {
                parent.Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send();
}
//create the invoice
function createInvoice(customer, title, data, activeon, expireson, contractID) {

    var entity = {};
    entity["customerid_account@odata.bind"] = "/accounts("   customer   ")";
    entity["pricelevelid@odata.bind"] = "/pricelevels(be2084c3-1e50-eb11-bc99-00155db20709)";
    entity.name = title;
    entity["transactioncurrencyid@odata.bind"] = "/transactioncurrencies(59f3fa86-385a-ea11-bc6a-00155db20709)";
    entity["new_VertragId@odata.bind"] = "/contracts(" contractID ")";
    entity.new_contractactiveon = activeon;
    entity.new_contractexpireson = expireson;

    var req = new XMLHttpRequest();
    req.open("POST", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/invoices", true);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.onreadystatechange = function () {
        if (this.readyState === 4) {
            req.onreadystatechange = null;
            if (this.status === 204) {
                var uri = this.getResponseHeader("OData-EntityId");
                var regExp = /\(([^)] )\)/;
                var matches = regExp.exec(uri);
                var newEntityId = matches[1];
                var invoiceID = this.getResponseHeader("OData-EntityId").substring(67,103); 
                test(data, invoiceID);

                
                
            } else {
                parent.Xrm.Utility.alertDialog(this.statusText);
            }
        }
    };
    req.send(JSON.stringify(entity));

}





I believe this part is at fault here:

setTimeout(50000, Xrm.Utility.openEntityForm("invoice", invoiceID).then(
function (success) {
console.log(success);
},
function (error) {
console.log(error);
}));

I'd like to open my freshly created invoice record after all of its line items are created. As of now line item creation is incomplete and yet it jumps to the record

I would appreciate your feedback and solutions as I am not too well-versed in coding. Overall improvements to my code would be very welcome as well :)

  • Suggested answer
    Pradeep Rai Profile Picture
    Pradeep Rai 5,490 Super User 2024 Season 2 on at
    RE: open record after its line items have been created via web api

    Hi MusterMax,

    Yes, I have one suggestion instead of managing everything on client side.

    We can move some logic in Plugin side as below:

    1. We will create one custom action

    2. On custom action we will register one plugin

    3. The plugin is responsible for performing all business logic which you have done in script.

    4. Now, in plugin we will set output parameter. In this output parameter we set record Id which we need to open.

    5. Now in our script we will call the custom. This point will trigger the plugin.

    Overview:

    Script-> Custom Script code to call custom action-> upon action call, plugin will be triggered->

    Plugin  logic executed -> recordId will be found in success call in script code.

    Now. we can open the newly created record using script method.

    Thanks,

    Pradeep.

    Please mark this as VERIFIED if it helps.

  • MusterMax Profile Picture
    MusterMax 75 on at
    RE: open record after its line items have been created via web api

    Hello Pradeep Rai,

    i tried your solution but unfortuantely it did not work for me

    Do you have any other ideas perhaps?

    Kindly

    MusterMax

  • Suggested answer
    Pradeep Rai Profile Picture
    Pradeep Rai 5,490 Super User 2024 Season 2 on at
    RE: open record after its line items have been created via web api

    Hi,

    Yes, we can use the David Yack library.

    But i have update your code please check below code:

    var currentYear = new Date().getFullYear();
    var currentStart = new Date(currentYear, 0, 1);
    //currentStart.setHours(0,0,0,0);
    var currentEnd = new Date(currentYear, 11, 31);
    //currentEnd.setHours(0,0,0,0);
    function start() {
        var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37);
        var fetchxml = `
    
    
    
    
    
    
    
    
    
    
    
    
    
    
       
    
    
    
    
    
    
    
    
    
    
    `;
    
        var encodedFetchXML = encodeURIComponent(fetchxml);
        var queryPath = "/api/data/v8.2/contractdetails?fetchXml="   encodedFetchXML;
        var requestPath = parent.Xrm.Page.context.getClientUrl()   queryPath;
    
        var req = new XMLHttpRequest();
        req.open("GET", requestPath, true);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
        req.onreadystatechange = function () {
    
            if (this.readyState === 4) {
    
                this.onreadystatechange = null;
                if (this.status === 200) {
                    var returned = JSON.parse(this.responseText);
                    var results = returned.value;
    
                    getContractInfo(results);
                } else {
    
                    alert(this.statusText);
    
                }
    
            }
    
        };
    
        req.send();
    }
    
    function test(data, newInvoiceID) {
        var data = data;
        var ID = newInvoiceID;
    
        for (var i = 0; i < data.length; i  ) {
            var existingProduct = data[i];
            var lineitem = {};
            lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
            lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
            lineitem["new_contractactiveon"] = currentStart;
            lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
            lineitem["invoiceid@odata.bind"] = "/invoices("   ID   ")";
            lineitem.quantity = existingProduct.initialquantity;
            if (Date.parse(existingProduct.activeon) < Date.parse(currentStart)) {
    
                if (Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
                    lineitem["new_contractexpireson"] = currentEnd;
                    lineitem["manualdiscountamount"] = existingProduct.discount;
                }
    
                if (Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
                    var lineitem = {};
    
                    lineitem["new_contractexpireson"] = existingProduct.expireson;
    
                }
    
            } else if (Date.parse(existingProduct.activeon) > Date.parse(currentStart)) {
    
                if (Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
                    var lineitem = {};
                    lineitem["new_contractactiveon"] = existingProduct.activeon;
                    lineitem["new_contractexpireson"] = currentEnd;
                    lineitem["manualdiscountamount"] = existingProduct.discount;
                }
    
                if (Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
                    var lineitem = {};
                    lineitem["new_contractactiveon"] = existingProduct.activeon;
                    lineitem["new_contractexpireson"] = existingProduct.expireson;
                }
    
            }
            //API CALL
            var req = new XMLHttpRequest();
            req.open("POST", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/invoicedetails", false);
            req.setRequestHeader("OData-MaxVersion", "4.0");
            req.setRequestHeader("OData-Version", "4.0");
            req.setRequestHeader("Accept", "application/json");
            req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            req.onreadystatechange = function () {
                if (this.readyState === 4) {
                    req.onreadystatechange = null;
                    if (this.status === 204) {
                        var uri = this.getResponseHeader("OData-EntityId");
                        var regExp = /\(([^)] )\)/;
                        var matches = regExp.exec(uri);
                        var newEntityId = matches[1];
                        if (data.length == i) {
                            Xrm.Utility.openEntityForm("invoice", newInvoiceID).then(
                                function (success) {
                                    console.log(success);
                                },
                                function (error) {
                                    console.log(error);
                                })
                        }
                    } else {
                        parent.Xrm.Utility.alertDialog(this.statusText);
                    }
                }
            };
            req.send(JSON.stringify(lineitem));
          
        }
    }
    
    //info from contract that is going to be used in the invoice
    function getContractInfo(data) {
        var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37);
    
        var req = new XMLHttpRequest();
        req.open("GET", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/contracts("   ID   ")?$select=activeon,_customerid_value,expireson,_serviceaddress_value,title&$expand=contract_line_items($select=activeon,expireson,initialquantity,price,title,new_thisstart, new_thisend)", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 200) {
                    var result = JSON.parse(this.response);
                    var activeon = result["new_thisstart"];
                    var _customerid_value = result["_customerid_value"];
                    var expireson = result["new_thisend"];
                    var title = result["title"];
    
                    createInvoice(_customerid_value, title, data, activeon, expireson, ID);
                } else {
                    parent.Xrm.Utility.alertDialog(this.statusText);
                }
            }
        };
        req.send();
    }
    //create the invoice
    function createInvoice(customer, title, data, activeon, expireson, contractID) {
    
        var entity = {};
        entity["customerid_account@odata.bind"] = "/accounts("   customer   ")";
        entity["pricelevelid@odata.bind"] = "/pricelevels(be2084c3-1e50-eb11-bc99-00155db20709)";
        entity.name = title;
        entity["transactioncurrencyid@odata.bind"] = "/transactioncurrencies(59f3fa86-385a-ea11-bc6a-00155db20709)";
        entity["new_VertragId@odata.bind"] = "/contracts("   contractID   ")";
        entity.new_contractactiveon = activeon;
        entity.new_contractexpireson = expireson;
    
        var req = new XMLHttpRequest();
        req.open("POST", parent.Xrm.Page.context.getClientUrl()   "/api/data/v8.2/invoices", true);
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.onreadystatechange = function () {
            if (this.readyState === 4) {
                req.onreadystatechange = null;
                if (this.status === 204) {
                    var uri = this.getResponseHeader("OData-EntityId");
                    var regExp = /\(([^)] )\)/;
                    var matches = regExp.exec(uri);
                    var newEntityId = matches[1];
                    var invoiceID = this.getResponseHeader("OData-EntityId").substring(67, 103);
                    test(data, invoiceID);
    
    
    
                } else {
                    parent.Xrm.Utility.alertDialog(this.statusText);
                }
            }
        };
        req.send(JSON.stringify(entity));
    
    }

    Thanks,
    Pradeep.
    Please mark this as VERIFIED if it helps.

  • MusterMax Profile Picture
    MusterMax 75 on at
    RE: open record after its line items have been created via web api

    Hi, thank you for your reply! I forgot to mention we are on CRM 2016 (8.2) which does not have access to xrm.webapi unfortunately.

    Is there perhaps another way?

  • Suggested answer
    Pradeep Rai Profile Picture
    Pradeep Rai 5,490 Super User 2024 Season 2 on at
    RE: open record after its line items have been created via web api

    Hi,

    Please try below code:

    Code:

    var currentYear = new Date().getFullYear();
    var currentStart = new Date(currentYear, 0, 1);
    //currentStart.setHours(0,0,0,0);
    var currentEnd = new Date(currentYear, 11, 31);
    //currentEnd.setHours(0,0,0,0);
    function start() {
        var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37);
        var fetchxml = `
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        
                           
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        `;
    
        var updatedfetchXml = "?fetchXml="   fetchxml;
    
        Xrm.WebApi.retrieveMultipleRecords("contractdetail", updatedfetchXml).then(
            function success(result) {
                if (result != undefined &&
                    result.entities != undefined &&
                    result.entities.length > 0) {
                    getContractInfo(result.entities);
                }
            },
            function (error) {
                console.log(error.message);
                // handle error conditions
            }
        );
    }
    
    function test(data, newInvoiceID) {
        var data = data;
        var ID = newInvoiceID;
    
        for (var i = 0; i < data.length; i  ) {
            var existingProduct = data[i];
            var lineitem = {};
            lineitem["productid@odata.bind"] = "/products("   existingProduct._productid_value   ")";
            lineitem["uomid@odata.bind"] = "/uoms("   existingProduct._uomid_value   ")";
            lineitem["new_contractactiveon"] = currentStart;
            lineitem["new_ortfirma@odata.bind"] = "/accounts("   existingProduct._new_ortfirma_value   ")";
            lineitem["invoiceid@odata.bind"] = "/invoices("   ID   ")";
            lineitem.quantity = existingProduct.initialquantity;
            if (Date.parse(existingProduct.activeon) < Date.parse(currentStart)) {
    
                if (Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
                    lineitem["new_contractexpireson"] = currentEnd;
                    lineitem["manualdiscountamount"] = existingProduct.discount;
                }
    
                if (Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
                    var lineitem = {};
    
                    lineitem["new_contractexpireson"] = existingProduct.expireson;
    
                }
    
            } else if (Date.parse(existingProduct.activeon) > Date.parse(currentStart)) {
    
                if (Date.parse(existingProduct.expireson) > Date.parse(currentEnd)) {
                    var lineitem = {};
                    lineitem["new_contractactiveon"] = existingProduct.activeon;
                    lineitem["new_contractexpireson"] = currentEnd;
                    lineitem["manualdiscountamount"] = existingProduct.discount;
                }
    
                if (Date.parse(existingProduct.expireson) < Date.parse(currentEnd)) {
                    var lineitem = {};
                    lineitem["new_contractactiveon"] = existingProduct.activeon;
                    lineitem["new_contractexpireson"] = existingProduct.expireson;
                }
    
            }
    
            // create account record
            Xrm.WebApi.createRecord("invoicedetail", lineitem).then(
                function success(result) {
                    if (data.length == i  ) {
                        Xrm.Utility.openEntityForm("invoice", newInvoiceID).then(
                            function (success) {
                                console.log(success);
                            },
                            function (error) {
                                console.log(error);
                            })
                    }
                },
                function (error) {
                    console.log(error.message);
                    // handle error conditions
                }
            );
    
    
    
        }
    }
    
    //info from contract that is going to be used in the invoice
    function getContractInfo(data) {
        var ID = parent.Xrm.Page.data.entity.getId().substring(1, 37);
    
        Xrm.WebApi.retrieveRecord("contract", ID, "?$select=activeon,_customerid_value,expireson,_serviceaddress_value,title&$expand=contract_line_items($select=activeon,expireson,initialquantity,price,title,new_thisstart, new_thisend)").then(
            function success(result) {
                var activeon = result["new_thisstart"];
                var _customerid_value = result["_customerid_value"];
                var expireson = result["new_thisend"];
                var title = result["title"];
    
                createInvoice(_customerid_value, title, data, activeon, expireson, ID);
    
            },
            function (error) {
                console.log(error.message);
                // handle error conditions
            }
        );
    }
    //create the invoice
    function createInvoice(customer, title, data, activeon, expireson, contractID) {
    
        var entity = {};
        entity["customerid_account@odata.bind"] = "/accounts("   customer   ")";
        entity["pricelevelid@odata.bind"] = "/pricelevels(be2084c3-1e50-eb11-bc99-00155db20709)";
        entity.name = title;
        entity["transactioncurrencyid@odata.bind"] = "/transactioncurrencies(59f3fa86-385a-ea11-bc6a-00155db20709)";
        entity["new_VertragId@odata.bind"] = "/contracts("   contractID   ")";
        entity.new_contractactiveon = activeon;
        entity.new_contractexpireson = expireson;
    
    
    
        // create account record
        Xrm.WebApi.createRecord("invoice", entity).then(
            function success(result) {
                test(data, result.id);
            },
            function (error) {
                console.log(error.message);
                // handle error conditions
            }
        );
    }


    In above code i have removed the XmlHttpRequest with Xrm.webapi.

    In dynamics, whenever we want to perform CRUD operation then we can use the XRM.WEBAPI.

    Reference link:
    https://docs.microsoft.com/en-us/powerapps/developer/model-driven-apps/clientapi/reference/xrm-webapi/createrecord

    Thanks,
    Pradeep.
    Please mark this as VERIFIED if it helps.

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Tips for Writing Effective Suggested Answers

Best practices for providing successful forum answers ✍️

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,269 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,198 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans