| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- const parseUrl = process.env.PARSE_URL || 'http://127.0.0.1:3000/parse';
- const appId = process.env.PARSE_APP_ID;
- const masterKey = process.env.PARSE_MASTER_KEY;
- const fallbackShopId = process.env.FALLBACK_SHOP_ID;
- if (!appId || !masterKey || !fallbackShopId) {
- throw new Error('Missing PARSE_APP_ID, PARSE_MASTER_KEY, or FALLBACK_SHOP_ID');
- }
- const headers = {
- 'Content-Type': 'application/json',
- 'X-Parse-Application-Id': appId,
- 'X-Parse-Master-Key': masterKey,
- };
- const shopPointer = objectId => ({ __type: 'Pointer', className: 'Shop', objectId });
- async function request(path, method = 'GET', body) {
- const response = await fetch(`${parseUrl}${path}`, {
- method,
- headers,
- body: body === undefined ? undefined : JSON.stringify(body),
- });
- const text = await response.text();
- let result = {};
- try { result = JSON.parse(text); } catch {}
- if (!response.ok || result.error) {
- throw new Error(`${method} ${path}: ${result.error?.message || result.error || text.slice(0, 300) || response.status}`);
- }
- return result;
- }
- async function allRows(className, keys = '') {
- const rows = [];
- let skip = 0;
- while (true) {
- const page = await request(`/classes/${className}?limit=1000&skip=${skip}${keys ? `&keys=${keys}` : ''}`);
- rows.push(...(page.results || []));
- const length = page.results?.length || 0;
- if (length < 1000) return rows;
- skip += length;
- }
- }
- async function batch(requests) {
- for (let start = 0; start < requests.length; start += 25) {
- const result = await request('/batch', 'POST', { requests: requests.slice(start, start + 25) });
- const error = result.find?.(item => item.error)?.error;
- if (error) throw new Error(error.error || error.code || 'Parse batch failed');
- }
- }
- function returnKey(row) {
- const date = row.return_date?.iso || row.returnDate?.iso || row.return_date || row.returnDate || '';
- const orderId = row.order_id || row.orderId || row.amazon_order_id || '';
- const sku = row.sku || row.seller_sku || '';
- return [date, orderId, sku, row.asin || '', row.license_plate_number || ''].join('|');
- }
- const [returns, orders] = await Promise.all([
- allRows('ReturnRecord'),
- allRows('Order', 'platformOrderId,orderId,shop'),
- ]);
- const orderShop = new Map();
- for (const order of orders) {
- for (const id of [order.platformOrderId, order.orderId]) {
- if (id && order.shop?.objectId) orderShop.set(id, order.shop.objectId);
- }
- }
- const groups = new Map();
- for (const row of returns) {
- const key = returnKey(row);
- if (!groups.has(key)) groups.set(key, []);
- groups.get(key).push(row);
- }
- const updates = [];
- const deletes = [];
- let matchedOrders = 0;
- for (const rows of groups.values()) {
- const orderId = rows[0].order_id || rows[0].orderId || rows[0].amazon_order_id || '';
- const targetShopId = orderShop.get(orderId) || fallbackShopId;
- if (orderShop.has(orderId)) matchedOrders++;
- const keep = rows.find(row => row.shop?.objectId === targetShopId) || rows[0];
- updates.push({
- method: 'PUT',
- path: `/parse/classes/ReturnRecord/${keep.objectId}`,
- body: {
- shop: shopPointer(targetShopId),
- orderId,
- returnDate: keep.returnDate || keep.return_date,
- asin: keep.asin || '',
- sku: keep.sku || keep.seller_sku || '',
- reason: keep.reason || '',
- quantity: Number(keep.quantity || 0),
- comment: keep.customer_comments || keep.comment || '',
- disposition: keep.detailed_disposition || keep.disposition || '',
- fulfillmentCenterId: keep.fulfillment_center_id || keep.fulfillmentCenterId || '',
- licensePlateNumber: keep.license_plate_number || keep.licensePlateNumber || '',
- },
- });
- for (const row of rows) {
- if (row.objectId === keep.objectId) continue;
- deletes.push({ method: 'DELETE', path: `/parse/classes/ReturnRecord/${row.objectId}` });
- }
- }
- await batch(updates);
- await batch(deletes);
- const after = await allRows('ReturnRecord', 'objectId,shop,orderId');
- console.log(JSON.stringify({
- before: returns.length,
- uniqueBusinessKeys: groups.size,
- matchedOrders,
- fallbackAssignments: groups.size - matchedOrders,
- updated: updates.length,
- deleted: deletes.length,
- after: after.length,
- }, null, 2));
|