new product defaults are set correctly

This commit is contained in:
Ben Miller
2024-11-17 06:57:03 -07:00
parent 475eee70ea
commit 5d0ae653fa
6 changed files with 253 additions and 75 deletions

7
package-lock.json generated
View File

@ -11,7 +11,7 @@
"@types/google-apps-script": "^1.0.85",
"gas-webpack-plugin": "^2.6.0",
"graphql-tag": "^2.12.6",
"shopify-admin-api-typings": "^1.2.2",
"shopify-admin-api-typings": "github:beepmill/shopify-admin-api-typings",
"ts-loader": "^9.5.1",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4"
@ -1474,9 +1474,8 @@
}
},
"node_modules/shopify-admin-api-typings": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/shopify-admin-api-typings/-/shopify-admin-api-typings-1.2.2.tgz",
"integrity": "sha512-n9NSBPBKX+TSfAr8ibpXKoGdHCUCY6WBKV2FhD9xvjGG3DIqqUylqhC3OXKiWcrTQuyb3WnaRCvl16i3uhJMiQ==",
"version": "2.0.0",
"resolved": "git+ssh://git@github.com/beepmill/shopify-admin-api-typings.git#e8ba51acff0a4e66c31ee61d62f5244ad4f4233a",
"dev": true,
"license": "MIT",
"peerDependencies": {

View File

@ -13,7 +13,7 @@
"@types/google-apps-script": "^1.0.85",
"gas-webpack-plugin": "^2.6.0",
"graphql-tag": "^2.12.6",
"shopify-admin-api-typings": "^1.2.2",
"shopify-admin-api-typings": "github:beepmill/shopify-admin-api-typings",
"ts-loader": "^9.5.1",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4"

View File

@ -2,6 +2,9 @@
"folders": [
{
"path": "."
},
{
"path": "../shopify-admin-api-typings"
}
],
"settings": {

View File

@ -30,7 +30,7 @@ export class Product {
type: string = ""
weight_grams: number = 0
photos: string = ""
shopify_product: ShopifyProduct
shopify_product: shopify.Product
shopify_default_variant_id: string = ""
shopify_default_option_id: string = ""
shopify_default_option_value_id: string = ""
@ -73,52 +73,17 @@ export class Product {
}
}
MatchToShopifyProduct(shop: Shop) {
/* if (this.shopify_id.startsWith("gid://shopify/Product/")) {
return
} */
let query = new ShopifyProductsQuery("sku:" + this.sku, ["id", "title"])
console.log(query.JSON)
let response = shop.shopifyGraphQLAPI(query.JSON)
console.log(response)
let productsResponse = new ShopifyProductsResponse(response.content)
if (productsResponse.products.edges.length <= 0) {
console.log("no products matched")
MatchToShopifyProduct(shop: Shop): shopify.Product {
let product = shop.GetProductBySku(this.sku)
if (product == undefined || product.id == undefined || product.id == "") {
console.log("MatchToShopifyProduct: no product matched")
return
}
if (productsResponse.products.edges.length > 1) {
console.log("more than one product matched")
return
}
this.shopify_product = productsResponse.products.edges[0].node
this.shopify_product = product
this.shopify_id = this.shopify_product.id.toString()
this.shopify_default_variant_id =
productsResponse.products.edges[0].node.variants.nodes[0].id
console.log(JSON.stringify(productsResponse, null, 2))
console.log(JSON.stringify(productsResponse.products, null, 2))
console.log(JSON.stringify(productsResponse.products.edges[0], null, 2))
console.log(
JSON.stringify(productsResponse.products.edges[0].node, null, 2)
)
console.log(
JSON.stringify(
productsResponse.products.edges[0].node.options[0],
null,
2
)
)
console.log(
JSON.stringify(
productsResponse.products.edges[0].node.options[0].id,
null,
2
)
)
this.shopify_default_option_id =
productsResponse.products.edges[0].node.options[0].id
this.shopify_default_option_value_id =
productsResponse.products.edges[0].node.options[0].optionValues[0].id
this.shopify_default_variant_id = product.variants.nodes[0].id
this.shopify_default_option_id = product.options[0].id
this.shopify_default_option_value_id = product.options[0].optionValues[0].id
let productInventorySheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("product_inventory")
let row = getRowByColumnValue("product_inventory", "sku", this.sku)
@ -134,7 +99,7 @@ export class Product {
if (this.shopify_id != "") {
sps.id = this.shopify_id
}
if (this.shopify_status.match('DRAFT|ACTIVE|ARCHIVED')) {
if (this.shopify_status.match("DRAFT|ACTIVE|ARCHIVED")) {
sps.status = this.shopify_status
}
sps.productType = this.product_type
@ -151,26 +116,50 @@ export class Product {
variant.price = this.price
sps.variants.push(variant)
console.log("ToShopifyProductSet:\n" + JSON.stringify(sps, null, 2))
//TODO: add sales channels
//TODO: add initial inventory
return sps
}
UpdateShopifyProduct(shop: Shop) {
console.log("UpdateShopifyProduct()")
var newProduct = false
let config = new Config()
this.MatchToShopifyProduct(shop)
if (this.shopify_id == "") {
console.log(
"UpdateShopifyProduct: no product matched, this will be a new product"
)
newProduct = true
}
console.log("UpdateShopifyProduct: calling productSet")
let sps = this.ToShopifyProductSet()
console.log("sps: " + JSON.stringify(sps))
let query = new ShopifyProductSetQuery(sps)
console.log(JSON.stringify(query))
let response = shop.shopifyGraphQLAPI(query.JSON)
console.log(JSON.stringify(response, null, 2))
this.MatchToShopifyProduct(shop)
let product = response.content.data.productSet.product
this.shopify_id = product.id
if (newProduct) {
console.log("UpdateShopifyProduct: setting defaults on new product")
let item: shopify.InventoryItem
do {
console.log("UpdateShopifyProduct: attempting to get inventory item")
item = shop.GetInventoryItemBySku(this.sku)
} while (item.id == "")
console.log("UpdateShopifyProduct: setting defaults on inventory item")
shop.SetInventoryItemDefaults(item, config)
console.log("UpdateShopifyProduct: publishing to online store")
response = this.PublishToShopifyOnlineStore(shop)
this.MatchToShopifyProduct(shop)
console.log("UpdateShopifyProduct: adjusting inventory item quantity")
shop.UpdateInventoryItemQuantity(item, 1, config)
console.log(JSON.stringify(response, null, 2))
}
// Update to include new changes
console.log("UpdateShopifyProduct: updating inventory match")
this.MatchToShopifyProduct(shop)
}
PublishToShopifyOnlineStore(shop: Shop) {
console.log("PublishToShopifyOnlineStore")
let config = new Config()
let query = /* GraphQL */ `
mutation publishablePublish($id: ID!, $input: [PublicationInput!]!) {
@ -191,12 +180,13 @@ export class Product {
message
}
}
}`
let variables = {
"id": this.shopify_id,
"input": {
"publicationId": config.shopifyStorePublicationId
}
`
let variables = {
id: this.shopify_id,
input: {
publicationId: config.shopifyStorePublicationId,
},
}
let j = `{
"query": ${formatGqlForJSON(String(query))},

View File

@ -7,7 +7,9 @@ export class Config {
shopifyAdminApiAccessToken: string
shopifyApiURI: string
shopifyStorePublicationId: string
shopifyLocationId: string
shopifyCountryCodeOfOrigin: string
shopifyProvinceCodeOfOrigin: string
constructor() {
let ss = SpreadsheetApp.getActive()
@ -49,5 +51,23 @@ export class Config {
"shopifyStorePublicationId",
"value"
)
this.shopifyLocationId = vlookupByColumns(
"vars",
"key",
"shopifyLocationId",
"value"
)
this.shopifyCountryCodeOfOrigin = vlookupByColumns(
"vars",
"key",
"shopifyCountryCodeOfOrigin",
"value"
)
this.shopifyProvinceCodeOfOrigin = vlookupByColumns(
"vars",
"key",
"shopifyProvinceCodeOfOrigin",
"value"
)
}
}

View File

@ -517,6 +517,160 @@ export class Shop {
} while (!done)
}
GetProductBySku(sku: string) {
console.log("GetProductBySku('" + sku + "')")
let gql = /* GraphQL */ `
query productBySku {
products(first: 1, query: "sku:${sku}") {
edges {
node {
id
title
handle
variants(first: 1) {
nodes {
id
sku
}
}
options {
id
name
optionValues {
id
name
}
}
}
}
}
}
`
let query = buildGqlQuery(gql, {})
let response = this.shopifyGraphQLAPI(query)
if (response.content.data.products.edges.length <= 0) {
console.log("GetProductBySku: no product matched")
return
}
let product = response.content.data.products.edges[0].node
console.log("Product found:\n" + JSON.stringify(product, null, 2))
return product
}
GetInventoryItemBySku(sku: string) {
console.log('GetInventoryItemBySku("' + sku + '")')
let gql = /* GraphQL */ `
query inventoryItems {
inventoryItems(first:1, query:"sku:${sku}") {
edges {
node {
id
tracked
sku
}
}
}
}
`
let query = buildGqlQuery(gql, {})
let response = this.shopifyGraphQLAPI(query)
let item: shopify.InventoryItem =
response.content.data.inventoryItems.edges[0].node
console.log(
"GetInventoryItemBySku: found item:\n" + JSON.stringify(item, null, 2)
)
return item
}
UpdateInventoryItemQuantity(
item: shopify.InventoryItem,
delta: number = 1,
config: Config
) {
console.log("UpdateInventoryItemQuantity(" + JSON.stringify(item) + ")")
let gql = /* GraphQL */ `
mutation inventoryAdjustQuantities(
$input: InventoryAdjustQuantitiesInput!
) {
inventoryAdjustQuantities(input: $input) {
userErrors {
field
message
}
inventoryAdjustmentGroup {
createdAt
reason
referenceDocumentUri
changes {
name
delta
}
}
}
}
`
let variables = {
input: {
reason: "correction",
name: "available",
changes: [
{
delta: delta,
inventoryItemId: item.id,
locationId: config.shopifyLocationId,
},
],
},
}
let query = buildGqlQuery(gql, variables)
let response = this.shopifyGraphQLAPI(query)
let newItem: shopify.InventoryItem = response.content
console.log("new item:\n" + JSON.stringify(newItem, null, 2))
return newItem
}
SetInventoryItemDefaults(item: shopify.InventoryItem, config: Config) {
let gql = /* GraphQL */ `
mutation inventoryItemUpdate($id: ID!, $input: InventoryItemInput!) {
inventoryItemUpdate(id: $id, input: $input) {
inventoryItem {
id
unitCost {
amount
}
tracked
countryCodeOfOrigin
provinceCodeOfOrigin
harmonizedSystemCode
countryHarmonizedSystemCodes(first: 1) {
edges {
node {
harmonizedSystemCode
countryCode
}
}
}
}
userErrors {
message
}
}
}
`
let variables = {
id: item.id,
input: {
tracked: true,
countryCodeOfOrigin: config.shopifyCountryCodeOfOrigin,
provinceCodeOfOrigin: config.shopifyProvinceCodeOfOrigin,
},
}
let query = buildGqlQuery(gql, variables)
let response = this.shopifyGraphQLAPI(query)
let newItem: shopify.InventoryItem = response.content
return newItem
}
shopifyAPI(endpoint: string, query: {}, next = "") {
var options: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
method: "get",
@ -541,6 +695,7 @@ export class Shop {
}
shopifyGraphQLAPI(query: {}, next = "") {
console.log("shopifyGraphQLAPI:query: " + JSON.stringify(query))
let endpoint = Shop.endpoints.graphql
let options: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
method: "post",
@ -552,10 +707,13 @@ export class Shop {
muteHttpExceptions: true,
}
var url = this.buildURL(endpoint)
console.log(UrlFetchApp.getRequest(url, options))
console.log(
"shopifyGraphQLAPI sending request:\n" +
JSON.stringify(UrlFetchApp.getRequest(url, options), null, 2)
)
var resp = UrlFetchApp.fetch(url, options)
let content = resp.getContentText()
console.log(content)
console.log("shopifyGraphQLAPI got response:\n" + content)
let content_json = JSON.parse(content)
console.log(JSON.stringify(content_json, null, 2))
@ -737,8 +895,8 @@ export class ShopifyVariant {
optionValues: [{}] = [
{
optionName: "Title",
name: "Default Title"
}
name: "Default Title",
},
]
}
@ -756,7 +914,7 @@ export class ShopifyProductsQuery {
query: string = "",
fields: string[] = ["id", "title", "handle"],
cursor: string = "",
pageSize: number = 10,
pageSize: number = 10
) {
let cursorText: string
if (cursor == "") {
@ -838,7 +996,8 @@ export class ShopifyProductSetQuery {
let j = `{
"query": ${formatGqlForJSON(String(this.GQL))},
"variables": {
"productSet": ${JSON.stringify(product)}
"productSet": ${JSON.stringify(product)},
"synchronous": ${synchronous}
}
}`
console.log(j)
@ -862,9 +1021,9 @@ export class ShopifyProductSetInput {
{
name: "Title",
values: {
name: "Default Title"
}
}
name: "Default Title",
},
},
]
}
@ -904,4 +1063,11 @@ export function getShopifyProducts() {
shop.GetProducts()
}
(global as any)
export function buildGqlQuery(gql: string, variables: {}) {
let query = `{
"query": ${formatGqlForJSON(String(gql))},
"variables": ${JSON.stringify(variables)}
}`
console.log("buildGqlQuery:\n" + query)
return JSON.parse(query)
}