UNPKG

@gameroom/cli

Version:

A command line tool for Gameroom

146 lines (144 loc) 6.91 kB
const cosmetic = require('cosmetic'), { models: { Price, Product, Unit } } = require('@gameroom/kit'), { grGreen } = require('../../../helpers'), { ShopifyV2 } = require('../../../models'), { config, spinner } = require('../../../refs'), LIMIT = 500 module.exports = async ({ containers, stores, verbose }) => { // Gameroom units >> Shopify inventory levels // date filter let filter if (config.shopify_unit_sync) { const date = new Date(config.shopify_unit_sync) spinner.info(`last unit sync ${date.toLocaleString()}`) // just in case... // date.setTime(date.getTime() - 1) filter = { key: 'updated_at', comparison: '>', value: date } } else { spinner.info(`first unit sync`) } // Get updated units and add or update or remove them on shopify let offset = 0, done = false, processed = {}, prices = {} // update shopify let added = 0, removed = 0, skipped = 0, updated = 0, current = 0, total = 0 spinner.text = `0 / 0 processed, 0 ${cosmetic.green('added')}, 0 ${cosmetic.red('removed')}, 0 ${cosmetic.yellow('updated')}, 0 skipped, 0 not offered` while (!done) { if (config.should_exit) break // get batch of units const units = await Unit.get({ filter, limit: LIMIT, offset, sort: [{ updated_at: 1 }] }) done = units.length === 0 offset += units.length total += units.length if (verbose) spinner.info(`got ${units.length} ${grGreen('units')}`) // iterate through batch for (let [i, unit] of units.entries()) { try { spinner.text = `${current} / ${total} processed, ${added} ${cosmetic.green('added')}, ${removed} ${cosmetic.red('removed')}, ${updated} ${cosmetic.yellow('updated')}, ${skipped} skipped` current++ if (config.should_exit) break if (verbose) spinner.info(`syncing gameroom ${grGreen('unit')} ${unit.id}`) // snapshot unit properties const { properties: { shopify_id }, updated_at } = unit // check updated_at if (updated_at.equals(processed[unit.id])) { config.shopify_unit_sync = new Date(updated_at * 1000) if (verbose) spinner.succeed(`already processed ${grGreen('unit')}`) skipped++ continue } // get store and container const store = stores.find(s => s.id === unit.store_id) const container = containers.find(s => s.id === unit.container_id) // shopifyable checks if (verbose) { if (!store) spinner.warn(`missing ${cosmetic.green('store')}`) if (!store?.shopify_id) spinner.warn(`missing ${cosmetic.green('location')}`) if (!container) spinner.warn(`missing ${cosmetic.green('container')}`) if (!unit.product_id) spinner.warn(`missing ${grGreen('product')}`) if (!unit.price_id) spinner.warn(`missing ${grGreen('price')}`) // if (!unit.image) spinner.warn(`missing ${grGreen('image')}`) } // get shopify inventory level let shopify_inventory = shopify_id ? await ShopifyV2.Variant.getWithId(shopify_id) : null // // conditions const shopifyable = store?.offered && store?.shopify_id && container?.offered && unit.offered && unit.quantity > 0 const add = !shopify_inventory && shopifyable const remove = shopify_inventory && !shopifyable const update = shopify_inventory && shopifyable if (add) { // get gameroom price const price = prices[unit.price_id] || await Price.find(unit.price_id) if (price) prices[price.id] = price if (!price) throw new Error('price not found') if (price.amount <= 0) { // will be removed at the product level config.shopify_unit_sync = new Date(updated_at * 1000) if (verbose) spinner.warn(`skipping ${grGreen('unit')}`) skipped++ continue } // create shopify inventory shopify_inventory = await ShopifyV2.Inventory.fromUnitAndPriceAndStore(unit, price, store) shopify_inventory = await shopify_inventory.save() unit.properties.shopify_id = shopify_inventory.id if (verbose) spinner.info(`created shopify ${cosmetic.green('inventory')}`) added++ } else if (remove) { // delete shopify inventory await ShopifyV2.Inventory.delete(shopify_id) shopify_inventory = null if (verbose) spinner.info(`removed shopify ${cosmetic.green('inventory')}`) removed++ } else if (update) { // get gameroom price // update inventory location // update inventory price // update images? // const price = prices[unit.price_id] || await Price.find(unit.price_id) // if (price) prices[price.id] = price // if (!price) throw new Error('price not found') // if (price.amount <= 0) { // // will be removed at the product level // config.shopify_unit_sync = new Date(updated_at * 1000) // if (verbose) spinner.warn(`skipping ${grGreen('unit')}`) // skipped++ // continue // } // update shopify inventory shopify_inventory = await shopify_inventory.updateFromUnitAndStore(unit) if (verbose) spinner.info(`updated shopify ${cosmetic.green('inventory')}`) updated++ } else { // not offered and not shopified, no action necessary config.shopify_unit_sync = new Date(updated_at * 1000) if (verbose) spinner.succeed(`skipping ${grGreen('unit')}`) skipped++ continue } // update shopify id if (shopify_inventory) { unit.properties.shopify_id = shopify_inventory.id } else { delete unit.properties.shopify_id } // update unit if need be if (unit.properties.shopify_id != shopify_id) { unit = await Unit.update({ id: unit.id, properties: unit.properties }) if (verbose) spinner.info(`updated gameroom ${grGreen('unit')}`) // updated units go to the end of the pagination line and mess up the offset... offset-- } config.shopify_unit_sync = new Date(updated_at * 1000) processed[unit.id] = unit.updated_at if (verbose) spinner.succeed(`synced ${grGreen('unit')}`) } catch (err) { skipped++ // if verbose, the id has already been printed spinner.fail(`failed ${grGreen('unit')}${verbose ? '' : ` ${unit.id}`} ${err}`) return } } } spinner.succeed(`${total} processed, ${added} ${cosmetic.green('added')}, ${removed} ${cosmetic.red('removed')}, ${updated} ${cosmetic.yellow('updated')}, ${skipped} skipped`) spinner.succeed(`completed unit sync to ${cosmetic.green('shopify')} @ ${new Date().toLocaleString()}`) }