Skip to content

Instantly share code, notes, and snippets.

@andrewarrow
Created September 10, 2025 19:59
Show Gist options
  • Select an option

  • Save andrewarrow/c75c7a3fedda9abb8fd1af142956acc9 to your computer and use it in GitHub Desktop.

Select an option

Save andrewarrow/c75c7a3fedda9abb8fd1af142956acc9 to your computer and use it in GitHub Desktop.
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