UNPKG

mws-zodane-advanced

Version:

fixed throtal resend

356 lines (324 loc) 21.1 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <base data-ice="baseUrl" href="../../"> <title data-ice="title">lib/reports.js | mws-advanced</title> <link type="text/css" rel="stylesheet" href="css/style.css"> <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css"> <script src="script/prettify/prettify.js"></script> <script src="script/manual.js"></script> </head> <body class="layout-container" data-ice="rootContainer"> <header> <a href="./">Home</a> <a href="identifiers.html">Reference</a> <a href="source.html">Source</a> <div class="search-box"> <span> <img src="./image/search.png"> <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span> </span> <ul class="search-result"></ul> </div> </header> <nav class="navigation" data-ice="nav"><div> <ul> <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~InvalidUsage.html">InvalidUsage</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~RequestCancelled.html">RequestCancelled</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~ServiceError.html">ServiceError</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/errors.js~ValidationError.html">ValidationError</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-callEndpoint">callEndpoint</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-init">init</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getLowestPricedOffersForASIN">getLowestPricedOffersForASIN</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getMarketplaces">getMarketplaces</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getMatchingProductForId">getMatchingProductForId</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listFinancialEvents">listFinancialEvents</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listInventorySupply">listInventorySupply</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listOrderItems">listOrderItems</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-listOrders">listOrders</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReport">getReport</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportList">getReportList</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportListAll">getReportListAll</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportListByNextToken">getReportListByNextToken</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getReportRequestList">getReportRequestList</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-requestAndDownloadReport">requestAndDownloadReport</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-requestReport">requestReport</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MWS_ENDPOINTS">MWS_ENDPOINTS</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MWS_MARKETPLACES">MWS_MARKETPLACES</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-BuyBoxPrice">BuyBoxPrice</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-DetailedShippingTime">DetailedShippingTime</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-LowestPrice">LowestPrice</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-LowestPricedOffers">LowestPricedOffers</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-Money">Money</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-Offer">Offer</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OfferCount">OfferCount</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OfferSummary">OfferSummary</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-SellerFeedbackRating">SellerFeedbackRating</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-ShipsFrom">ShipsFrom</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-MarketDetail">MarketDetail</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-OrderItemList">OrderItemList</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-GetReportRequestListResult">GetReportRequestListResult</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-GetReportRequestListResult">GetReportRequestListResult</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-typedef">T</span><span data-ice="name"><span><a href="typedef/index.html#static-typedef-ReportRequestInfo">ReportRequestInfo</a></span></span></li> <li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#endpoints">endpoints</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-REPORT_PROCESSING_STATUS_TYPES">REPORT_PROCESSING_STATUS_TYPES</a></span></span></li> <li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-REQUEST_REPORT_TYPES">REQUEST_REPORT_TYPES</a></span></span></li> </ul> </div> </nav> <div class="content" data-ice="content"><h1 data-ice="title">lib/reports.js</h1> <pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">/** reporting functions * @module mws-advanced */ const { promisify } = require(&apos;util&apos;); const fs = require(&apos;fs&apos;); const errors = require(&apos;./errors&apos;); /** * Promisified version of fs.writeFile * We like to use Promises. writeFile does not come in a Promise variant, currently. * Use util/promisify to make it work with Promises. * This is better than using writeFileSync. Trust me. :-) * @param {string} fileName - path/filename to write to * @param {string|Buffer} contents - what to write to file */ const writeFile = promisify(fs.writeFile); const { callEndpoint } = require(&apos;./callEndpoint&apos;); const sleep = require(&apos;./util/sleep&apos;); /** * @typedef ReportRequestInfo * @param {string} ReportType Type of Report Requested @see {@link REQUEST_REPORT_TYPES} * @param {string} ReportProcessingStatus Status of Report @see {@link REPORT_PROCESSING_STATUS_TYPES} * @param {string} EndDate ISO Date for Date Ending period * @param {boolean} Scheduled True if report is scheduled, false if immediate * @param {string} ReportRequestId Identifier to use with getReport to fetch the report when ready * @param {string} SubmittedDate ISO Date for Date request was submitted * @param {string} StartDate ISO Date for Date report begins at */ // TODO: convert ISO Dates to Date objects? /** * Request a report from MWS * Many optional parameters may be required by MWS! Read [ReportType](https://docs.developer.amazonservices.com/en_US/reports/Reports_ReportType.html) for specifics! * * @async * @param {object} options * @param {string} options.ReportType Type of Report to Request @see {@link REQUEST_REPORT_TYPES} * @param {Date} [options.StartDate] Date to start report * @param {Date} [options.EndDate] Date to end report at * @param {object} [options.ReportOptions] Reports may have additional options available. Please see the [ReportType](https://docs.developer.amazonservices.com/en_US/reports/Reports_ReportType.html) official docs * @param {string[]} [MarketplaceId] Array of marketplace IDs to generate reports covering * @returns {ReportRequestInfo} */ const requestReport = async (options) =&gt; { const result = await callEndpoint(&apos;RequestReport&apos;, options); return result.ReportRequestInfo; }; // interesting note: there are tons of reports returned by this API, // apparently Amazon auto pulls reports, and many reports pulled in the Seller Central // interface will also show up here. Somewhere in the docs, it says that Amazon // keeps all reports for 90 days. // TODO: for some reason GetReportRequestListResult showsmentation twice. /** * @typedef GetReportRequestListResult * @param {string} ReportType Type of Report Requested @see {@link REQUEST_REPORT_TYPES} * @param {string} ReportProcessingStatus Status of Report @see {@link REPORT_PROCESSING_STATUS_TYPES} * @param {string} EndDate ISO Date for Report End Period * @param {boolean} Scheduled True if report is scheduled, false if immediate * @param {string} ReportRequestId Identifier for the Report Request * @param {string} StartedProcessingDate ISO Date for time MWS started processing request * @param {string} StartDate ISO Date for Report Start Period * @param {string} CompletedDate ISO Date for time MWS completed processing request * @param {string} GeneratedReportId Identifier to use with getReport to retrieve the report */ /** * Returns a list of report requests that you can use to get the ReportRequestId for a report * After calling requestReport, you should call this function occasionally to see if/when the report * has been processed. * * @async * @param {object} [options] Options to pass to GetReportRequestList * @param {string[]} [ReportRequestIdList] List of report request IDs @see {@link requestReport} * @param {string[]} [ReportTypeList] List of Report Types @see {@link REQUEST_REPORT_TYPES} * @param {string[]} [ReportProcessingStatusList] List of Report Processing Status @see {@link REPORT_PROCESSING_STATUS_TYPES} * @param {number} [MaxCount=10] Maximum number of report requests to return, max is 100 * @param {Date} [RequestedFromDate=90-days-past] Oldest date to search for * @param {Date} [RequestedToDate=Now] Newest date to search for * @returns {GetReportRequestListResult[]} */ // TODO: make sure we get NextToken out of there and into the main data structure somewhere const getReportRequestList = async (options = {}) =&gt; { const result = await callEndpoint(&apos;GetReportRequestList&apos;, options); // NextToken is under result.GetReportRequestListResponse.GetReportRequestListResult return result.ReportRequestInfo; }; /** * Returns the contents of a report * @async * @param {object} options Options to pass to GetReport * @param {string} options.ReportId Report number from @see {@link GetReportList} or GeneratedReportId from @see {@link GetReportRequestListResult} * @return {Array|object} Contents of the report to return (format may vary WIDELY between different reports generated, see [ReportType](https://docs.developer.amazonservices.com/en_US/reports/Reports_ReportType.html)) */ const getReport = async (options) =&gt; { const result = await callEndpoint(&apos;GetReport&apos;, options); return result; }; /** * TODO: write documentation for getReportList */ const getReportList = async (options = {}) =&gt; { const result = await callEndpoint(&apos;GetReportList&apos;, options); // NextToken should be in result.GetReportListResponse.GetReportListResult try { const ret = { result: result.ReportInfo, nextToken: result.HasNext &amp;&amp; result.NextToken, }; return ret; } catch (err) { return result; } }; /** * TODO: write documentation for getReportListByNextToken * (or just roll getReportList and getReportListByNextToken into the same wrapper) * (that wrapper might be getReportListAll, and just rename it) */ const getReportListByNextToken = async (options) =&gt; { const result = await callEndpoint(&apos;GetReportListByNextToken&apos;, options); try { const ret = { result: result.ReportInfo, nextToken: result.HasNext &amp;&amp; result.NextToken, }; return ret; } catch (err) { return result; } }; /** * TODO: write documentation for getReportListAll (or see comment on getReportListByNextToken) */ const getReportListAll = async (options = {}) =&gt; { let reports = []; const reportList = await getReportList(options); reports = reports.concat(reportList.result); let { nextToken } = reportList; /* eslint-disable no-await-in-loop */ while (nextToken) { const nextPage = await getReportListByNextToken({ NextToken: nextToken }); // eslint-disable-next-line prefer-destructuring nextToken = nextPage.nextToken; reports = reports.concat(nextPage.result); await sleep(2000); } /* eslint-enable no-await-in-loop */ return reports; }; // TODO: should we emit events notifying of things happening inside here? // TODO: need to test all report types with this function, because not all reports return // the same set of data - some are not giving a ReportRequestId for some reason?! // perhaps there was an error in requestReport() regarding this. // TODO: _GET_FLAT_FILE_ORDERS_DATA_ seems to always result in a cancelled report // TODO: _GET_FLAT_FILE_PENDING_ORDERS_DATA_ results in undefined reportRequestId // TODO: undefined reportRequestId results in us downloading a large list of reports // when we call getReportRequestList() // TODO: need to improve the throttling mechanism, waiting 45 seconds per test minimum sucks. // known to work if given a StartDate: _GET_FLAT_FILE_ORDERS_DATA_, _GET_AMAZON_FULFILLED_SHIPMENTS_DATA_ // known to require calling GetReportList (therefore not yet working): _GET_SELLER_FEEDBACK_DATA_ // _GET_AMAZON_FULFILLED_SHIPMENTS_DATA_ // // unsure why not working: _GET_FLAT_FILE_ACTIONABLE_ORDER_DATA_ - i may not have any data. // may require parameters? just cancells if not given parameters. // _GET_CONVERGED_FLAT_FILE_SOLD_LISTINGS_DATA_ // _GET_CONVERGED_FLAT_FILE_ORDER_REPORT_DATA_ // _GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_ // _GET_FLAT_FILE_ALL_RDERS_DATA_BY_ORDER_DATE_ // _GET_XML_ALL_ORDERS_DATA_BY_LAST_UPDATE_ // _GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_ // _GET_FLAT_FILE_PENDING_ORDERS_DATA_ - may also have failed due to not having any pending orders? // after I got to _GET_FLAT_FILE_PENDING_ORDERS_DATA_ .. getReportRequestList started throwing out // &quot;undefined&quot; as a status. wtf? // _GET_FLAT_FILE_ALL_ORDERS_DATA_BY_LAST_UPDATE_ // _GET_FLAT_FILE_ALL_ORDERS_DATA_BY_ORDER_DATE_ // _GET_XML_ALL_ORDERS_DATA_BY_LAST_UPDATE_ // _GET_XML_ALL_ORDERS_DATA_BY_ORDER_DATE_ /** * TODO: Document requestAndDownloadReport */ const requestAndDownloadReport = async (ReportType, file, reportParams = {}) =&gt; { async function checkReportComplete(reportRequestId) { console.log(`-- checking if report is complete ${reportRequestId}`); /* eslint-disable no-await-in-loop */ while (true) { const report = await getReportRequestList({ ReportRequestIdList: [reportRequestId], }); switch (report.ReportProcessingStatus) { case &apos;_IN_PROGRESS_&apos;: // fallthrough intentional case &apos;_SUBMITTED_&apos;: // fallthrough intentional console.log(`-- retrying report ${reportRequestId} in 45 sec`); await sleep(45000); // GetReportRequestList throttles to at most 10 requests, you get 1 back every 45 seconds break; case &apos;_CANCELLED_&apos;: console.log(`-- cancelled: ${reportRequestId}`, report); return { cancelled: true }; case &apos;_DONE_&apos;: return report; case &apos;_DONE_NO_DATA_&apos;: return null; default: console.log(`-- unknown status retry in 45 sec: ${report.ReportProcessingStatus}`, report); await sleep(45000); break; } } /* eslint-enable no-await-in-loop */ } console.log(`-- requesting report ${ReportType}`); const request = await requestReport({ ReportType, ...reportParams, }); const reportRequestId = request.ReportRequestId; await sleep(20000); // some requests may be available quickly, check after 20 sec const reportCheck = await checkReportComplete(reportRequestId); if (reportCheck.cancelled) { console.warn(&apos;******** report request cancelled by server&apos;, ReportType); throw new errors.RequestCancelled(&apos;Report cancelled by server&apos;); } let ReportId = reportCheck.GeneratedReportId; // When no ReportId is received, then call getReportList to find it. if (!ReportId) { const reportList = await getReportList({ ReportTypeList: [ReportType], }); ReportId = reportList[reportList.length - 1].ReportId; } const report = await getReport({ ReportId }); if (file) { await writeFile(file, JSON.stringify(report, null, 4)); } return report; }; module.exports = { getReport, getReportList, getReportListAll, getReportListByNextToken, getReportRequestList, requestAndDownloadReport, requestReport, }; </code></pre> </div> <footer class="footer"> Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.0.4)</span><img src="./image/esdoc-logo-mini-black.png"></a> </footer> <script src="script/search_index.js"></script> <script src="script/search.js"></script> <script src="script/pretty-print.js"></script> <script src="script/inherited-summary.js"></script> <script src="script/test-summary.js"></script> <script src="script/inner-link.js"></script> <script src="script/patch-for-local.js"></script> </body> </html>