0
votes

I am trying to send multiple asyncronous xmlhttprequest's using the oData endpoint. Some of them are creating Order details and are updating Order details in Microsoft Dynamics CRM 2013.

If I use the developer tools and manually trace through the code it works fine. However, if I run it from my web resource I constantly get 500 responses from the server. Some of the requests complete correctly, while the others fail.

I am looking for a purely javascript solution. I have tried Googling it and looking at multiple posts on stackoverflow but to no avail. I have used Fiddler2 but the response text is 'Generic SQL Error'. If I run the request again in the composer, it works just fine. Could it be a db locking issue?

Thanks in advance and I can provide more info if need be.

Here is my code with the for-loop:

var updateDetails = function (data) {
    var table = document.getElementById("selectedItemTable");
    var tbody = table.getElementsByTagName("tbody")[0];
    var upsaleQty, qty;
    var salesOrderDetailId;

    for (var i = 0; i < tbody.childElementCount; i++) {
        var prodName = tbody.rows[i].cells[0].innerHTML;
        var match = false;

        for (var j = 0; j < data.length; j++) {
            if (prodName === data[j].product_order_details.tf_ShortName) {
                match = true;
                upsaleQty = data[j].tf_UpsaleQty ? parseFloat(data[j].tf_UpsaleQty) : 0;
                qty = parseFloat(data[j].Quantity) + parseFloat(tbody.rows[i].cells[1].innerHTML);
                salesOrderDetailId = data[j].SalesOrderDetailId;
            }
        }

        if (!match) {
            var productQuery = odataBaseUrl + "/ProductSet?$filter=tf_ShortName eq '" + prodName + "'&$select=Name,tf_ShortName,ProductId,DefaultUoMId";
            performRequest(productQuery, createDetail);
        } else {
            upsaleQty = upsaleQty + parseFloat(tbody.rows[i].cells[1].innerHTML);

            // Update Order Detail
            var updateObj = {};
            updateObj.tf_UpsaleQty = upsaleQty.toFixed(5);
            updateObj.Quantity = qty.toFixed(5);

            var updateDetail = JSON.stringify(updateObj);

            console.dir("Update " + prodName + ":" + updateDetail);

            createUpdateDetail(true, salesOrderDetailId, updateDetail);
        }
    }

    makePdf();
    document.getElementById("save").style.visibility = "hidden";
}

Here is the code that sends the create/update request:

var createUpdateDetail = function (update, orderDetailGuid, json) {
    var odataReq = odataBaseUrl + "/SalesOrderDetailSet";

    if (update) {
        odataReq += "(guid'" + orderDetailGuid + "')";
    }

    var oReq = getXMLHttpRequest();

    if (oReq != null) {
        oReq.open("POST", encodeURI(odataReq), true);
        oReq.setRequestHeader("Accept", "application/json");
        oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");

        if (update) {
            oReq.setRequestHeader("X-HTTP-Method", "MERGE");
        }

        oReq.send(json);
    } else {
        alert('Error in creating request.');
    }
}

Here is the perform request function:

var performRequest = function (odataUrl, onReadyFunction, concatResults) {
    console.dir(odataUrl);

    var oReq = getXMLHttpRequest();
    if (oReq != null) {
        oReq.open("GET", encodeURI(odataUrl), true);
        oReq.setRequestHeader("Accept", "application/json");
        oReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        oReq.onreadystatechange = function () {
            if (oReq.readyState == 4 && oReq.status == 200) {
                // Parse the result

                if (!concatResults) {
                    concatResults = new Object();
                    concatResults.results = new Array();
                }

                oReq.onreadystatechange = null; //avoids memory leaks
                console.dir(oReq.responseText);
                var result = window.JSON.parse(oReq.responseText).d;

                for (var i = 0; i < result.results.length; i++) {
                    concatResults.results.push(result.results[i])
                }

                if (result.__next != null)
                    performRequest(decodeURI(result.__next), onReadyFunction, concatResults);
                else
                    onReadyFunction(concatResults.results);
            }
        };
        oReq.send();
    } else {
        alert('Error in creating request.');
    }

}

Create Detail function:

var createDetail = function (data) {
    // Create Order Detail
    var table = document.getElementById("selectedItemTable");
    var tbody = table.getElementsByTagName("tbody")[0];
    var qty = 0;

    for (var i = 0; i < tbody.childElementCount; i++) {
        if (data[0].tf_ShortName === tbody.rows[i].cells[0].innerHTML) {
            qty = parseFloat(tbody.rows[i].cells[1].innerHTML).toFixed(5);
        }
    }

    var createObj = {};
    createObj.SalesOrderId = { Id: orderGuid, LogicalName: "salesorder" };
    createObj.ProductId = { Id: data[0].ProductId, LogicalName: "product" };
    createObj.Quantity = qty;
    createObj.tf_UpsaleQty = qty;
    createObj.UoMId = { Id: data[0].DefaultUoMId.Id, LogicalName: data[0].DefaultUoMId.LogicalName };
    var createDet = JSON.stringify(createObj);

    console.dir("Create:" + createDet);

    createUpdateDetail(false, "", createDet);
}
2

2 Answers

1
votes

I think ExecuteMultipleRequest to SOAP endpoint it's your solution. As a result you get only one service call instead making multiple service call which is currently implemented in your solution.

In case you avoid generating request string to soap endpoint in your code I would like to recommend you this JS library.

0
votes

I ended up creating an array and treated it like a queue. I put all of the odata requests to create and update the Order Details in the array and then processed them sequentially. The onreadystatechange would trigger the next request. Granted, it's not as efficient as running the processed in parallel, but it worked for my needs and resolved the 500 errors. Thanks for your help.