dedupe-sp-api-classes.mjs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import {
  2. allRows, parseRequest, regionByMarketplace, shopPointer,
  3. } from './sp-api-collector-lib.mjs';
  4. async function batch(requests) {
  5. for (let start = 0; start < requests.length; start += 25) {
  6. const result = await parseRequest('/batch', 'POST', { requests: requests.slice(start, start + 25) });
  7. const error = result.find?.(item => item.error)?.error;
  8. if (error) throw new Error(error.error || error.code || 'Parse batch failed');
  9. }
  10. }
  11. async function dedupeRecordKeys(className) {
  12. const rows = await allRows(className, 'objectId,recordKey');
  13. const seen = new Set();
  14. const deletes = [];
  15. for (const row of rows) {
  16. if (!row.recordKey || seen.has(row.recordKey)) {
  17. deletes.push({ method: 'DELETE', path: `/parse/classes/${className}/${row.objectId}` });
  18. } else {
  19. seen.add(row.recordKey);
  20. }
  21. }
  22. await batch(deletes);
  23. return { before: rows.length, deleted: deletes.length, after: rows.length - deletes.length };
  24. }
  25. const shops = await allRows('Shop', 'objectId,marketplaceId');
  26. const shopById = new Map(shops.map(shop => [shop.objectId, shop]));
  27. const shipments = await allRows('AmazonInboundShipment');
  28. const groups = new Map();
  29. for (const row of shipments) {
  30. const shop = shopById.get(row.shop?.objectId);
  31. const region = row.region || regionByMarketplace[shop?.marketplaceId] || 'UNKNOWN';
  32. const businessKey = `${region}:${row.shipmentId || row.recordKey || row.objectId}`;
  33. if (!groups.has(businessKey)) groups.set(businessKey, []);
  34. groups.get(businessKey).push({ ...row, region });
  35. }
  36. const shipmentUpdates = [];
  37. const shipmentDeletes = [];
  38. for (const [recordKey, rows] of groups) {
  39. const keep = rows[0];
  40. shipmentUpdates.push({
  41. method: 'PUT',
  42. path: `/parse/classes/AmazonInboundShipment/${keep.objectId}`,
  43. body: { recordKey, region: keep.region },
  44. });
  45. for (const row of rows.slice(1)) {
  46. shipmentDeletes.push({ method: 'DELETE', path: `/parse/classes/AmazonInboundShipment/${row.objectId}` });
  47. }
  48. }
  49. await batch(shipmentUpdates);
  50. await batch(shipmentDeletes);
  51. const results = {
  52. AmazonInboundShipment: {
  53. before: shipments.length,
  54. uniqueShipments: groups.size,
  55. deleted: shipmentDeletes.length,
  56. after: groups.size,
  57. },
  58. };
  59. for (const className of [
  60. 'SpApiSellerAccount', 'SpApiMarketplaceParticipation', 'AmazonInventorySummary',
  61. 'AmazonSalesMetric', 'AmazonCatalogItem', 'AmazonProductPricing', 'AmazonOrderItem',
  62. 'AmazonFinancialEvent', 'AmazonCustomerFeedback', 'AmazonReportRow',
  63. ]) {
  64. results[className] = await dedupeRecordKeys(className);
  65. }
  66. console.log(JSON.stringify(results, null, 2));