| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- import {
- activeAmazonShops, allRows, dateValue, forward, hash, log, regionByMarketplace,
- shopPointer, sleep, upsertMany, writeAudit,
- } from './sp-api-collector-lib.mjs';
- const shops = await activeAmazonShops();
- const listings = await allRows('Listing', 'asin,shop');
- const capturedAt = dateValue(new Date());
- for (const shop of shops) {
- const asins = [...new Set(listings
- .filter(item => item.shop?.objectId === shop.objectId && item.asin)
- .map(item => String(item.asin).trim().toUpperCase()))];
- let records = 0;
- let emptyResponses = 0;
- let failures = 0;
- const startedAt = new Date();
- for (const asin of asins) {
- const endpoints = [
- ['item_browse_node', `/customerFeedback/2024-06-01/items/${asin}/browseNode?marketplaceId=${shop.marketplaceId}`],
- ['item_review_topics', `/customerFeedback/2024-06-01/items/${asin}/reviews/topics?marketplaceId=${shop.marketplaceId}&sortBy=MENTIONS&sortOrder=DESC`],
- ['item_review_trends', `/customerFeedback/2024-06-01/items/${asin}/reviews/trends?marketplaceId=${shop.marketplaceId}`],
- ];
- for (const [feedbackType, endpoint] of endpoints) {
- try {
- const result = await forward(shop.objectId, endpoint, 'GET', undefined, 2);
- if (!result || Object.keys(result).length === 0) {
- emptyResponses++;
- continue;
- }
- const browseNodeId = String(result.browseNodeId || result.browseNode?.id || '');
- await upsertMany('AmazonCustomerFeedback', [{
- recordKey: `${shop.objectId}:${asin}:${feedbackType}`,
- marketplaceId: shop.marketplaceId,
- feedbackType,
- asin,
- browseNodeId,
- capturedAt,
- rawData: result,
- shop: shopPointer(shop.objectId),
- }]);
- records++;
- } catch (error) {
- failures++;
- log('feedback_failed', { shop: shop.name, asin, feedbackType, error: error.message });
- }
- await sleep(500);
- }
- }
- await writeAudit({
- dataType: 'customer_feedback', endpoint: '/customerFeedback/2024-06-01',
- status: failures ? 'partial' : 'completed', shop,
- region: regionByMarketplace[shop.marketplaceId] || 'UNKNOWN', marketplaceId: shop.marketplaceId,
- records, pages: asins.length * 3, error: failures ? `${failures} calls failed` : '',
- startedAt, details: { asins: asins.length, emptyResponses, failures },
- });
- log('feedback_completed', { shop: shop.name, asins: asins.length, records, emptyResponses, failures });
- }
- for (const shop of shops) {
- const startedAt = new Date();
- const statuses = ['WORKING', 'SHIPPED', 'RECEIVING', 'CLOSED', 'CANCELLED', 'DELETED', 'ERROR', 'IN_TRANSIT', 'DELIVERED', 'CHECKED_IN'];
- const after = new Date(Date.now() - 729 * 24 * 60 * 60 * 1000).toISOString();
- const before = new Date().toISOString();
- let token = '';
- let pages = 0;
- let records = 0;
- const seenTokens = new Set();
- try {
- do {
- pages++;
- const path = token
- ? `/fba/inbound/v0/shipments?QueryType=NEXT_TOKEN&MarketplaceId=${shop.marketplaceId}&NextToken=${encodeURIComponent(token)}`
- : `/fba/inbound/v0/shipments?QueryType=DATE_RANGE&MarketplaceId=${shop.marketplaceId}`
- + `&ShipmentStatusList=${statuses.join(',')}`
- + `&LastUpdatedAfter=${encodeURIComponent(after)}&LastUpdatedBefore=${encodeURIComponent(before)}`;
- const result = await forward(shop.objectId, path, 'GET', undefined, 2);
- const payload = result.payload || result;
- const shipments = payload.ShipmentData || payload.shipments || [];
- const rows = shipments.map(item => ({
- recordKey: `${regionByMarketplace[shop.marketplaceId] || 'UNKNOWN'}:${item.ShipmentId || hash(item)}`,
- region: regionByMarketplace[shop.marketplaceId] || 'UNKNOWN',
- marketplaceId: shop.marketplaceId,
- shipmentId: item.ShipmentId || '',
- shipmentName: item.ShipmentName || '',
- shipmentStatus: item.ShipmentStatus || '',
- destinationFulfillmentCenterId: item.DestinationFulfillmentCenterId || '',
- labelPrepType: item.LabelPrepType || '',
- capturedAt,
- rawData: item,
- shop: shopPointer(shop.objectId),
- }));
- await upsertMany('AmazonInboundShipment', rows);
- records += rows.length;
- token = String(payload.NextToken || '').trim();
- if (token) {
- if (seenTokens.has(token)) throw new Error('Repeated inbound NextToken');
- seenTokens.add(token);
- await sleep(1200);
- }
- } while (token);
- await writeAudit({
- dataType: 'inbound_shipments', endpoint: '/fba/inbound/v0/shipments',
- status: 'completed', shop, region: regionByMarketplace[shop.marketplaceId] || 'UNKNOWN',
- marketplaceId: shop.marketplaceId, records, pages, startedAt, details: { after, before },
- });
- log('inbound_completed', { shop: shop.name, records, pages });
- } catch (error) {
- await writeAudit({
- dataType: 'inbound_shipments', endpoint: '/fba/inbound/v0/shipments',
- status: records ? 'partial' : 'failed', shop, region: regionByMarketplace[shop.marketplaceId] || 'UNKNOWN',
- marketplaceId: shop.marketplaceId, records, pages, error: error.message, startedAt,
- });
- log('inbound_failed', { shop: shop.name, records, pages, error: error.message });
- }
- }
|