Untitled
unknown
plain_text
a year ago
6.8 kB
12
Indexable
const dotenv = require('dotenv'); const Shopify = require('shopify-api-node'); const Bottleneck = require('bottleneck'); const cron = require('node-cron'); dotenv.config(); const INVENTORY_BUFFER = 2; const sourceShopify = new Shopify({ shopName: process.env.SOURCE_SHOP_NAME, accessToken: process.env.SOURCE_SHOPIFY_ACCESS_TOKEN, accessMode: 'private', apiVersion: '2021-07', scopes: ['read_inventory', 'read_products'] }); const destinationShopify = new Shopify({ shopName: process.env.DESTINATION_SHOP_NAME, accessToken: process.env.DESTINATION_SHOPIFY_ACCESS_TOKEN, accessMode: 'private', apiVersion: '2024-04', scopes: ['read_inventory', 'write_inventory', 'read_products', 'write_products'] }); sourceShopify.shop.get() .then(shop => { console.log('Connected to Source Shopify successfully.'); }) .catch(err => { console.error('Failed to connect to Source Shopify:', err); }); destinationShopify.shop.get() .then(shop => { console.log('Connected to Destination Shopify successfully.'); }) .catch(err => { console.error('Failed to connect to Destination Shopify:', err); }); // LIST IS ONLY FETCHING FIRST 50 PRODUCTS, ADD RATE LIMIT FOR SHOPIFY API // Function to fetch all source products inventory async function getAllProducts() { try { let params = { limit: 250 }; let allRecords = []; do { const products = await sourceShopify.product.list(params); allRecords = allRecords.concat(products) params = products.nextPageParameters; } while (params !== undefined); console.log(`${allRecords.length} products found in the source store.`); let allData = []; for(let product of allRecords){ let allVariants = product.variants.map( i => ({ id: product.id, title: product.title, SKU: i.sku, barcode: i.barcode, inventory: i.inventory_quantity > 0 ? i.inventory_quantity - INVENTORY_BUFFER : 0 })) allData = [...allData, ...allVariants] } return allData; } catch (error) { console.error('Failed to fetch products:', error); return []; } } async function getAllProductsFromDestination() { try { let params = { limit: 250 }; let allRecords = []; do { const products = await destinationShopify.product.list(params); allRecords = allRecords.concat(products) params = products.nextPageParameters; } while (params !== undefined); const allDestinationProducts = allRecords.filter(i => i.status === "active"); console.log(`${allDestinationProducts.length} active products found in the destination store.`); return allDestinationProducts; } catch (error) { console.error('Failed to fetch products:', error); return []; } } async function updateForMultipleLocation(productFromDestination, prod, inventoryList) { try { inventoryList.forEach(async i => { await destinationShopify.inventoryLevel.set({ inventory_item_id: productFromDestination.inventory_item_id, location_id: i.location_id, available: prod.inventory }) console.log(`Successfully updated for location ${i.location_id}`) }) } catch (err) { console.log(err); } } // UPDATE INVENTORY NOT WORKING // Function to update inventory in destination store async function updateDestinationStore(products) { try { // Fetch product list from the destination store const destinationProducts = await getAllProductsFromDestination(); for (const desProduct of destinationProducts) { let prod = {}; let prodBarcode = ''; const productFromDestination = desProduct.variants.find(i => products.some(p => { prodBarcode = p.barcode if (p?.barcode === i?.barcode) { prod = p; return true } }) ) // console.log(prod, "EXISTS", productFromDestination) if (productFromDestination) { const res = await destinationShopify.inventoryItem.get(productFromDestination.inventory_item_id) if (res.tracked) { const inventoryList = await destinationShopify.inventoryLevel.list({ inventory_item_ids: productFromDestination.inventory_item_id }) if (inventoryList.length > 1) { await updateForMultipleLocation(productFromDestination, prod, inventoryList); } else { const inventoryLocation = inventoryList[0].location_id; await destinationShopify.inventoryLevel.set({ inventory_item_id: productFromDestination.inventory_item_id, location_id: inventoryLocation, available: prod.inventory }) console.log(`Inventory updated for product ${productFromDestination.title} with barcode ${productFromDestination.barcode}`); } } else { console.error(`Tracking not enabled for the inventory item ${productFromDestination.inventory_item_id} with variant barcode ${productFromDestination.barcode}`) } } else { console.error(`No matching products found in source table ${prodBarcode ? "for barcode" + prodBarcode : "because barcode value is null"}`); } } } catch (error) { if (error.response && error.response.statusCode === 403) { console.error('Failed to update inventory in the destination store: You do not have permission to perform this action.'); } else { console.error(`Failed to update inventory for product with barcode in the destination store:`, error); } } } // Rate limiting configuration const limiter = new Bottleneck({ maxConcurrent: 1, // Number of concurrent requests minTime: 2000 // Minimum time between each request (in milliseconds) }); //Fetch products and update inventory with rate limiting function cronJobEveryHour(){ limiter.schedule(getAllProducts) .then(products => { console.table(products); return updateDestinationStore(products); }) .catch(error => { console.error('Error during product fetch or inventory update:', error); }); } cron.schedule('0 0 */1 * * *', cronJobEveryHour); cronJobEveryHour();
Editor is loading...
Leave a Comment