Created
September 10, 2025 19:59
-
-
Save andrewarrow/c75c7a3fedda9abb8fd1af142956acc9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package shopify | |
| import ( | |
| "fmt" | |
| ) | |
| // RemoveLineItemFromOrder removes a line item from an unfulfilled order using GraphQL Admin API | |
| func (c *Client) RemoveLineItemFromOrder(orderID uint64, lineItemID uint64) error { | |
| // Convert IDs to GraphQL format | |
| orderGID := c.BuildGraphqlId("Order", orderID) | |
| lineItemGID := c.BuildGraphqlId("LineItem", lineItemID) | |
| fmt.Printf("Starting order edit for order %d (GID: %s), lineItem: %s\n", orderID, orderGID, lineItemGID) | |
| // Step 1: Get the variant ID from the original line item | |
| variantID, err := c.getLineItemVariantID(orderGID, lineItemGID) | |
| if err != nil { | |
| return fmt.Errorf("failed to get line item variant: %w", err) | |
| } | |
| fmt.Printf("Line item variant ID: %s\n", variantID) | |
| // Step 2: Begin order edit and find the calculated line item ID by variant | |
| calculatedOrderID, calculatedLineItemID, err := c.beginOrderEditAndFindLineItemByVariant(orderGID, variantID) | |
| if err != nil { | |
| return fmt.Errorf("failed to begin order edit: %w", err) | |
| } | |
| fmt.Printf("Order edit begun, calculatedOrder ID: %s, calculatedLineItem ID: %s\n", calculatedOrderID, calculatedLineItemID) | |
| // Step 3: Set line item quantity to 0 | |
| err = c.setLineItemQuantityWithCalculatedID(calculatedOrderID, calculatedLineItemID, 0) | |
| if err != nil { | |
| return fmt.Errorf("failed to set line item quantity: %w", err) | |
| } | |
| fmt.Printf("Line item %d quantity set to 0\n", lineItemID) | |
| // Step 4: Commit the order edit | |
| err = c.commitOrderEdit(calculatedOrderID) | |
| if err != nil { | |
| return fmt.Errorf("failed to commit order edit: %w", err) | |
| } | |
| fmt.Printf("Order edit committed successfully for order %d\n", orderID) | |
| return nil | |
| } | |
| // beginOrderEdit starts an order edit session and returns the calculatedOrder ID | |
| func (c *Client) beginOrderEdit(orderGID string) (string, error) { | |
| query := ` | |
| mutation orderEditBegin($id: ID!) { | |
| orderEditBegin(id: $id) { | |
| calculatedOrder { | |
| id | |
| lineItems(first: 50) { | |
| edges { | |
| node { | |
| id | |
| originalLineItem { | |
| id | |
| } | |
| } | |
| } | |
| } | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": orderGID, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return "", err | |
| } | |
| // Parse the response to extract calculatedOrder ID | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditBegin := data["orderEditBegin"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditBegin["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return "", fmt.Errorf("orderEditBegin errors: %+v", errors) | |
| } | |
| } | |
| calculatedOrder := orderEditBegin["calculatedOrder"].(map[string]interface{}) | |
| calculatedOrderID := calculatedOrder["id"].(string) | |
| return calculatedOrderID, nil | |
| } | |
| // getLineItemVariantID gets the variant ID from an original line item | |
| func (c *Client) getLineItemVariantID(orderGID string, lineItemGID string) (string, error) { | |
| query := ` | |
| query getOrder($id: ID!) { | |
| order(id: $id) { | |
| lineItems(first: 50) { | |
| edges { | |
| node { | |
| id | |
| variant { | |
| id | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": orderGID, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return "", err | |
| } | |
| data := resp.Data.(map[string]interface{}) | |
| order := data["order"].(map[string]interface{}) | |
| lineItems := order["lineItems"].(map[string]interface{}) | |
| edges := lineItems["edges"].([]interface{}) | |
| for _, edge := range edges { | |
| edgeMap := edge.(map[string]interface{}) | |
| node := edgeMap["node"].(map[string]interface{}) | |
| if node["id"].(string) == lineItemGID { | |
| variant := node["variant"].(map[string]interface{}) | |
| return variant["id"].(string), nil | |
| } | |
| } | |
| return "", fmt.Errorf("line item %s not found in order", lineItemGID) | |
| } | |
| // beginOrderEditAndFindLineItemByVariant starts an order edit and finds calculated line item by variant ID | |
| func (c *Client) beginOrderEditAndFindLineItemByVariant(orderGID string, variantID string) (string, string, error) { | |
| query := ` | |
| mutation orderEditBegin($id: ID!) { | |
| orderEditBegin(id: $id) { | |
| calculatedOrder { | |
| id | |
| lineItems(first: 50) { | |
| edges { | |
| node { | |
| id | |
| variant { | |
| id | |
| } | |
| quantity | |
| } | |
| } | |
| } | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": orderGID, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return "", "", err | |
| } | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditBegin := data["orderEditBegin"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditBegin["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return "", "", fmt.Errorf("orderEditBegin errors: %+v", errors) | |
| } | |
| } | |
| calculatedOrder := orderEditBegin["calculatedOrder"].(map[string]interface{}) | |
| calculatedOrderID := calculatedOrder["id"].(string) | |
| // Find the calculated line item ID that matches our variant | |
| lineItems := calculatedOrder["lineItems"].(map[string]interface{}) | |
| edges := lineItems["edges"].([]interface{}) | |
| var calculatedLineItemID string | |
| for _, edge := range edges { | |
| edgeMap := edge.(map[string]interface{}) | |
| node := edgeMap["node"].(map[string]interface{}) | |
| variant := node["variant"].(map[string]interface{}) | |
| if variant["id"].(string) == variantID { | |
| calculatedLineItemID = node["id"].(string) | |
| break | |
| } | |
| } | |
| if calculatedLineItemID == "" { | |
| return "", "", fmt.Errorf("could not find calculated line item for variant %s", variantID) | |
| } | |
| return calculatedOrderID, calculatedLineItemID, nil | |
| } | |
| // beginOrderEditAndFindLineItem starts an order edit session and finds the calculated line item ID | |
| func (c *Client) beginOrderEditAndFindLineItem(orderGID string, lineItemGID string) (string, string, error) { | |
| query := ` | |
| mutation orderEditBegin($id: ID!) { | |
| orderEditBegin(id: $id) { | |
| calculatedOrder { | |
| id | |
| lineItems(first: 50) { | |
| edges { | |
| node { | |
| id | |
| originalLineItem { | |
| id | |
| } | |
| } | |
| } | |
| } | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": orderGID, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return "", "", err | |
| } | |
| // Parse the response to extract calculatedOrder ID and find the calculated line item | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditBegin := data["orderEditBegin"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditBegin["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return "", "", fmt.Errorf("orderEditBegin errors: %+v", errors) | |
| } | |
| } | |
| calculatedOrder := orderEditBegin["calculatedOrder"].(map[string]interface{}) | |
| calculatedOrderID := calculatedOrder["id"].(string) | |
| // Find the calculated line item ID that matches our original line item | |
| lineItems := calculatedOrder["lineItems"].(map[string]interface{}) | |
| edges := lineItems["edges"].([]interface{}) | |
| var calculatedLineItemID string | |
| for _, edge := range edges { | |
| edgeMap := edge.(map[string]interface{}) | |
| node := edgeMap["node"].(map[string]interface{}) | |
| originalLineItem := node["originalLineItem"].(map[string]interface{}) | |
| if originalLineItem["id"].(string) == lineItemGID { | |
| calculatedLineItemID = node["id"].(string) | |
| break | |
| } | |
| } | |
| if calculatedLineItemID == "" { | |
| return "", "", fmt.Errorf("could not find calculated line item for original line item %s", lineItemGID) | |
| } | |
| return calculatedOrderID, calculatedLineItemID, nil | |
| } | |
| // setLineItemQuantityWithCalculatedID sets the quantity using the calculated line item ID | |
| func (c *Client) setLineItemQuantityWithCalculatedID(calculatedOrderID string, calculatedLineItemID string, quantity int) error { | |
| query := ` | |
| mutation orderEditSetQuantity($id: ID!, $lineItemId: ID!, $quantity: Int!) { | |
| orderEditSetQuantity(id: $id, lineItemId: $lineItemId, quantity: $quantity) { | |
| calculatedLineItem { | |
| id | |
| quantity | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": calculatedOrderID, | |
| "lineItemId": calculatedLineItemID, | |
| "quantity": quantity, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return err | |
| } | |
| // Parse the response for errors | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditSetQuantity := data["orderEditSetQuantity"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditSetQuantity["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return fmt.Errorf("orderEditSetQuantity errors: %+v", errors) | |
| } | |
| } | |
| return nil | |
| } | |
| // setLineItemQuantity sets the quantity of a line item in the calculated order | |
| func (c *Client) setLineItemQuantity(calculatedOrderID string, lineItemID uint64, quantity int) error { | |
| query := ` | |
| mutation orderEditSetQuantity($id: ID!, $lineItemId: ID!, $quantity: Int!) { | |
| orderEditSetQuantity(id: $id, lineItemId: $lineItemId, quantity: $quantity) { | |
| calculatedLineItem { | |
| id | |
| quantity | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| lineItemGID := c.BuildGraphqlId("LineItem", lineItemID) | |
| variables := map[string]interface{}{ | |
| "id": calculatedOrderID, | |
| "lineItemId": lineItemGID, | |
| "quantity": quantity, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return err | |
| } | |
| // Parse the response for errors | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditSetQuantity := data["orderEditSetQuantity"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditSetQuantity["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return fmt.Errorf("orderEditSetQuantity errors: %+v", errors) | |
| } | |
| } | |
| return nil | |
| } | |
| // commitOrderEdit commits the order edit changes | |
| func (c *Client) commitOrderEdit(calculatedOrderID string) error { | |
| query := ` | |
| mutation orderEditCommit($id: ID!) { | |
| orderEditCommit(id: $id) { | |
| order { | |
| id | |
| } | |
| userErrors { | |
| field | |
| message | |
| } | |
| } | |
| } | |
| ` | |
| variables := map[string]interface{}{ | |
| "id": calculatedOrderID, | |
| } | |
| resp, err := c.ExecuteGraphQL(query, variables) | |
| if err != nil { | |
| return err | |
| } | |
| // Parse the response for errors | |
| data := resp.Data.(map[string]interface{}) | |
| orderEditCommit := data["orderEditCommit"].(map[string]interface{}) | |
| // Check for user errors | |
| if userErrors, ok := orderEditCommit["userErrors"]; ok { | |
| if errors := userErrors.([]interface{}); len(errors) > 0 { | |
| return fmt.Errorf("orderEditCommit errors: %+v", errors) | |
| } | |
| } | |
| return nil | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment