Subversion Repositories munaweb

Rev

Rev 180 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<!DOCTYPE html>
<html lang="en">

<head>
    <title>eBay Listings Price Check</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
    <link rel="icon" href="favicon.ico" type="image/x-icon">

    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="js/XMLWriter.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.23.0/moment.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data-2012-2022.min.js"></script>
    <link rel="stylesheet" href="css/style.css">
    <script src="js/muna-tools.js"></script>
</head>

<body onload="return initConfig();">
    <div>
        <div>
            <div class="container-fluid bg-secondary">
                <div class="clearfix">
                    <img class="img-fluid float-right" src="images/MUNA%20-%20Logo%20100x100.png" alt="MUNA Trading Logo" />
                    <h1 id="connected">eBay Listings Price Check
                    <input id="login" type="button" class="btn bg-success mb-2 w3-hide" onclick="eBayLogin();" value="Login" /></h1>
                </div>
            </div>

            <div class="border col">
                <div>
                    <form id="searchForm" class="container-fluid bg-light" onsubmit="return checkListingPrices();">
                        <input id="startButton" type="button" class="btn btn-dark" onclick="checkListingPrices();" value="Start" />
                    </form>
                </div>
                <div class="modal" id="progressBarDiv">
                    <div class="modal-dialog">
                        <div class="modal-content">
                            <div class="modal-header">
                                <h4 id="progressBarHeader"></h4>
                            </div>
                            <div class="modal-body">
                                <div class="progress">
                                    <div id="progressBar" class="progress-bar" style="width:0%">0%</div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div id="results" class="border bg-info w3-hide"></div>
                <div id="logging"></div>
            </div>
        </div>

        <footer class="container-fluid text-center border border-bottom-0 border-left-0 border-right-0">
            <div w3-include-html="php/footer.php"></div>
        </footer>

    </div>

    <script>

// Config
var configMinPrice = "5.99";
var configDifference = 2.00;
var configPercentage = 20.00;
var configAbsoluteMinPrice = 5.00;
var configAdjMinPrice = 5.48;
var configSearchUrl = 'https://dev.munatrading.com/ebay/search.html?keyword=';
var configSearchUrlPart2 = '&hideDuplicateItems=on&locatedIn=WorldWide&sortOrder=PricePlusShippingLowest&results=100';

var pagesToProcess = 0;
var maxPagesToProcess = 0;
var pagesProcessed = 0;
var productIdsToProcess = 0;
var maxProductIdsToProcess = 0;
var productIdsProcessed = 0;
var productsToPrice = 0;
var maxProductsToPrice = 0;
var productsPriced = 0;
var html = [];
var eBaySearchCount = [];
var productPricesCount = [];

// Initialize Configuration Variables
function initConfig() {
    eBayAuthToken = readCookie();
    if (eBayAuthToken.length > 0) {
        connected();
    }

    if (eBayAuthTokenFlag === false) {
        var x = document.getElementById("login");
        if (x.className.indexOf("w3-show") == -1) {
            x.className += " w3-show";
        }
    }
}

function requireNewLogin() {
    // dummy
}

function checkListingPrices() {
    var x;

    document.getElementById("logging").innerHTML = '';

    x = document.getElementById("results");
    if (x.className.indexOf("w3-show") == -1) {
        x.className += " w3-show";
    }
    x.className = x.className.replace(" process-errors", "");
    x.innerHTML = '';

    initProgressBar('Retrieving Active Listings (1/3)');

    pagesToProcess = 1;
    maxPagesToProcess = 1;
    pagesProcessed = 0;
    eBaySearchCount = [];
    eBaySearchCount[1] = 0;
    eBaySearch(1);

    function checkpagesToProcess() {
        if (pagesToProcess > 0) {
            window.setTimeout(checkpagesToProcess, 250); // wait 100 milliseconds
        } else {
            findMissingProductIds();
        }
    }

    checkpagesToProcess();
}

// item filters for request
var filterarray = [];
var urlfilter = [];

// Fill the array of item filters from input form
function fillFilterArray() {
    filterarray = [];
    var obj = [];

    obj = {
        "name": "Seller",
        "value": configeBaySellerName,
        "paramName": "",
        "paramValue": ""
    };
    filterarray.push(obj);

    obj = {
        "name": "MinPrice",
        "value": Number(configMinPrice).toFixed(2),
        "paramName": "Currency",
        "paramValue": "USD"
    };
    filterarray.push(obj);

    obj = {
        "name": "ListingType",
        "value": "FixedPrice",
        "paramName": "",
        "paramValue": ""
    };
    filterarray.push(obj);

    urlfilter = "";
    // Iterate through each filter in the array
    for (var i = 0; i < filterarray.length; i++) {
        //Index each item filter in filterarray
        var itemfilter = filterarray[i];
        // Iterate through each parameter in each item filter
        for (var index in itemfilter) {
            // Check to see if the paramter has a value (some don't)
            if (itemfilter[index] !== "") {
                if (itemfilter[index] instanceof Array) {
                    for (var r = 0; r < itemfilter[index].length; r++) {
                        var value = itemfilter[index][r];
                        urlfilter += "&itemFilter\(" + i + "\)." + index + "\(" + r + "\)=" + value;
                    }
                } else {
                    urlfilter += "&itemFilter\(" + i + "\)." + index + "=" + itemfilter[index];
                }
            }
        }
    }
} // End fillFilterArray() function

var url = "";

function eBaySearch(pageNumber) {
    ++eBaySearchCount[pageNumber];

    // Fill the filter array from form input
    if (pageNumber == 1) {
        fillFilterArray();
    }

    // Construct the request
    url = configeBayFinding + "?";
    url += "OPERATION-NAME=findItemsAdvanced";
    url += "&SERVICE-VERSION=" + configeBayFindingVersion;
    url += "&SECURITY-APPNAME=" + configAppid;
    url += "&GLOBAL-ID=EBAY-US";
    url += "&RESPONSE-DATA-FORMAT=JSON";
    url += "&REST-PAYLOAD";
    url += "&paginationInput.entriesPerPage=100";
    url += "&paginationInput.pageNumber=";
    url += pageNumber;
    url += urlfilter;

    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
        if (this.readyState == 4) {
            if (this.status == 200) {
                _cb_findItemsAdvanced(JSON.parse(this.responseText));
            } else {
                if (eBaySearchCount[pageNumber] <= 5) {
                    window.setTimeout(function(){eBaySearch(pageNumber);}, 5000);             
                } else {
                    --pagesToProcess;
                    ++pagesProcessed;
                    updateProgressBar(maxPagesToProcess, pagesProcessed);
                    window.setTimeout(function(){eBaySearchCount[pageNumber+1]=0;eBaySearch(pageNumber+1);}, 5000);             
                }
            }
            
        }
    };

    xhttp.open("GET", configProxyUrl, true);
    xhttp.setRequestHeader("X-Proxy-Url", encodeURI(url));
    xhttp.send();

    return false;
}

function printeBayAPIError(str, root) {
    var x = document.getElementById("results");
    x.className += " process-errors";
    x.innerHTML += "<h2>eBay API Error (" + str + ")<h2>";
    x.innerHTML += "<p>Id: " + root.errorMessage[0].error[0].errorId + "<br/>";
    x.innerHTML += "<p>Severity: " + root.errorMessage[0].error[0].severity + "<br/>";
    x.innerHTML += "<p>Message: " + root.errorMessage[0].error[0].message + "</p>";
}

// Parse the response and build an HTML table to display search results
function _cb_findItemsAdvanced(root) {
    // Error Handling
    var response = root.findItemsAdvancedResponse[0];
    var ack = response.ack;
    if (ack != 'Success') {
        printeBayAPIError('Find Item', response);

        if (ack == 'Failure' || ack == 'PartialFailure') {
            --pagesToProcess;
            return;
        }
    }

    createTable(response.searchResult[0].item || [], Number(response.paginationOutput[0].pageNumber), Number(response.paginationOutput[0].totalPages));

    if (Number(response.paginationOutput[0].totalPages) > Number(response.paginationOutput[0].pageNumber)) {
        ++maxPagesToProcess;
        ++pagesToProcess;
        eBaySearchCount[Number(response.paginationOutput[0].pageNumber) + 1] = 0;
        eBaySearch(Number(response.paginationOutput[0].pageNumber) + 1);
    }

    document.getElementById("logging").innerHTML = html.join('');
    --pagesToProcess;
    ++pagesProcessed;
    updateProgressBar(maxPagesToProcess, pagesProcessed);
} // End _cb_findItemsAdvanced() function


function createTable(obj, pageNumber, totalPages) {
    if (pageNumber == 1) {
        document.getElementById("logging").innerHTML = '';
        html = [];

        html.push('<div class="border table-responsive">');
        html.push('<h3>Price Validation</h3>');
        html.push('<table id="itemTable" class="table table-hover table-striped table-bordered small css-serial">');
        html.push('<thead class="thead-dark">');
        html.push('<tr>');

        html.push(tableHeader('#'));
        html.push(tableHeader('Item Id'));
        html.push(tableHeader('Thumbnail'));
        html.push(tableHeader('Title'));
        html.push(tableHeader('Product Id'));
        html.push(tableHeader('Price'));
        html.push(tableHeader('# Active Listings'));
        html.push(tableHeader('# Priced Lower'));
        html.push(tableHeader('Lowest Price'));
        html.push(tableHeader('Highest Price'));
        html.push(tableHeader('Above/Below Lowest'));
        html.push(tableHeader('Views'));
        html.push(tableHeader('Watchers'));
        html.push(tableHeaderHidden('Condition'));
        html.push(tableHeaderHidden('# Better Condition'));
        html.push(tableHeader('Price Adj.'));
        html.push(tableHeaderHidden('Best Offer'));
        html.push(tableHeaderHidden('MinBetterCondition'));
        html.push(tableHeaderHidden('BetterConditionBreakdown'));
        html.push(tableHeaderHidden('SameConditionBreakdown'));

        html.push('</tr>');
        html.push('</thead>');
        html.push('<tbody>');
    }

    for (var entry = 0; entry < obj.length; entry++) {
        html.push('<tr>');
        html.push(tableCell(''));
        html.push(tableCell('<a href="' + obj[entry].viewItemURL + '" target="_blank">' + obj[entry].itemId + '</a>'));
        html.push(tableCell('<img src="' + obj[entry].galleryURL[0].replace('http:', 'https:') + '">'));
        html.push(tableCell(obj[entry].title));
        if (obj[entry].productId !== undefined) {
            var str = '<a href="' + configSearchUrl;
            str += 'ReferenceID%3A' + obj[entry].productId[0].__value__;
            str += configSearchUrlPart2 + '" target="_blank">';
            str += obj[entry].productId[0]["@type"] + ' ' + obj[entry].productId[0].__value__;
            str += '</a>';
            html.push(tableCell(str));
        } else {
            html.push(tableCellLabel('ProductId' + obj[entry].itemId));
        }

        html.push(tableCell('$' + Number(obj[entry].sellingStatus[0].convertedCurrentPrice[0].__value__).toFixed(2)));
        html.push(tableCell(1));
        html.push(tableCell(0));
        html.push(tableCell('$0.00'));
        html.push(tableCell('$0.00'));
        html.push(tableCell('$0.00 (0.00%)'));

        html.push(tableCell(0));
        html.push(tableCell(obj[entry].listingInfo[0].watchCount === undefined ? 0 : Number(obj[entry].listingInfo[0].watchCount)));
        html.push(tableCellHidden(obj[entry].condition === undefined ? 4000 : Number(obj[entry].condition[0].conditionId)));
        html.push(tableCellHidden(0));
        html.push(tableCell('<input id="PriceAdj' + obj[entry].itemId + '" type="text" size="10"><br><input type="button" class="btn btn-dark" onclick="changePrice(' + obj[entry].itemId + ');" value="Adjust Price" />'));
        html.push(tableCellLabelHidden('BestOffer' + obj[entry].itemId, obj[entry].listingInfo[0].bestOfferEnabled));
        html.push(tableCellHidden('0'));
        html.push(tableCellHidden('[]'));
        html.push(tableCellHidden('[]'));

        html.push('</tr>');
    }

    if (pageNumber == totalPages) {
        html.push('</tbody>');
        html.push('</table>');
        html.push('</div>');
    }
}

function setCellsAttribute(table, row, col, label) {
    table.rows[row].cells[col].setAttribute("id", label);
}

function sortTableDesc(tableName, column) {
    var table, rows, switching, i, x, y, shouldSwitch;
    --column; // column parameter starts with 1
    table = document.getElementById(tableName);
    switching = true;
    /*Make a loop that will continue until
    no switching has been done:*/
    while (switching) {
        //start by saying: no switching is done:
        switching = false;
        rows = table.getElementsByTagName("TR");
        /*Loop through all table rows (except the
        first, which contains table headers:*/
        for (i = 1; i < (rows.length - 1); i++) {
            //start by saying there should be no switching:
            shouldSwitch = false;
            /*Get the two elements you want to compare,
            one from current row and one from the next:*/
            x = rows[i].getElementsByTagName("TD")[column];
            y = rows[i + 1].getElementsByTagName("TD")[column];
            //check if the two rows should switch place:
            if (x !== undefined && (Number(x.innerHTML.substr(1)) < Number(y.innerHTML.substr(1)))) {
                //if so, mark as a switch and break the loop:
                shouldSwitch = true;
                break;
            }
        }
        if (shouldSwitch) {
            /*If a switch has been marked, make the switch
            and mark that a switch has been done:*/
            rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
            switching = true;
        }
    }
}

function findMissingProductIds() {
    var i;
    var x = document.getElementById("itemTable");
    var missingList = [];
    var viewList = [];
    var maxItems = 20;

    initProgressBar('Retrieving Product Ids (2/3)');

    productIdsToProcess = 0;
    maxProductIdsToProcess = 0;
    productIdsProcessed = 0;

    for (i = 1; i < x.rows.length; i++) {
        if (x.rows[i].cells[4] !== undefined && x.rows[i].cells[4].innerText.length < 1) {
            missingList.push(x.rows[i].cells[1].innerText);
        } else {
            var p = x.rows[i].cells[4].innerText.substr(x.rows[i].cells[4].innerText.indexOf(" ") + 1);
            setCellsAttribute(x, i, 5, "Price" + p);
            setCellsAttribute(x, i, 6, "Active" + p);
            setCellsAttribute(x, i, 7, "Lower" + p);
            setCellsAttribute(x, i, 8, "Minimum" + p);
            setCellsAttribute(x, i, 9, "Maximum" + p);
            setCellsAttribute(x, i, 11, "Views" + x.rows[i].cells[1].innerText);
            setCellsAttribute(x, i, 13, "Condition" + p);
            setCellsAttribute(x, i, 14, "BetterCondition" + p);
            setCellsAttribute(x, i, 17, "MinBetterCondition" + p);
            setCellsAttribute(x, i, 18, "BetterConditionBreakdown" + p);
            setCellsAttribute(x, i, 19, "SameConditionBreakdown" + p);
            viewList.push(x.rows[i].cells[1].innerText);
        }
    }

    for (i = 0;
        (i * maxItems) < missingList.length; i++) {
        ++productIdsToProcess;
        ++maxProductIdsToProcess;
        findMissingProductId(missingList.slice(i * maxItems, (i + 1) * maxItems));
    }

    for (i = 0;
        (i * maxItems) < viewList.length; i++) {
        ++productIdsToProcess;
        ++maxProductIdsToProcess;
        findViews(viewList.slice(i * maxItems, (i + 1) * maxItems));
    }

    function checkproductIdsToProcess() {
        if (productIdsToProcess > 0) {
            window.setTimeout(checkproductIdsToProcess, 250); // wait 100 milliseconds
        } else {
            priceProductIds();
        }
    }

    checkproductIdsToProcess();
}

function findMissingProductId(itemIdList) {
    var i;
    var xml;

    var xw = new XMLWriter('UTF-8', '1.0');
    var xhr = new XMLHttpRequest();

    xw.writeStartDocument();
    xw.writeStartElement("GetMultipleItemsRequest");
    xw.writeAttributeString('xmlns', 'urn:ebay:apis:eBLBaseComponents');

    for (i = 0; i < itemIdList.length; i++) {
        xw.writeElementString('ItemID', itemIdList[i]);
    }

    xw.writeElementString('IncludeSelector', 'Details');
    xw.writeElementString('ErrorLanguage', 'en_US');
    xw.writeElementString('Version', configeBayShoppingVersion);
    xw.writeElementString('WarningLevel', configWarningLevel);

    xw.writeEndElement(); /* xmlrequest */
    xw.writeEndDocument();

    xhr.open('POST', configProxyUrl, true);
    xhr.setRequestHeader('Content-Type', 'text/xml');
    xhr.setRequestHeader('X-EBAY-API-APP-NAME', configAppid);
    xhr.setRequestHeader('X-EBAY-API-VERSION', configeBayShoppingVersion);
    xhr.setRequestHeader('X-EBAY-API-CALL-NAME', 'GetMultipleItems');
    xhr.setRequestHeader('X-EBAY-API-SITEID', '0');
    xhr.setRequestHeader('X-EBAY-API-DEV-NAME', '');
    xhr.setRequestHeader('X-EBAY-API-CERT-NAME', '');
    xhr.setRequestHeader('X-EBAY-API-REQUEST-ENCODING', 'XML');
    xhr.setRequestHeader('X-Proxy-URL', configeBayShopping);

    xml = xw.flush();
    xw.close();

    xhr.onload = function() {
        var jsonObj = XMLparse(xhr.responseXML, false);
        var obj = jsonObj.GetMultipleItemsResponse;
        var returnCode = obj.Ack;
        var str;

        var x = document.getElementById("results");

        if (returnCode == 'Success') {
            for (i = 0; i < obj.Item.length; i++) {
                var ItemID = getJsonValue(obj.Item[i].ItemID);
                var SKU = getJsonValue(obj.Item[i].SKU);
                var HitCount = getJsonValue(obj.Item[i].HitCount);
                var n = (SKU === undefined ? 0 : SKU.indexOf(" - "));
                var row;
                var str;
                var code;

                if (n > 0) {
                    code = SKU.substr(n + 3);
                    code = code.substr(code.indexOf(" ") + 1);
                    str = '<a href="' + configSearchUrl;
                    str += code;
                    str += configSearchUrlPart2 + '" target="_blank">';
                    str += SKU.substr(n + 3);
                    str += '</a>';
                    document.getElementById('ProductId' + ItemID).innerHTML = str;
                    x = document.getElementById("itemTable");
                    row = document.getElementById('ProductId' + ItemID).parentNode.rowIndex;
                    setCellsAttribute(x, row, 5, "Price" + code);
                    setCellsAttribute(x, row, 6, "Active" + code);
                    setCellsAttribute(x, row, 7, "Lower" + code);
                    setCellsAttribute(x, row, 8, "Minimum" + code);
                    setCellsAttribute(x, row, 9, "Maximum" + code);
                    x.rows[row].cells[11].innerHTML = HitCount;
                    setCellsAttribute(x, row, 13, "Condition" + code);
                    setCellsAttribute(x, row, 14, "BetterCondition" + code);
                    setCellsAttribute(x, row, 17, "MinBetterCondition" + code);
                    setCellsAttribute(x, row, 18, "BetterConditionBreakdown" + code);
                    setCellsAttribute(x, row, 19, "SameConditionBreakdown" + code);
                } else {
                    row = document.getElementById('ProductId' + ItemID).parentNode.rowIndex;
                    document.getElementById("itemTable").deleteRow(row);
                }
            }
        } else {
            x.className += " process-errors";
            str += '<p class="text-danger"><strong>' + returnCode + ':</strong></p>';

            var errors = getJsonArray(obj.Errors);
            str += "<p>";
            for (i = 0; i < errors.length; i++) {
                str += errors[i].SeverityCode + " (" + errors[i].ErrorCode + "): " + escapeHtml(errors[i].LongMessage) + "<br/>";
            }
            str += "</p>";
            x.innerHTML += str;
        }

        --productIdsToProcess;
        ++productIdsProcessed;
        updateProgressBar(maxProductIdsToProcess, productIdsProcessed);
    };

    xhr.send(xml);
}

function findViews(itemIdList) {
    var i;
    var xml;

    var xw = new XMLWriter('UTF-8', '1.0');
    var xhr = new XMLHttpRequest();

    xw.writeStartDocument();
    xw.writeStartElement("GetMultipleItemsRequest");
    xw.writeAttributeString('xmlns', 'urn:ebay:apis:eBLBaseComponents');

    for (i = 0; i < itemIdList.length; i++) {
        xw.writeElementString('ItemID', itemIdList[i]);
    }

    xw.writeElementString('ErrorLanguage', 'en_US');
    xw.writeElementString('Version', configeBayShoppingVersion);
    xw.writeElementString('WarningLevel', configWarningLevel);

    xw.writeEndElement(); /* xmlrequest */
    xw.writeEndDocument();

    xhr.open('POST', configProxyUrl, true);
    xhr.setRequestHeader('Content-Type', 'text/xml');
    xhr.setRequestHeader('X-EBAY-API-APP-NAME', configAppid);
    xhr.setRequestHeader('X-EBAY-API-VERSION', configeBayShoppingVersion);
    xhr.setRequestHeader('X-EBAY-API-CALL-NAME', 'GetMultipleItems');
    xhr.setRequestHeader('X-EBAY-API-SITEID', '0');
    xhr.setRequestHeader('X-EBAY-API-DEV-NAME', '');
    xhr.setRequestHeader('X-EBAY-API-CERT-NAME', '');
    xhr.setRequestHeader('X-EBAY-API-REQUEST-ENCODING', 'XML');
    xhr.setRequestHeader('X-Proxy-URL', configeBayShopping);

    xml = xw.flush();
    xw.close();

    xhr.onload = function() {
        var jsonObj = XMLparse(xhr.responseXML, false);
        var obj = jsonObj.GetMultipleItemsResponse;
        var returnCode = obj.Ack;
        var str;

        var x = document.getElementById("results");

        if (returnCode == 'Success') {
            for (i = 0; i < obj.Item.length; i++) {
                var ItemID = getJsonValue(obj.Item[i].ItemID);
                var HitCount = getJsonValue(obj.Item[i].HitCount);

                document.getElementById('Views' + ItemID).innerHTML = HitCount;
            }
        } else {
            x.className += " process-errors";
            str += '<p class="text-danger"><strong>' + returnCode + ':</strong></p>';

            var errors = getJsonArray(obj.Errors);
            str += "<p>";
            for (i = 0; i < errors.length; i++) {
                str += errors[i].SeverityCode + " (" + errors[i].ErrorCode + "): " + escapeHtml(errors[i].LongMessage) + "<br/>";
            }
            str += "</p>";
            x.innerHTML += str;
        }

        --productIdsToProcess;
        ++productIdsProcessed;
        updateProgressBar(maxProductIdsToProcess, productIdsProcessed);
    };

    xhr.send(xml);
}

function priceProductIds() {
    var i;
    var price;
    var lowest;
    var difference;
    var percentage;
    var noPricedLower;
    var noActive;
    var noBetterCondition;
    var percLower;
    var x = document.getElementById("itemTable");

    initProgressBar('Retrieving Prices (3/3)');

    productsToPrice = 0;
    maxProductsToPrice = 0;
    productsPriced = 0;

    for (i = 1; i < x.rows.length; i++) {
        if (x.rows[i].cells[4].innerText.length > 0) {
            ++productsToPrice;
            ++maxProductsToPrice;
            productPricesCount = [];
            findProductPrices(x.rows[i].cells[4].innerText, 1);
        }
    }

    function checkProductsToPrice() {
        if (productsToPrice > 0) {
            window.setTimeout(checkProductsToPrice, 100); // wait 100 milliseconds
        } else {
            /*
                xxxxx
                Minimum of 5 comparison listings
                (Take out lowest and highest price before calculating the average)
                (Don't go under $4.98)
                (Price items below cheapest item with better condition)
                Price within the first 20-25% listing (by number)
                (Price below the average price)
                adjust BIN (buy it now) when changing the price: No BIN under $10; minimum accepted 65%, auto-accepted 85+%
                (disregard certain sellers (for now decluttr and zuber, list could be expanded))
            */
            for (i = (x.rows.length - 1); i > 0; i--) {
                noPricedLower = Number(x.rows[i].cells[7].innerHTML);
                noActive = Number(x.rows[i].cells[6].innerHTML);

                if (noActive < 6) {
                    document.getElementById("itemTable").deleteRow(i);
                    continue;
                }

                if (noPricedLower > 0) {
                    price = Number(x.rows[i].cells[5].innerHTML.substr(1));
                    lowest = Number(x.rows[i].cells[8].innerHTML.substr(1));
                    difference = price - lowest;
                    percentage = 100.00 - (lowest / price * 100.00);
                    x.rows[i].cells[10].innerHTML = "$" + difference.toFixed(2) + " (" + percentage.toFixed(2) + "%)";

                    percLower = (noPricedLower / noActive) * 100.00;
                    if (noPricedLower > 24.99) {
                        x.rows[i].cells[5].style.color = "red";
                        x.rows[i].cells[7].style.color = "red";
                    } else {
                        document.getElementById("itemTable").deleteRow(i);
                        continue;
                    }

                    if (difference < configDifference || percentage < configPercentage || price < configAbsoluteMinPrice) {
                        document.getElementById("itemTable").deleteRow(i);
                        continue;
                    } else {
                        x.rows[i].cells[5].style.color = "red";
                        x.rows[i].cells[10].style.color = "red";
                    }
                } else if (noPricedLower === 0) {
                    noBetterCondition = Number(x.rows[i].cells[14].innerHTML);
                    if (noActive == (noBetterCondition + 1)) {
                        document.getElementById("itemTable").deleteRow(i);
                        continue;
                    }

                    price = Number(x.rows[i].cells[5].innerHTML.substr(1));
                    lowest = Number(x.rows[i].cells[8].innerHTML.substr(1));
                    difference = price - lowest;
                    percentage = 100.00 - (lowest / price * 100.00);
                    x.rows[i].cells[10].innerHTML = "$" + difference.toFixed(2) + " (" + percentage.toFixed(2) + "%)";

                    if ((difference * -1.00) < configDifference && (percentage * -1.00) < configPercentage) {
                        document.getElementById("itemTable").deleteRow(i);
                        continue;
                    } else {
                        x.rows[i].cells[5].style.color = "green";
                        x.rows[i].cells[10].style.color = "green";
                    }
                    continue;
                }
            }

            endProgressBar();

            x = document.getElementById("results");
            x.innerHTML += '<p><strong>Sorting Report.....</strong></p>';

            sortTableDesc("itemTable", 6);

            x.innerHTML += '<p><strong>Report Finished!</strong></p>';
            if (!x.className.includes("process-errors")) {
                setTimeout(function() {
                    x.className = x.className.replace(" w3-show", "");
                }, 3000);
            }
        }
    }

    checkProductsToPrice();
}

function findProductPrices(productId, pageNumber) {
    var n = productId.indexOf(" ");
    var productIdType = productId.substr(0, n);
    var keyword = productId.substr(n + 1);

    var idx = (Number(keyword) * 10) + pageNumber;
    if (productPricesCount[idx] === undefined) {
        productPricesCount[idx] = 1;
    } else {
        ++productPricesCount[idx];
    }

    url = configeBayFinding + "?";
    if (productIdType == 'ReferenceID') {
        url += "OPERATION-NAME=findItemsByProduct";
    } else {
        url += "OPERATION-NAME=findItemsAdvanced";
    }
    url += "&RESPONSE-DATA-FORMAT=JSON";
    url += "&SECURITY-APPNAME=" + configAppid;
    url += "&SERVICE-VERSION=" + configeBayFindingVersion;
    url += "&GLOBAL-ID=EBAY-US";
    url += "&buyerPostalCode=";
    url += configZip;
    url += "&paginationInput.entriesPerPage=100";
    url += "&paginationInput.pageNumber=";
    url += pageNumber;

    if (productIdType == 'ReferenceID') {
        url += "&productId.@type=";
        url += productIdType;
        url += "&productId=";
        url += keyword;
    } else {
        url += "&keywords=";
        url += keyword;
    }

    url += "&itemFilter(0).name=ExcludeSeller";
    url += "&itemFilter(0).value=";
    url += configeBaySellerName;

    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
        if (this.readyState == 4) {
            if (this.status == 200) {
                _cb_findProductPrices(JSON.parse(this.responseText));
            } else {
                if (productPricesCount[idx] <= 5) {
                    window.setTimeout(function(){findProductPrices(productId, pageNumber);}, 5000);             
                } else {
                    --productsToPrice;
                    ++productsPriced;
                    updateProgressBar(maxProductsToPrice, productsPriced);
                }
            }

        }
    };

    xhttp.open("GET", configProxyUrl, true);
    xhttp.setRequestHeader("X-Proxy-Url", encodeURI(url));
    xhttp.send();

}

function _cb_findProductPrices(root) {
    var array;
    var response;
    var ack;
    var productId;
    var i;
    var currentPrice;
    var Title = "";
    var noLower;
    var noActive;
    var minPrice;
    var maxPrice;
    var conditionId;
    var currentConditionId;
    var noBetterCondition;
    var myPrice;
    var currentPriceInt;
    var minBetterCondition;
    var betterConditionbBreakdown = [];
    var sameConditionbBreakdown = [];

    if (root.findItemsAdvancedResponse !== undefined) {
        response = root.findItemsAdvancedResponse[0];
    } else if (root.findItemsByProductResponse !== undefined) {
        response = root.findItemsByProductResponse[0];
    } else {
        --productsToPrice;
        ++productsPriced;
        updateProgressBar(maxProductsToPrice, productsPriced);
        return;
    }

    ack = response.ack;
    if (ack != 'Success') {
        printeBayAPIError('Get Prices', response);

        if (ack == 'Failure' || ack == 'PartialFailure') {
            --productsToPrice;
            ++productsPriced;
            updateProgressBar(maxProductsToPrice, productsPriced);
            return;
        }
    }

    if (root.findItemsAdvancedResponse !== undefined) {
        array = typeof root.findItemsAdvancedResponse[0] != 'object' ? JSON.parse(root.findItemsAdvancedResponse[0]) : root.findItemsAdvancedResponse[0].searchResult[0].item;
        response = root.findItemsAdvancedResponse[0];
        url = new URL(response.itemSearchURL);
        productId = url.searchParams.get("_nkw");
    } else {
        array = typeof root.findItemsByProductResponse[0] != 'object' ? JSON.parse(root.findItemsByProductResponse[0]) : root.findItemsByProductResponse[0].searchResult[0].item;
        url = new URL(response.itemSearchURL);
        productId = url.searchParams.get("_productid");
    }

    var items = response.searchResult[0].item || [];
    noActive = Number(document.getElementById('Active' + productId).innerHTML);
    noLower = Number(document.getElementById('Lower' + productId).innerHTML);
    myPrice = Number(document.getElementById('Price' + productId).innerHTML.substr(1));
    minPrice = Number(document.getElementById('Minimum' + productId).innerHTML.substr(1));
    maxPrice = Number(document.getElementById('Maximum' + productId).innerHTML.substr(1));
    conditionId = Number(document.getElementById('Condition' + productId).innerHTML);
    noBetterCondition = Number(document.getElementById('BetterCondition' + productId).innerHTML);
    minBetterCondition = Number(document.getElementById('MinBetterCondition' + productId).innerHTML);
    betterConditionbBreakdown = JSON.parse(document.getElementById('BetterConditionBreakdown' + productId).innerHTML);
    sameConditionbBreakdown = JSON.parse(document.getElementById('SameConditionBreakdown' + productId).innerHTML);

    for (i = 0; i < items.length; i++) {
        Title = items[i].title[0].toLowerCase();
        if (Title.includes("disc only") > 0 ||
            Title.includes("disk only") > 0 ||
            Title.includes("only disc") > 0 ||
            Title.includes("only disk") > 0 ||
            Title.search(/dis[ck].*only/) > 0) {
            continue; // exclude "disc only listing
        }

        currentConditionId = (items[i].condition === undefined ? 0 : Number(items[i].condition[0].conditionId));
        currentPrice = Number(items[i].sellingStatus[0].convertedCurrentPrice[0].__value__);
        currentPriceInt = Math.ceil(currentPrice);

        if (currentConditionId > conditionId) {
            continue; // Like for like conditions only
        } else if (currentConditionId > conditionId) {
            if (minBetterCondition < 0.01 || minBetterCondition > currentPrice) {
                minBetterCondition = currentPrice;
            }

            ++noBetterCondition;
        }

        if (items[i].sellingStatus[0].bidCount === 0 && items[i].listingInfo[0].convertedBuyItNowPrice !== undefined) {
            currentPrice = Number(items[i].listingInfo[0].convertedBuyItNowPrice[0].__value__);
        }

        if (items[i].shippingInfo[0].shippingServiceCost) {
            currentPrice += Number(items[i].shippingInfo[0].shippingServiceCost[0].__value__);
        }

        if (currentConditionId > conditionId) {
            if (betterConditionbBreakdown[currentPriceInt] === undefined) {
                betterConditionbBreakdown[currentPriceInt] = 0;
            }
            ++betterConditionbBreakdown[currentPriceInt];
        } else {
            if (sameConditionbBreakdown[currentPriceInt] === undefined) {
                sameConditionbBreakdown[currentPriceInt] = 0;
            }
            ++sameConditionbBreakdown[currentPriceInt];
        }

        if (currentPrice < myPrice) {
            ++noLower;
        }

        if (minPrice < 0.01 || minPrice > currentPrice) {
            minPrice = currentPrice;
        }

        if (maxPrice < 0.01 || maxPrice < currentPrice) {
            maxPrice = currentPrice;
        }

        ++noActive;
    }

    document.getElementById('Active' + productId).innerHTML = noActive;
    document.getElementById('Lower' + productId).innerHTML = noLower;
    document.getElementById('Minimum' + productId).innerHTML = '$' + minPrice.toFixed(2);
    document.getElementById('Maximum' + productId).innerHTML = '$' + maxPrice.toFixed(2);
    document.getElementById('BetterCondition' + productId).innerHTML = noBetterCondition;
    document.getElementById('MinBetterCondition' + productId).innerHTML = minBetterCondition;
    document.getElementById('BetterConditionBreakdown' + productId).innerHTML = JSON.stringify(betterConditionbBreakdown);
    document.getElementById('SameConditionBreakdown' + productId).innerHTML = JSON.stringify(sameConditionbBreakdown);

    if (Number(response.paginationOutput[0].totalPages) > Number(response.paginationOutput[0].pageNumber)) {
        ++productsToPrice;
        ++maxProductsToPrice;
        var row = document.getElementById('Lower' + productId).parentNode.rowIndex;
        findProductPrices(document.getElementById("itemTable").rows[row].cells[4].innerText, Number(response.paginationOutput[0].pageNumber) + 1);
    }

    --productsToPrice;
    ++productsPriced;
    updateProgressBar(maxProductsToPrice, productsPriced);
}

function changePrice(itemId) {
    var i;
    var newPrice = parseFloat(document.getElementById('PriceAdj' + itemId).value).toFixed(2);

    if (isNaN(newPrice) || newPrice < configAdjMinPrice) {
        document.getElementById('PriceAdj' + itemId).value = '';
        return;
    }

    document.getElementById('PriceAdj' + itemId).value = newPrice;

    if (eBayAuthTokenFlag === false) {
        return;
    }

    var xw = new XMLWriter('UTF-8', '1.0');
    var xhr = new XMLHttpRequest();

    if (!createAddXML(xw, xhr, 'ReviseItemRequest', 'ReviseItem', itemId, newPrice)) {
        return;
    }

    xml = xw.flush();
    xw.close();

    xhr.onload = function() {
        var jsonObj = XMLparse(xhr.responseXML, false);
        var obj = jsonObj.ReviseItemResponse;
        var returnCode = obj.Ack;
        var str = "";

        var x = document.getElementById("results");
        if (x.className.indexOf("w3-show") == -1) {
            x.className += " w3-show";
        }
        x.className = x.className.replace(" process-errors", "");

        if (returnCode == 'Success' || (returnCode == 'Warning' && (obj.Errors.ErrorCode == '21917108' || obj.Errors.ErrorCode == '23007'))) {
            document.getElementById('PriceAdj' + itemId).style.color = "green";

            str = '<p><strong>' + returnCode + '</strong></p>';

            if (returnCode == 'Warning') {
                str += "<p>" + obj.Errors.SeverityCode + " (" + obj.Errors.ErrorCode + "): " + escapeHtml(obj.Errors.LongMessage) + "</p>";
                x.className += " process-errors";
            }
            var fees = getJsonArray(obj.Fees.Fee);
            str += "<p>";
            for (i = 0; i < fees.length; i++) {
                if (fees[i].Fee.text !== "0.0") {
                    str += fees[i].Name + ": $" + Number(fees[i].Fee.text).toFixed(2) + "<br/>";
                }
            }
            str += "</p>";

            if (obj.DiscountReason) {
                str += "<p>Discount Reason: " + obj.DiscountReason + "</p>";
            }

            if (obj.ListingRecommendations !== undefined) {
                var recommendations = getJsonArray(obj.ListingRecommendations.Recommendation);
                for (i = 0; i < recommendations.length; i++) {
                    str += decode(recommendations[i]);
                }
            }
            
            x.innerHTML = str;
        } else {
            document.getElementById('PriceAdj' + itemId).style.color = "red";
            str = "<p><strong>" + returnCode + ":</strong></p>";
            x.className += " process-errors";

            var errors = getJsonArray(obj.Errors);
            str += "<p>";
            for (i = 0; i < errors.length; i++) {
                str += errors[i].SeverityCode + " (" + errors[i].ErrorCode + "): " + escapeHtml(errors[i].LongMessage) + "<br/>";
            }
            str += "</p>";
            x.innerHTML = str;
        }

        if (obj.Message) {
            x.innerHTML += obj.Message;
        }

        if (!x.className.includes("process-errors")) {
            setTimeout(function() {
                x.className = x.className.replace(" w3-show", "");
            }, 3000);
        }
    };

    xhr.send(xml);
}

function createAddXML(xw, xhr, xmlrequest, callname, itemId, newPrice) {
    xw.writeStartDocument();
    xw.writeStartElement(xmlrequest);
    xw.writeAttributeString('xmlns', 'urn:ebay:apis:eBLBaseComponents');

    xw.writeStartElement('RequesterCredentials');
    xw.writeElementString('eBayAuthToken', eBayAuthToken);
    xw.writeEndElement(); /* RequesterCredentials */

    xw.writeStartElement('Item');

    xw.writeStartElement('StartPrice');
    xw.writeAttributeString('currencyID', 'USD');
    xw.writeString(newPrice);
    xw.writeEndElement(); /* StartPrice */

    //xw.writeElementString('ItemID', itemId);
    xw.writeString('<ItemID>' + itemId + '</ItemID>');

    if (document.getElementById('BestOffer' + itemId).innerHTML == 'true') {
        if (newPrice >= 14.99) {
            var autoAcceptPrice = newPrice * configAutoAcceptPrice;
            var minBestOfferPrice = newPrice * configMinBestOfferPrice;

            xw.writeStartElement('BestOfferDetails');
            xw.writeElementString('BestOfferEnabled', 'true');
            xw.writeEndElement(); /* BestOfferDetails */
            xw.writeStartElement('ListingDetails');
            xw.writeStartElement('BestOfferAutoAcceptPrice');
            xw.writeAttributeString('currencyID', 'USD');
            xw.writeString(autoAcceptPrice.toFixed(2));
            xw.writeEndElement(); /* BestOfferAutoAcceptPrice */
            xw.writeStartElement('MinimumBestOfferPrice');
            xw.writeAttributeString('currencyID', 'USD');
            xw.writeString(minBestOfferPrice.toFixed(2));
            xw.writeEndElement(); /* MinimumBestOfferPrice */
            xw.writeEndElement(); /* ListingDetails */
        } else {
            xw.writeStartElement('BestOfferDetails');
            xw.writeElementString('BestOfferEnabled', 'false');
            xw.writeEndElement(); /* BestOfferDetails */
        }
    }

    xw.writeEndElement(); /* Item */

    xw.writeElementString('ErrorLanguage', 'en_US');
    xw.writeElementString('Version', configeBayTradingVersion);
    xw.writeElementString('WarningLevel', configWarningLevel);

    xw.writeEndElement(); /* xmlrequest */
    xw.writeEndDocument();

    xhr.open('POST', configProxyUrl, true);
    xhr.setRequestHeader('Content-Type', 'text/xml');
    xhr.setRequestHeader('X-EBAY-API-APP-NAME', configAppid);
    xhr.setRequestHeader('X-EBAY-API-COMPATIBILITY-LEVEL', configeBayTradingVersion);
    xhr.setRequestHeader('X-EBAY-API-CALL-NAME', callname);
    xhr.setRequestHeader('X-EBAY-API-SITEID', '0');
    xhr.setRequestHeader('X-EBAY-API-DEV-NAME', '');
    xhr.setRequestHeader('X-EBAY-API-CERT-NAME', '');
    xhr.setRequestHeader('X-Proxy-URL', configServiceEndpoint);

    return true;
}

function connected() {
    var x;

    eBayAuthTokenFlag = true;
    document.getElementById("connected").innerHTML += " (Connected)";

    x = document.getElementById("login");
    x.className = x.className.replace(" w3-show", "");

    x = document.getElementById("results");
    x.innerHTML = "";
    x.className = x.className.replace(" w3-show", "");
}

    </script>
    <script>includeHTML();</script>

</body>
</html>