feat: medusa-source-shopify loader (#563)

* added statuses to product + unit test for updating status

* add update to product model

* added integration tests

* added integration test to validate that updating status to null results in invalid_data error

* removed comment

* update GET /store/products integration test

* fixed unit test with IdMap

* init plugin

* changed dbehaviour on invalid status input on admin list products

* mprices

* updated migration to add status = published on all existing products + added integration test on GET /admin/products when status null is provided

* merged product status

* init ShopifyService

* made requested changes to migration and GET /store/products

* fixed test

* made requested changes to migration

* push progress on source plugin

* add webhook product/create handler

* fixed normalization of variant weight

* removed weight func

* work on events

* finished product hooks (error on new variant needs to be fixed)

* fixed order status

* create fulfillments

* update fulfillment on cancel

* refactored services, handle returns though medusa, helper methods

* order updates

* removed dist

* update gitignore

* emit cahnges to product

* added redis ignore check to prevent update loops

* fixed product-variant.deleted event

* fix more events

* fix test

* fix: order taxes

* added refund with no items

* fixes to hooks

* fixed handling refunds and returns issued from Shopify

* added unit tests to ShopifyProductService and ShopifyCollectionService

* linting fix

* prepared loader PR

* fix: jsDocs

* fix: pager

* fix: build output and babelrc

* chore: linting

* fix: address type

* fix: migration clean up

* fix: update snapshots with ext_ids

Co-authored-by: Sebastian Rindom <skrindom@gmail.com>
This commit is contained in:
Kasper Fabricius Kristensen
2021-12-08 10:09:21 +01:00
committed by GitHub
co-authored by Sebastian Rindom
parent f2ba4018fc
commit 577bcc23d4
46 changed files with 7857 additions and 61 deletions
@@ -0,0 +1,13 @@
export function buildQuery(query) {
let path = ""
if (query) {
const queryString = Object.entries(query).map(([key, value]) => {
return `${key}=${value}`
})
path = `?${queryString.join("&")}`
}
return path
}
@@ -0,0 +1,5 @@
export const INCLUDE_PRESENTMENT_PRICES = {
"X-Shopify-Api-Features": "include-presentment-prices",
}
export const IGNORE_THRESHOLD = 2
@@ -0,0 +1,7 @@
import Shopify from "@shopify/shopify-api"
export const createClient = (options) => {
const { domain, password } = options
return new Shopify.Clients.Rest(`${domain}.myshopify.com`, password)
}
@@ -0,0 +1,46 @@
export async function pager(
client,
path,
extraHeaders = null,
extraQuery = {}
) {
let objects = []
let nextPage = null
let hasNext = true
while (hasNext) {
const params = {
path,
query: { page_info: nextPage },
}
if (extraHeaders) {
Object.assign(params, { extraHeaders: extraHeaders })
}
if (extraQuery) {
Object.assign(params.query, extraQuery)
}
if (!params.query.page_info) {
delete params.query.page_info
}
const response = await client.get(params)
objects = [...objects, ...response.body[path]]
const link = response.headers.get("link")
const match =
/(?:page_info=)(?<page_info>[a-zA-Z0-9]+)(?:>; rel="next")/.exec(link)
if (match?.groups) {
nextPage = match.groups["page_info"]
hasNext = true
} else {
hasNext = false
}
}
return objects
}
@@ -0,0 +1,3 @@
export function parsePrice(price) {
return parseInt(Number(price).toFixed(2) * 100)
}
@@ -0,0 +1,4 @@
export function removeIndex(arr, obj) {
const index = arr.indexOf(obj)
arr.splice(index, 1)
}