How to update product price with graphql on shopify if there is no product variant - graphql

I am using a python script with requests to update various properties of a shopify shop using graphql and it works fine.
The problem is I can't figure out how to update a product price when there is no product variant using Graphql
All the documentation refers to mutations on product variants, but most of the products on this shop don't have any variants.
However I read somewhere that products without variants are "default variants" themselves, but i can't find the id for this.
If I pass the product id, or global id, the response is just no id found.
I have spent hours on the documentation and I can't find the correct reference.
I even asked our banned friend, but wasn't really helpful:)
Here is the working graphql query for updating variants for reference.
query = '''
mutation productVariantUpdate($input1: ProductVariantInput!) {
item1: productVariantUpdate(input: $input1) {
productVariant {
id,
price
}
userErrors {
field
message
}
}
'''
variables = {
"input2":{"id":"gid://shopify/ProductVariant/42177699971252","price":15.20}
}

A product has many variants. Between one, and one hundred. End of story. If you have a product ID, you can get the variant IDs. End of story. If you have a variant ID, you can get the variant details. With those, you will find that a variant has an inventory_item_id. Or inventoryItemId. You get the picture? With that, you can get the item! The item has a price. You can use a mutation to set the price. That is how it is done.
If you say you have a product without a variant, that is false. Impossible.

Sounds like you're confusing the number of options with variants.
The Product object also has a totalVariants count and hasOnlyDefaultVariant fields

Ok,
The confusing part was, when you have a product the uri has a product id, if you create a variant, there is a variant id in the uri as well.
But i didn't realize that the existance of a default variant id as i never came across of this in the gui, so i never tried to run a variant query on a product without multiple variants.
So running:
{
product(id: "gid://shopify/Product/123456798"){
variants(first:5 ){
nodes {
id
price
}
}
}
}
Does return the dafault variant id which i can then use for updating.

Related

NopCommerce 2.5 Homepage sort order

NopCommerce 2.5
I want to sort the products on the home page on the display order given in Admin/Category/Edit/... but I can't find the table that the display order is held in. I have the query in Nop.Services\Catalog\ProductService.cs and I guess I need to set up a Join here but with which table???.
public virtual IList<Product> GetAllProductsDisplayedOnHomePage()
{
var query = from p in _productRepository.Table
orderby p.Name
where p.Published &&
!p.Deleted &&
p.ShowOnHomePage
select p;
var products = query.ToList();
return products;
}
Can someone point me in the right direction, or even better fill in the gaps?
I guess this is quite late but...
No way to modify the default order. In the code above you see the "ORDER BY Name" is hardcoded. This is a big flaw of nopCommerce. There's no table or field that stores the DisplayOrder on HomePage, because there's no HomePage <-> Product relation at all, it's just a switch: it's either ON or OFF.

Codeigniter route products, categories and sub-categories

I am using Codeigniter for my project.
I need to get URL structure like this:
Main product page
example.com/language-prefix/products/
Select products by category
example.com/language-prefix/products/category
Select products by category AND sub-category:
example.com/language-prefix/products/category/sub-category
Select specifict product under category AND sub-category:
example.com/language-prefix/products/category/sub-category/product-name
OR only under category
example.com/language-prefix/products/category/product-name
Question is - what would be a good solution for this? Because problem starts here:
example.com/language-prefix/products/category/what-ever
what-ever can be a product or a sub-category and how to decide - what data and view should be returned?
In my DB table structure I have many-to-many relationships between products and categories. It means, than one product can be assigned to many categories. Every category has a self refferecing foreign key (parent).
Maybe I need to get some restrictions for category adding for products? Or specifing a main category or what?
I have couple of ideas:
Keep every route for category/sub-category and product in DB for example:
/products/watches/for-men/
/products/watches/for-men/rolex-abc-whatever-product
And so on, and so on. But this, I have feeling could be very slow.
Make a simple route to products controller -> method view(), and in the method go trough all passed segments and when it comes to
/products/category/what-ever
then first check if there exists such product, if true, then return product_view and data, if not, check if there is such sub-category and if there is, then return the product grid or return 404 if there is not.
I assume a simple solution could be just keep all categories and sub-categories after /products/ and add category-id like
example.com/language-prefix/products/1-watches
example.com/language-prefix/products/2-for-men
But I hope there is better solution for this.
Also I cant figure out this:
example.com/language-prefix/products/category/sub-category/product-name
I need to return product with name product-name AND check if it is under those two categories so URL for example:
example.com/language-prefix/products/hello-kity/bla-bla/product-name
would NOT return that product.
Any better/other solutions?
"Keep every route for category/sub-category and product in DB"
the idea above won't work well in CI and you'll probably break the way CI routing works. remember that the route points you to a controller/function. only when you get there can you start calling the db... so this idea will be weird since you gotta' call the db first to match the routes.
"Make a simple route to products controller -> method view(), and in the method go trough all passed segments and when it comes to /products/category/what-ever"
the idea above is better, you could have a route like this $route['[a-z]{2}/products/(:any)'] = "product/index/$1"; so http://www.example.com/sg/products/gems/ruby and http://www.example.com/sg/products/gems/red/ruby will both go to the product controller's index function
segment(4) can be either "red" which is a sub-category or "ruby" which is a product. segment(3) is always going to be a category. segment(5) is either empty or a product. you must now simply decide if products or sub-categories that precedence, better still handle within your code logic that they never will collide. i.e. product and category/sub-category names cannot be duplicated.
public function test($category = NULL, $sub_category_or_product = NULL, $product = NULL)
{
echo $category.'<br />'; // segment(3) is always your category
if ($product)
{
echo $sub_category_or_product.'<br />'; // segment(4) is a sub-category
echo $product.'<br />'; // segment(5) is a product
}
else
{
echo $sub_category_or_product.'<br />'; // it's a sub-category or product
// call the db and test whether its a sub-category
// then test if its a product... or the other way around
}
}
of cuz this is just one of the many possible ways to solve it...
however if you don't have to stick with that URL structure...
i would suggest you put products/categories/sub-categories under the "/products/" namespace in the URL for "listing view". and put products under the "/p/something" namespace for the details view
www.example.com/p/ruby // product details
www.example.com/products // product listing
www.example.com/products/gems // product listing
www.example.com/products/gems/red // product listing
for example see:
http://www.beautylish.com/products
http://www.beautylish.com/p/mac-mineralize-skinfinish-natural
this way you won't have to worry about categories/sub-categories names clashing with product names
people probably want to put the cats and sub cats in the product url for seo... but if you check beautylish they got very damn good seo without choking up the url and simply putting only the product name, it's also shorter and more readable.

Linq related items not loading

I have a "task" table, which has a "sub category". The sub category is related to a Category. A category has many sub categories, but my task item only stored the sub category id (The category can be deduced from this).
So, my entity framework seems to understand this relationship.
But, my link is failing.
public TaskObject GetTask(int taskId)
{
var item = (from t in _te.tasks.Include("r_sub_category").Include("r_category").Include("r_priority").Include("r_state").Include("assigned_person").Include("create_person").Include("update_person") where t.task_id == taskId select t).FirstOrDefault();
return Transformer.UnpackTask(item);
}
There is a r_category table, and entity object, but when I run this, it tells me:
A specified Include path is not valid. The EntityType 'taskerModel.task' does not declare a navigation property with the name 'r_category'.
And that's correct - r_category is linked to my r_sub_category table... and not directly to task. Is there a way to load the r_category?
Or, maybe this Include is lazy, and I should be doing some sort of Joining myself? Maybe more efficient?
You need to show the full path with dot Notation so im guessing it would be
"r_sub_category.r_category".
And so forth

Magento - How to add multiple items to the cart programmatically?

I'm trying to add multiple simple products to the cart at the same time using a query string as below, however it only adds the last product to the cart instead of both:
Can someone let me know what I'm doing wrong?
http://www.domain.co.uk/checkout/cart/add?product=9916&qty=4&product=15749&qty=4
I have also tried this:
http://www.domain.co.uk/checkout/cart/add?product[]=9916&qty[]=4&product[]=15749&qty[]=4
Any help much appreciated!
Add Product To Cart With Querystring
Add simple product in shopping cart with no attribute.
http://yourserver.com/checkout/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY
Here PRODUCT_ID = 'Product Id',PRODUCT_QUANTITY = 'product quantity to purchase'.
Add product into shopping cart with single custome option.
http://yourserver.com/checkout/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY&super_attribute[OPTION_ID]=OPTION_VALUE
Here OPTION_ID = 'Custom attribute option id',OPTION_VALUE = 'Custom attribute option value'.
Add product into shopping cart with multipal custome option.
http://yourserver.com/checkout/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY&super_attribute[OPTION_ID_1]=OPTION_VALUE_1&super_attribute[OPTION_ID_2]=OPTION_VALUE_2
Here OPTION_ID_1 & OPTION_ID_1 = 'Custom attribute option ids',OPTION_VALUE_1 & OPTION_VALUE_2 = 'Custom attribute option values'.Here add more options in `super_attribute` array
Add Extra products with mail product with only 1 quantity.
http://yourserver.com/checkout/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY&related_product=PRODUCT_ID_1,PRODUCT_ID_2
Here PRODUCT_ID_1 and PRODUCT_ID_2 is other products id. add more product by id using `,` separator. Example:- &related_product=1,2,3,4.
Default magento there is not setting for add related product quantity into cart.so if you want to add this code than open app/code/core/Mage/Checkout/controllers/CartController.php find public function addAction().
if (!empty($related)) {
$cart->addProductsByIds(explode(',', $related));
}
Replace with
$rel_qty = $this->getRequest()->getParam('related_qty');
if (!empty($related)) {
$relatedproducts = explode(',', $related);
$relatedqtys = explode(',',$rel_qty);
$i = 0;
foreach($relatedproducts as $relatedproduct)
{
$cart->addProduct($relatedproduct, array('qty'=>$relatedqtys[$i]));
$i++;
}
}
Now use query string for add related products with quantity.
http://yourserver.com/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY&related_product=PRODUCT_ID_1,PRODUCT_ID_2&related_qty=PRODUCT_ID_1_QUANTITY,PRODUCT_ID_2_QUANTITY
If you don't want to change any code, you can try to utilize related products functionality by adding related_product parameter to your request. So your url will look like this:
http://www.domain.co.uk/checkout/cart/add?product=9916&qty=4&related_product=15749
If you want to add more products, just list them with comma separator: related_product=1,2,3
The only drawback from that is that you actually can't specify the qty for related products.
To see how it works - Mage_Checkout_Model_Cart::addProductsByIds(array_of_ids)
If qty for subsequent products is a mandatory for you, you'll need to create your own controller, or override the Mage_Checkout_CartController::addAction method.
I found a cheeky way I found of getting around the quantity limitation of the related_products query string field noted above in other answers. If you just put the SAME ID MULTIPLE TIMES in the value of related_products, as many times as the quantity you need, then that will achieve the same effect as if there was an explicit qty field for each related product. So taking himansu's answer above and adapting it we get:
http://yourserver.com/checkout/cart/add?product=PRODUCT_ID&qty=PRODUCT_QUANTITY&related_product=PRODUCT_ID_1,PRODUCT_ID_1,PRODUCT_ID_1,PRODUCT_ID_2,PRODUCT_ID_2
This will add to the cart PRODUCT_QUANTITY of PRODUCT_ID, 3 of PRODUCT_ID_1, and 2 of PRODUCT_ID_2.
So as long as you're happy doing a little work to generate the same ID multiple times this works a treat. And no custom code changes required on your magento server.

Finding Related Rows in Doctrine -- "Cleanest" Design?

I'm new to Doctrine, and I'm trying to get my head around both Doctrine and Symfony at the same time, so please bear with me.
I have a "Sentence" object. Sentences can be "rated" (scored out of five) by Users. I'm modelling this with the fairly obvious design where I have a Sentence table, a User table and a Rating table. Each row in the Rating table represents one user's rating of one sentence.
Rating:
...
columns:
rating: { type: integer } # This is my score out of five
sentence_id: { type: integer }
user_id: { type: integer }
relations:
sfGuardUser: { local: user_id }
Sentence: { local: sentence_id, onDelete: CASCADE, foreignAlias: Ratings }
That's working fine, but I'm struggling to find the cleanest way of asking questions of my model.
For example, in my code I have a logged-in User, related to my session, and I'm displaying a page representing a Sentence, which is also already sitting in a variable. I want to display the logged-in user's rating of that Sentence.
In raw SQL, effectively what I want to do is:
SELECT
rating
FROM
rating_table
WHERE
sentence_id = {$sentence->id} AND user_id = {$user->id}
Now, I know I could just do this on the RatingTable, simply by writing a new query with a bit of DQL, or even using one of the "magic" finders. But that seems a bit clumsy and not very OO, when I already have a Sentence object in memory with a getRatings() method generated by Doctrine for me which must already have the rating I want in its Collection of "all ratings for this sentence".
Is there an easy, efficient way that I'm missing of doing something like $sentence->getRatings()->findByUserId($user->getId())?
Or is it actually sensible just to ignore the fact that I've already got a collection of "ratings for this sentence" in memory and dive back out to the database, ignoring them completely?
There isnt a finder within a collection like that that im aware of (unlike with Propel)... if there is and I missed it in the Doctrine API then im going to leanr a blissful piece of code when someone posts it :-)
Having said that, IF you already have the collection loaded i would just add a custom method tot he model.. for example:
public function getUserRating($user){
if($user instanceof Doctrine_Record){ // or sfGuardUser depending on how tightly you want to couple
$user = $user->getId();
}
foreach($this->getRatings() as $rating){
if($user == $rating->getUserId()){
return $rating;
}
}
return null;
}

Resources