How to make bulk updates on prices and quantities via API on python?

How to make bulk updates on prices and quantities via API on python?

dfrance
Shopify Partner
2 0 1

I have a list of items that have to be updated daily on prices and inventory quantities, I already know how to do it individually with the code below:

 

for item in update_data.to_dict('records'😞
  #update price on variant
  p_variant = shopify.Product.find(item['id']).variants[0]
  #In case theres a need to update the tracking by api, by default the inventory management is "none", which doesn't allow for api updates
  p_variant.inventory_management = 'shopify'
  p_variant.price = item['Markup price']
  p_variant.save()  
  #update inventory quantity
  print(item['name'])
  shopify.InventoryLevel.set(location_id = location_id, 
                             inventory_item_id = item['inventory_item_id'],
                             available = item['Qnt available'])
  sleep(0.5)
 

But this is too slow and I have 10k+ itens to updates. I didn't find any function to make a mass update and everything that I found until now is either on another language or outdated. Any help is apreciated!
Replies 7 (7)

ShopifyDevSup
Shopify Staff
1451 238 497

Hi @dfrance 👋


Generally, we recommend using bulk mutations to update large volumes of data asychronously and the Shopify python library supports GraphQL requests for bulk operations.

 

Alternatively, you can use the `productVariantsBulkUpdate` mutation to update the variant prices in bulk, and `inventoryBulkAdjustQuantityAtLocation` mutation to bulk modify the inventory quantities directly. Below is an example using the python library:

 

session = shopify.Session(shop_url, api_version, access_token)
shopify.ShopifyResource.activate_session(session)

mutation = """
mutation ($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
  inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
    inventoryLevels {
        id
        available
    }
  }
}
"""
inputs = {
  "inventoryItemAdjustments": [
    {
      "inventoryItemId": "gid://shopify/InventoryItem/41900365676662",
      "availableDelta": 2
    },
    {
      "inventoryItemId": "gid://shopify/InventoryItem/41900365742198",
      "availableDelta": 3
    },
    {
      "inventoryItemId": "gid://shopify/InventoryItem/41900365807734",
      "availableDelta": 4
    }
  ],
  "locationId": "gid://shopify/Location/61122510966"
}

shopify.GraphQL().execute(
    query=mutation,
    variables=inputs,
)

 

 

Hope that helps!

 

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

dfrance
Shopify Partner
2 0 1

While this does help, what I want is to set and not adjust values, I found the mutation "inventorySetOnHandQuantities" but this doesn't do bulk updates from what I saw. is there any alternative to that?

I could of course register the present number on stock and do the difference top adjust to the new stock value. The problem is that this method allows for weird behavior since it will have a time window between getting the present stock value and the new stock value

newbie_01
Shopify Partner
34 0 12

HI

Is there a bulk mutation for updating inventory at a certain location id?

Checking the list the closest one could be productVariantUpdate but the field

inventoryQuantities is only used for creating variants, not for updating them.
daroan
Tourist
4 0 9

Hi, I already lose over 10 hours trying to make this work... no luck!

from BASICS_v1 import *
import requests
import pandas as pd
import logging
import requests
import json
import shopify

class Test:
def __init__(self, api_key=shopify_api_key, api_secret=shopify_api_secret, token=shopify_token,
shop_url= shopify_shop_url, api_version= shopify_api_version😞
self._shopify_api_key = api_key
self._shopify_api_secret = api_secret
self._shopify_token = token
self._shopify_shop_url = shop_url
self._shopify_api_version = api_version
self._folder = os.path.dirname(os.path.abspath(__file__))
self._headers = {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': self._shopify_token
}
logging.basicConfig(filename=f'{self._folder}/error.log', level=logging.ERROR)
self._session = shopify.Session(shop_url, api_version, token)
shopify.ShopifyResource.activate_session(self._session)

def update_products_in_bulk(self, product_data😞
url = f"https://{self._shopify_shop_url}/admin/api/{self._shopify_api_version}/inventory_levels/set.json"

responses = []
total_products = len(product_data)

print(f"Total products to update: {total_products}")

for i in range(0, total_products, 100😞
batch = product_data[i:i + 100]
print(f"Processing batch {i//100 + 1}/{(total_products + 99) // 100}...")

json_payload = json.dumps({"inventory_levels" : batch}) # Trying to update on bulk = DO NOT WORK
json_payload_b = json.dumps(batch[0]) # Selecting only 1 dictionary from batch = WORKS

try:
response = requests.post(url, headers=self._headers, data=json_payload)
if response.status_code == 200:
responses.append(response.json())
print(f"Batch {i//100 + 1} update successful.")
else:
print(f"Error updating batch {i//100 + 1}: Status Code {response.status_code}, Response: {response.text}")
responses.append(response.json())
except json.JSONDecodeError as e:
print(f"JSON Decode Error: {str(e)} - Response text: '{response.text}'")
except requests.RequestException as e:
print(f"Request failed: {str(e)}")

return responses



def bulk_update_inventory(self, locationid=locationid, inventory_adjustments=None😞
# Define the mutation for bulk updating inventory quantities
mutation = """
mutation ($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
inventoryLevels {
id
available
}
}
}
"""

total_adjustments = len(inventory_adjustments)
responses = []

for i in range(0, total_adjustments, 100😞
batch = inventory_adjustments[i:i + 100]

# Prepare the variables for the GraphQL mutation
inputs = {
"inventoryItemAdjustments": batch,
"locationId": f"gid://shopify/Location/{locationid}" # Example location ID, replace with actual ID
}

# Execute the GraphQL mutation
response = shopify.GraphQL().execute(query=mutation, variables=inputs)
responses.append(response)
print(f"Processed batch {i//100 + 1}/{(total_adjustments + 99) // 100}: {response}")

# Deactivate the session after the operation is complete
shopify.ShopifyResource.clear_session()

return responses




inventory= pd.read_pickle(f'{folder}/inventory')[-20:]

# Extract and adjust the relevant fields from the provided adjustments
simplified_adjustments = [
{'location_id': locationid,
'inventory_item_id': adj['inventory_item_id'],
'available': adj['available']}
for adj in inventory
]
x= Test().update_products_in_bulk(simplified_adjustments) # WORK

# Extract and adjust the relevant fields from the provided adjustments
simplified_adjustments = [
{"inventoryLevelId": f"gid://shopify/InventoryItem/{adj['inventory_item_id']}",
# "locationId": location,
"availableDelta": int(adj['available']),
}
for adj in inventory
]
x= Test().bulk_update_inventory(inventory_adjustments=simplified_adjustments) # DO NOT WORK

####

Does not matter what I do, I can only update 1 by 1 using requests, the same data used on GraphQL with Mutation never works

sample_data= [{'inventoryLevelId': 'gid://shopify/InventoryItem/49995823382866', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49995823415634', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49995823448402', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281786706', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281819474', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281852242', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281885010', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281917778', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281950546', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236281983314', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282016082', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282048850', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282081618', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282114386', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282147154', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282179922', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282212690', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282245458', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/42498772729991', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/42535159529607', 'availableDelta': 24}]

I tried add locationId, change the mutation, none work ... the error on function above = 
bulk_update_inventory()

A help would be VERY MUCH appreciated, I am doing this for my own web store... 😞

ERROR = Processed batch 1/1: {"errors":[{"message":"Field 'inventoryBulkAdjustQuantityAtLocation' doesn't exist on type 'Mutation'","locations":[{"line":3,"column":9}],"path":["mutation","inventoryBulkAdjustQuantityAtLocation"],"extensions":{"code":"undefinedField","typeName":"Mutation","fieldName":"inventoryBulkAdjustQuantityAtLocation"}},{"message":"Variable $inventoryItemAdjustments is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"inventoryItemAdjustments"}},{"message":"Variable $locationId is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"locationId"}}]}
daroan
Tourist
4 0 9

If I use the function update_products_in_bulk() with json_payload return the error = 


Error updating batch 1: Status Code 400, Response: {"errors":{"inventory_item_id":"Required parameter missing or invalid"}}
Processed batch 1/1: {"errors":[{"message":"Field 'inventoryBulkAdjustQuantityAtLocation' doesn't exist on type 'Mutation'","locations":[{"line":3,"column":9}],"path":["mutation","inventoryBulkAdjustQuantityAtLocation"],"extensions":{"code":"undefinedField","typeName":"Mutation","fieldName":"inventoryBulkAdjustQuantityAtLocation"}},{"message":"Variable $inventoryItemAdjustments is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"inventoryItemAdjustments"}},{"message":"Variable $locationId is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"locationId"}}]}

this function only work with 
json_payload_b

ShopifyDevSup
Shopify Staff
1451 238 497

Hi @daroan,

 

Looking at the api calls you are making with your code, the error you are receiving with the update_products_in_bulk() function is expected when you are using json_payload, as the REST inventory_levels/set.json endpoint, does only accept a single inventory item per call. This explains why the json_payload_b does work with this query, as it is only setting a single inventory item, where the json_payload input is trying to set multiple inventory items in a single call.

As for the error in the bulk_update_inventory() function, it appears this is due to the fact that the inventoryBulkAdjustQuantityAtLocation mutation query has been deprecated and fully removed as of API version 2024-04, I've confirmed this as well by testing on my own test store and I do receive the same error when making the call on version 2024-04 or later. To resolve this issue, you should switch to using the inventoryAdjustQuantities mutation instead, though if needed you can continue using the InventoryBulkAdjustQuantityAtLocation mutation as it is still available on API versions 2023-10 through 2024-01. However it will be completely unusable when these api versions are fully deprecated 1 year from their release.

Here's some relevant developer documentation to help with this further:
 

  • inventoryBulkAdjustQuantityAtLocation: the 2024-04 version does show this mutation is not supported. If you change the version in the documentation page in the upper left to 2024-01 or earlier, it will still display the mutation, but it does show it is deprecated and suggests to use inventoryAdjustQuantities instead.


     
  • inventoryAdjustQuantities: This is the new mutation you should use moving forward, and it does accept multiple inventory items per call, however it's important to know you can only update one inventory state per call. For example you can update the available quantity for multiple items, but if you wanted to update the on hand state, you would need to make a separate call.
     

I hope this helps, and I hope you have a great day 🙂

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us know!
- Was your question answered? Mark it as an Accepted Solution
- To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

daroan
Tourist
4 0 9

Hi I very much appreciated the answer, was even faster than I could catch up... 😄

 

Tried update_products_in_bulk to update inventory in bulk with adjust.json does not worked, below is the data used before json.dumps({"inventory_levels" : batch}):

 

data= [{'location_id': 62155718791, 'inventory_item_id': 49236282179922, 'available': 0}, {'location_id': 62155718791, 'inventory_item_id': 49236282212690, 'available': 0}, {'location_id': 62155718791, 'inventory_item_id': 49236282245458, 'available': 0}, {'location_id': 62155718791, 'inventory_item_id': 42498772729991, 'available': 0}, {'location_id': 62155718791, 'inventory_item_id': 42535159529607, 'available': 0}]

Error updating batch 1: Status Code 400, Response: {"errors":{"inventory_item_id":"Required parameter missing or invalid"}}

 

===

On bulk_update_inventory I tried change the version to 2024-01 but also did not work, data used:

data= {'inventoryItemAdjustments': [{'inventoryLevelId': 'gid://shopify/InventoryItem/49236282179922', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282212690', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/49236282245458', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/42498772729991', 'availableDelta': 0}, {'inventoryLevelId': 'gid://shopify/InventoryItem/42535159529607', 'availableDelta': 0}], 'locationId': 'gid://shopify/Location/62155718791'}

 

Processed batch 1/1: {"errors":[{"message":"Field 'inventoryBulkAdjustQuantityAtLocation' doesn't exist on type 'Mutation'","locations":[{"line":3,"column":9}],"path":["mutation","inventoryBulkAdjustQuantityAtLocation"],"extensions":{"code":"undefinedField","typeName":"Mutation","fieldName":"inventoryBulkAdjustQuantityAtLocation"}},{"message":"Variable $inventoryItemAdjustments is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"inventoryItemAdjustments"}},{"message":"Variable $locationId is declared by anonymous mutation but not used","locations":[{"line":2,"column":9}],"path":["mutation"],"extensions":{"code":"variableNotUsed","variableName":"locationId"}}]}


😞