according to the documentation, the Create Shipment method requires the property "items" - an array of the items being shipped, for example:
{
"tracking_number": "EJ958083578US",
"comments": "Ready to go...",
"order_address_id": 1,
"items": [
{
"order_product_id": 15,
"quantity": 2
}
]
}
In our business, a shipment almost invariably contains ALL items from the relevant order.
That being the case, is there a way to create a shipment without listing all items (which would require iterating over the product line-items)? Or, alternatively, a way to include all items by default (without iterating)?
We are simply wishing to automate the process of adding tracking numbers to orders - which (as a manual process) involves uploading a csv with [order_number: tracking_number] - i.e. it self-evidently assumes that all items are being shipped. The API seems not to include that (very sensible) option, but I may be wrong.
From Bigcommerce Support:
There is not a way to add a tracking number without adding a shipment nor a way to default the shipment to include all products. This is a helpful suggestion though that I will be passing on to our Product Team for possible implementation into future versions of the API.
Unfortunately for now it is necessary that you GET to the products subresource of an order and iterate over all of the products to pull their 'id' values and 'order_address_id' values so you can generate your POST request to the shipment subresource. It is not necessary to make a GET request to the shipping address subresource directly unless you want the details of that shipping address. It is also not necessary to make a GET request to the base order object unless you want details found there or you are looking to automate the process of checking for orders ready to ship.
So assuming you know an order ID that you want to ship it should only take 2 requests total to both GET the products subresource and then POST to the shipment resource.
Related
I want to create a CSV export of product data from a Shopify store. For each product I'm exporting data like the product name, price, image URL etc... In this export I also want to list, for each product, all the collections the product belongs to, preferably in the hierarchal order the collections appear in the site's navigation menu (e.g Men > Shirts > Red Shirts).
If my understanding of the API is correct, for each product I need to make a separate call to the Collect API to get a list of collections it belongs to then another call to the Collections API to get the handle of each collection. This sounds like a lot of API calls for each product.
Is there a more efficient way to do this?
Is there any way to figure out the aforementioned hierarchy of collections?
Unfortunately, as you pointed out, I don't think there is an efficient way of doing this because of the way that the Shopify API is structured. It does not permit collections to be queried from products, rather only products queried from collections. That is, one can't see what collections a product belongs to, but can see what products belong to a collection.
The ShopifyAPI::Collect or ShopifyAPI::Collection REST resource does not return Product variant information, which is needed to get the price information as per the requirements. Furthermore, ShopifyAPI::Collect is limited to custom collections only, and would not work for products in ShopifyAPI::SmartCollection's. For this reason I suggest using GraphQL instead of REST to get the information needed.
query ($collectionCursor: String, $productCursor: String){
collections(first: 1, after: $collectionCursor) {
edges {
cursor
node {
id
handle
products(first: 8, after: $productCursor){
edges{
cursor
node{
id
title
variants(first: 100){
edges{
node{
price
}
}
}
}
}
}
}
}
}
}
{
"collectionCursor": null,
"productCursor": null
}
The $productCursor variable can be used to iterate over all of the products in a collection and the $collectionCursor to iterate over all collections. Note that only the first 100 variants need to be queried since Shopify has a hard limit on 100 variants per product.
The same query can be used to iterate over ShopifyAPI::SmartCollection's.
Alternatively the same query using the REST API would look something like this in Ruby.
collections = ShopifyAPI::Collection.all # paginate
collection.each do |collection|
collection.products.each do |product|
product.title
# note the extra call the Product API to get varint info
ShopifyAPI::Product.find(product.id).variants.each do |varaint|
variant.price
end
end
end
I don't see any way to address the inefficiencies with the REST query, but you might be able to improve on the GraphQL queries by using Shopify's GraphQL Bulk Operations.
Let's say that I'm developing an application about shopping. I have defined the following endpoints, which are quite self-explanatory:
GET /items
GET /items/{item-id}
GET /stores
GET /stores/{store-id}
Now, I want to create another endpoint that displays the price of individual item at different stores. This price information is not included in /items/{item-id} since I don't think it's suitable to be an attribute of item, and getting the list of prices requires a bit more calculation as I cannot return the object directly. I will name the endpoint /items/{item-id}/prices and expect a response like this:
[
{
"store_id": "store_1",
"price": 13.00
},
{
"store_id": "store_2",
"price": 12.99
}
]
I want to extend this further and create another endpoint that returns the price information for all items, but I'm having trouble naming this endpoint. So far I've thought of /items/prices or /items?display=prices but the former might be confusing as it matches with /items/{item-id}, and the latter just.. does not seem to make sense for me.
What is the best name to pick for my endpoint so that it stays consistent with the convention?
For all items pricelist endpoint for a single store, I'd recommend GET /stores/{store-id}/prices or GET /stores/{store-id}/pricelist.
For all items/stores pricelist, I'd use GET /items/pricelist or GET /items/*/pricelist, (both special before /items/{item-id}), which could be store-specified on demand by ?store={store-id}.
Adding prices endpoint to items would make no sense as item itself has nothing to do. It is store's responsibility to dictate the price.
I would suggest renaming stores endpoint to /stores/description/{id} and adding prices subcategory /stores/prices/by-item/{id} and /stores/prices/by-store/{id}.
I would say that for sepecfic item /prices/{store-id}/{item-id}
and for all prices /prices/{store-id}
I am trying to understand how to build an API call where I can get data (json format) for the recipes, ingredients, and procedure as mention here. Anyone who could help me out with this?
https://en.wikibooks.org/wiki/Cookbook:Recipes
This URL has the recipe names and when clicked on each item it gets the ingredients and the procedure.
To get all recipes I would not use Cookbook:Recipes but rather Category:Recipes which is more complete.
The API call to list all recipes which are listed in Category:Recipes is the following:
https://en.wikibooks.org/w/api.php?action=query&generator=categorymembers&gcmtitle=Category:Recipes&gcmlimit=max&format=json&gcmcontinue=.
It will return you 500 recipes but there are more on Wikibooks. To get the remaining ones, use the continue -> gcmcontinue value in the response and append it to the next API call.
To get the ingredients and procedure of a recipe, call for example
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits.
You can use the | character to retrieve multiple recipes with the same API call:
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&titles=Cookbook:Biscuits|Cookbook:Baklava.
If you want to retrieve only the ingredients or only the procedure of recipes, use the additional parameter rvsection=. Most of the time (but not always) the ingredients are in the first section and the procedure is the second section. So calling
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits&rvsection=1 returns you the ingredients for making biscuits and
https://en.wikibooks.org/w/api.php?action=query&prop=revisions&format=json&rvprop=content&rvslots=%2A&rvsection=1&titles=Cookbook:Biscuits&rvsection=2 returns you the procedure for making biscuits.
I'm not sure if it was your question, but in addition to Pascalco's answer, it worth note that you will NOT be able to get structured json data that details ingredients with their quantities and procedures, ie something like:
{ "ingredient": "milk", "quantity": { "number": "1", "unit":"liter"}}
The API will drop the raw mediawiki's syntax page content in one single field, and a few extra metadata about the page.
Moreover, the fact that those pages do not use templates make this type of data very difficult to extract, either with a syntax parser or html parser.
It is not at all clear to me how to update the price/stock for a listing once it has been created initally using listing->createListing().
To update the stock/price, Etsy's documentation says to call listing->updateInventory(). However, this call requires something called products together with a couple of properties (price_on_property, quantity_on_property and sku_on_property):
listing_id
products*
price_on_property
quantity_on_property
sku_on_property
where:
products is further defined in their documentation as a combination of property_values and offerings which I have no clue about.
listing_id is returned from the call to createListing() initially.
Etsy's footnote about price_on_property, stock_on_property and sku_on_property adds to the confusion:
price_on_property is an array of the property_ids of the properties which price depends on (if any).
quantity_on_property is an array of the property_ids of the properties which quantity depends on (if any).
sku_on_property is an array of the property_ids of the properties
which sku depends on (if any).
The update will fail if the supplied values for product sku and offering quantity and price are incompatible with the supplied values of the "on_property_*" fields.
When supplying a price, supply a float equivalent to amount divided by
divisor as specified in the Money resource.
The products parameter should be a JSON array of products, even if you only send a single product. All field names in the JSON blob should be lowercase.
Taken from https://www.etsy.com/developers/documentation/reference/listinginventory#method_updateinventory
Given that the starting point for adding things for sale on Etsy is just to call createListing() with details of the item that I wish to sell (inc stock quantity and price), I do not understand how to call updateInventory() to update the stock and/or price of this item and so can anybody provide some clarity on this matter please (and yes, I have contacted Etsy developer support, but it might take a while for them to respond).
In python - I assume you have the etsy_api module from github.
Etsy product listings have the following structure:
ListingProduct = {
"price_on_property": [
property_ids
],
"products": [
LIST OF PRODUCT VARIATIONS FOR THIS LIST. IF YOU HAVE NO VARIATIONS
THEN THIS LIST WILL HAVE ONLY 1 PRODUCT.
],
"quantity_on_property": [],
"sku_on_property": []
}
To update prices, you need to send back this ListingProduct model, but with the changes you want. Note
price_on_property is required if you have variations.
sku_on_property is optional if you have different skus for different
variations.
quantity_on_property is optional if you have different quantities on
variations.
The easiest way I have found is to do the following:
Get the listing_id for the product you want to change price on.
Make a call to the inventory URI to get this listing. I'm doing this to avoid having to construct ListingProduct['products']. It has too much going on with it.
listing_id = 'the product's listing_id'
ListingProduct = etsy_api.getInventory(listing_id=listing_id)
ListingProduct['products'] is a list of products for this listing. The size of this list is equal to the number of variations that you have.
Take ListingProduct['products'] and for each variation change the price.
If you take a look at ListingProduct['products'], you will see that the changes that need to be done are,
ListingProducts['products'][0]['offerings'][0]['price'] = NewPrice
If a listing has 2 variations, then change the price on that too
ListingProducts['products'][1]['offerings'][0]['price'] = OtherNewPrice
Once you do this make a call with the data.
data = {
'listing_id': listing_id
'products': json.dumps(ListingProduct['products'])
'price_on_property': 200 #If you have variation
}
etsy_api.updateInventory(**data)
To update the variations for a product in ETSY, you need to use update inventory call from the API (Expecting you are using Etsy module from GitHub).
refer to link https://www.etsy.com/developers/documentation/getting_started/inventory
The data you need to send with this call will include --
array (
products => json_encode($products),
price_on_property =>
quantity_on_property =>
)
price_on_property will include the variation property id provided by etsy
quantity_on_property will be included in case of more than one variation attribute
The products index will include an array of variations with the details --
[0] => (
product_id=> 1234,
property_values" => [
property_id => 500,
property_name => color,
'values => [ green ],
],
offerings" => [
(
price => 200
quantity => 1,
)
)
[1] => and so on...
Property Id will be provided by etsy for variation attributes.
Let's say we are making an invoice API. What is a more appropriate resource?
GET
paid_invoices
due_invoices
all_invoices
or
GET
invoices/all
invoices/due
invoices/paid
Additional question: If your API allows marking invoices as paid what's the proper resource?
PUT //where 3 is the id
invoices/3
or
PUT
pay_invoice/3
I would say:
GET /invoices returns all invoices;
A filter can return either paid or due invoices: GET /invoices?state=paid where state can be paid or due.
To mark an invoice as paid, you can either set the corresponding state to your resource, and then you just have to update (replace actually) it using PUT /invoices/<id>.
Alternatively, you can patch your resource: PATCH /invoices/<id>. This method requires a diff like state=paid for example.
It's just a matter of what you want to send to your API (a complete resource, or just the change to apply).
A non-REST solution could be to perform a PATCH request to /invoices/<id>/paid. It's not pure REST but it's ok.