From ca48bb657264ba17e940852ec360f92269c801cb Mon Sep 17 00:00:00 2001 From: Ben Miller Date: Thu, 14 Nov 2024 08:36:08 -0700 Subject: [PATCH] a little bit farther --- src/Product.ts | 66 ++++++++++++++++---- src/shopifyApi.ts | 155 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 174 insertions(+), 47 deletions(-) diff --git a/src/Product.ts b/src/Product.ts index f752b5b..c330eed 100644 --- a/src/Product.ts +++ b/src/Product.ts @@ -1,8 +1,16 @@ // prettier-ignore -import { Shop, ShopifyProduct, ShopifyProductsQuery, ShopifyProductsResponse, ShopifyProductSetInput, ShopifyProductVariant } from "./shopifyApi" +import { + Shop, + ShopifyProduct, + ShopifyProductsQuery, + ShopifyProductsResponse, + ShopifyProductSetInput, + ShopifyVariant, + ShopifyProductSetQuery, + VariantOptionValueInput, +} from "./shopifyApi" import { getCellRangeByColumnName, getRowByColumnValue } from "./sheetUtils" - export class Product { shopify_id: string = "" title: string = "" @@ -19,6 +27,9 @@ export class Product { weight_grams: number = 0 photos: string = "" shopify_product: ShopifyProduct + shopify_default_variant_id: string + shopify_default_option_id: string + shopify_default_option_value_id: string constructor(sku: string = "") { if (sku == "") { @@ -58,14 +69,11 @@ export class Product { } MatchToShopifyProduct(shop: Shop) { - if (this.shopify_id.startsWith("gid://shopify/Product/")) { + /* if (this.shopify_id.startsWith("gid://shopify/Product/")) { return - } + } */ - let query = new ShopifyProductsQuery( - "sku:" + this.sku, - ["id", "title"] - ) + let query = new ShopifyProductsQuery("sku:" + this.sku, ["id", "title"]) console.log(query.JSON) let response = shop.shopifyGraphQLAPI(query.JSON) console.log(response) @@ -80,6 +88,32 @@ export class Product { } this.shopify_product = productsResponse.products.edges[0].node 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 let productInventorySheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("product_inventory") let row = getRowByColumnValue("product_inventory", "sku", this.sku) @@ -90,24 +124,32 @@ export class Product { ToShopifyProductSet() { let sps = new ShopifyProductSetInput() - sps.category = this.category + //TODO: map category IDs + //sps.category = this.category sps.id = this.shopify_id sps.productType = this.product_type sps.tags = this.tags sps.title = this.title sps.descriptionHtml = this.description sps.variants = [] - let variant = new ShopifyProductVariant() - variant.id = 1 + let variant = new ShopifyVariant() + //TODO: handle multiple variants + variant.id = this.shopify_default_variant_id variant.sku = this.sku variant.price = this.price - variant.weight = this.weight_grams sps.variants.push(variant) + let opt = new ShopifyVa + let options = new VariantOptionValueInput() + options.id = this.shopify_default_option_value_id return sps } UpdateShopifyProduct(shop: Shop) { 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)) } } diff --git a/src/shopifyApi.ts b/src/shopifyApi.ts index 425c83a..7cc41b1 100644 --- a/src/shopifyApi.ts +++ b/src/shopifyApi.ts @@ -552,10 +552,13 @@ export class Shop { var url = this.buildURL(endpoint) console.log(UrlFetchApp.getRequest(url, options)) var resp = UrlFetchApp.fetch(url, options) - console.log(resp.getContentText()) + let content = resp.getContentText() + console.log(content) + let content_json = JSON.parse(content) + console.log(JSON.stringify(content_json, null, 2)) return { - content: JSON.parse(resp.getContentText()), + content: content_json, headers: resp.getHeaders(), } } @@ -614,7 +617,7 @@ export class ShopifyProduct { body_html: string created_at: Date handle: string - id: number + id: string images: ProductImage[] options: ProductOption[] product_type: string @@ -625,10 +628,14 @@ export class ShopifyProduct { template_suffix: string title: string updated_at: Date - variants: ShopifyProductVariant[] + variants: ShopifyVariantNodes vendor: string } +export class ShopifyVariantNodes { + nodes: ShopifyProductVariant[] +} + class ProductImage { id: number product_id: number @@ -642,11 +649,25 @@ class ProductImage { } class ProductOption { - id: number + id: string product_id: number name: string position: number values: string[] + optionValues?: ShopifyProductOptionValues +} + +export class ShopifyProductOptionValues { + id?: string + name?: string +} + +export class ShopifyVariantOptionValueInput { + id?: string + linkedMetafieldValue?: string + name?: string + optionId?: string + optionName?: string } export class ShopifyProductVariant { @@ -657,7 +678,7 @@ export class ShopifyProductVariant { grams: number weight: number weight_unit: string - id: number + id: string inventory_item_id: number inventory_management: string inventory_policy: string @@ -680,9 +701,39 @@ class Products { class ProductEdge { node: ShopifyProduct + variants?: ShopifyVariants + options?: ShopifyProductOption[] cursor: string } +export class ShopifyProductOption { + id?: string + name?: string + optionValues?: ShopifyProductOptionValue[] + values?: ShopifyProductOptionValue[] +} + +export class ShopifyProductOptionValue { + id?: string + name?: string +} + +export class ShopifyVariants { + nodes?: ShopifyVariant[] + node?: ShopifyVariant +} + +export class ShopifyVariant { + id?: string + sku?: string + price?: number + compareAtPrice?: number + barcode?: string + position?: number + nodes?: ShopifyProductVariant[] + optionValues?: VariantOptionValueInput[] +} + class PageInfo { hasNextPage: boolean hasPreviousPage: boolean @@ -714,7 +765,22 @@ export class ShopifyProductsQuery { this.GQL = `{ products(first: ${pageSize}${cursorText}${queryText}) { edges { - node { ${fields.join(" ")} } + node { + ${fields.join(" ")} + variants(first:1) { + nodes { + id + } + } + options { + id + name + optionValues { + id + name + } + } + } } pageInfo { hasNextPage @@ -736,38 +802,35 @@ export class ShopifyProductsResponse { } export class ShopifyProductSetQuery { - GQL: string - JSON: JSON - constructor( - query: string = "", - fields: string[] = ["id", "title", "handle"], - cursor: string = "", - pageSize: number = 10 - ) { - let cursorText: string - if (cursor == "") { - cursorText = "" - } else { - cursorText = `, after: "${cursor}"` + GQL: string = `mutation setProduct($productSet: ProductSetInput!) { + productSet(input: $productSet) { + product { + id } - let queryText: string - if (query == "") { - queryText = "" - } else { - queryText = `, query: "${query}"` + productSetOperation { + id + status + userErrors { + code + field + message + } } - this.GQL = `{ - products(first: ${pageSize}${cursorText}${queryText}) { - edges { - node { ${fields.join(" ")} } - } - pageInfo { - hasNextPage - endCursor + userErrors { + code + field + message } } }` - let j = `{"query": ${formatGqlForJSON(this.GQL)}}` + JSON: JSON + constructor(product: ShopifyProductSetInput, synchronous: boolean = true) { + let j = `{ + "query": ${formatGqlForJSON(this.GQL)}, + "variables": { + "productSet": ${JSON.stringify(product)} + } + }` console.log(j) this.JSON = JSON.parse(j) } @@ -782,8 +845,30 @@ export class ShopifyProductSetInput { status: string = "DRAFT" tags: string title: string - variants: ShopifyProductVariant[] vendor: string + variants: ShopifyVariant[] + productOptions: ShopifyProductOption[] +} + +export class ProductVariantSetInput { + barcode: string + compareAtPrice: number + id: string + optionValues: VariantOptionValueInput[] = [] + position?: number + price?: number + requiresComponents?: boolean + sku?: string + taxable?: boolean + taxCode?: string +} + +export class VariantOptionValueInput { + id?: string + linkedMetafieldValue?: string + name?: string + optionId?: string + optionName?: string } function formatGqlForJSON(gql: string) {