When adding a product to cart 2 or more times, each time with different custom options which normally have different prices, the calculated total price is wrong.
孝he total price should be the sum of the prices for each product/options pair added to cart. Instead the price ends up being the quantity multiplied by the price of the last added to cart product (with its options), dismissing the prices of previously added products/options.
Pick one option.
develop branch and create Pull Request 2. Feature / Improvement back to develop.release branch and create Pull Request 3. Stabilisation fix back to release.hotfix or master branch and create Pull Request 4. Hotfix back to hotfix.This is related to #1620 and the way we鈥檙e identifying clients side configurable/bundle products with data we get from the server during the server sync (cart/serverAfterPuled action)
This needs to be handled in multiple places. Most mutations in cart/store/mutations.ts and some methods in cart/store/actions.ts identify products by only verifying its SKU. I suggest product_option.extension_attributes.custom_options be taken in account as well. This should allow for multiple cart items having the same SKU.
@pkarw, what is a proper way to identify product taking in to account the options? I'm using this for time being, it works, but I'm not confident its the best approach:
state.cartItems.find(p => p.sku === product.sku && JSON.stringify(p.product_option) === JSON.stringify(product.product_option))
Hi! Thanks for Your input @bobcho. It's probably one of the ways to solve this issue. I like it because it's pretty general and will also work for the situation of different custom_options with the same SKU in cart. However, going this way the final implementation probably should use the kind of specific product.chcksm property which contains a hash of the product_options - to avoid JSON.stringify on compare.
Let's consider which other ways we have to solve this issue?
updateQuantity)product.server_item_id to identify items by the merge. In this case, we must assign server_item_id immediately after the product is added to the cart for the first time - in here:It shouldn't be hard as the current server API responds with the proper information: https://www.dropbox.com/s/5hxkx3x9fiof3kv/Screenshot%202019-06-01%2006.58.01.png?dl=0
Probably we should update it immediately anyway as it's not related solely to this issue.
Then, we can use this product.server_item_id to identify the products during sync. If the product has not yet set server_item_id it means it's a new one - not yet added to the server cart.
While adding to the cart we could keep the per sku identification - however, I'm not sure about the custom_options case - probably the sku is the same so kind of checksum on product_option will be required anyway just for this check.
parentSku-childSku1-childSku2 virtual identifiers so we can do the same on the client's side. Still - it doesn't solve the product custom options issue - and it's vulnerable to desync in case smbd. change the virtual sku naming algorithm server side.Thanks for the feedback!
Good point about the checksum - do you think it should represent only product_option or better to have a more "global" checksum representing the product itself (also taking SKU in account)? Something like:
product.chcksm = sha3_224(JSON.stringify({sku: product.sku, product_option: product.product_option ? product.product_option : null}));
I may be wrong as I've not checked the Magento API code, but judging by the demo API responses, I think 1 and 2 would require server API mod, because currently it seems the server only checks the SKU when adding / modifying items in the cart (api/cart/update). The API call that vue-storefront makes includes the options, but it seems they are not taken in account by the server. This results in the server and client having misaligned carts.
And then for 3 I agree with you - it doesn't solve the custom options issue and is vulnerable to desync. But it may work for bundles without any server mods.
Hey, do you know when this can be fixed? I try to find a solution by myself but at the moment I'm not that into the system to solve it in a good way. We want to launch our new shop but aren't not able to do without this functionality.
By the way, great System, I will continue learning vue storefront :)
@PatrickKluwig could you give me your email or write to me at [email protected]? We can speed up development of this functionality.
@patrickfriday Hey, thank you for your answere, the email address [email protected] is not available.
@PatrickKluwig that cannot be as I just got notification to that email :( What is yours, then I will write you an email :-)
I have a solution for personalized products. Overite the core module productsEquals.ts. After this you will be able to add same SKU multiple time to basket and sync with m2.
if(String(product1.sku ) === String(product2.sku)){
if(product1.product_option.extension_attributes.custom_options && product2.product_option){
let p1 = product1.product_option.extension_attributes.custom_options
let p2 = product2.product_option.extension_attributes.custom_options
let p1Array = []
let p2Array = []
for( let key in p1){
typeof p1[key].option_value === "undefined"? p1[key].option_value = null :p1[key].option_value=p1[key].option_value
p1Array.push({
"option_id": p1[key].option_id,
"option_label": p1[key].option_value
})
}
for( let key in p2){
p2Array.push({
"option_id": p2[key].option_id,
"option_label": p2[key].option_value
})
}
let values = (o) => Object.keys(o).sort().map(k => o[k]).join('|')
let mapped1 = p1Array.map(o => values(o))
let mapped2 = p2Array.map(o => values(o))
var res = mapped1.every(v => mapped2.includes(v))
return res
}
}
return String(product1.sku ) === String(product2.sku)
Most helpful comment
This is related to #1620 and the way we鈥檙e identifying clients side configurable/bundle products with data we get from the server during the server sync (cart/serverAfterPuled action)