vendure-ecommerce / vendure

The commerce platform with customization in its DNA.
https://www.vendure.io
Other
5.58k stars 989 forks source link

Separate variants into their own products (bundle products) #236

Open Zyles opened 4 years ago

Zyles commented 4 years ago

Is your feature request related to a problem? Please describe.

Take a look at how Magento and proper PIM systems handle stock.

All products are unique and have their own SKU. Products with variants are multiple products bundled together into one in the storefront, but in the backend they are multiple unique products.

If you have 5 t-shirts that have 5 colors but are same size and brand. They are still 5 unique physical products and stock should be managed separately.

Furthermore you can add two variants with the same SKU, that should cause a lot of problems.

Describe the solution you'd like

Use the Magento approach where each product is a unique product and a bundle is a collection of products that build a product with variants.

Describe alternatives you've considered

None.

Additional context

Look at how a PIM works and build from that.

michaelbromley commented 4 years ago

Hi there,

Use the Magento approach where each product is a unique product and a bundle is a collection of products that build a product with variants.

Thanks for your suggestion. The system you describe in Magento sounds like their products are comparable to a Vendure ProductVariant, and their bundles are equivalent to a Vendure Product. Is there anything else I'm missing there beyond the differing nomenclature? Is there something that the Magento system enables that Vendure cannot do?

Furthermore you can add two variants with the same SKU, that should cause a lot of problems.

Good catch, that should probably be disallowed.

Zyles commented 4 years ago

I only looked at the demo and didn't invest more time into installing it. So not sure how the underlying DB structure is mapped out.

Magento consists of "simple products" which are products with unique SKU and tied to a physical product. Like medium t-shirt with color red.

When you shop a product with variants like multiple colors and sizes, you build a "configurable product" that includes these simple products. That way you get multiple choices.

The way you setup the admin as I saw it. Is that you can't reuse these products in another other bundled product, because the variants are already defined under a product.

For example:

- SKU: 123, Medium t-shirt red
- SKU: 321, Medium t-shirt blue

- Bundle product 1
-- SKU: 123, Medium t-shirt red
-- SKU: 321, Medium t-shirt blue

- Bundle product 2
-- SKU: 123, Medium t-shirt red

How do you include SKU 123 in two Bundles?

If you can create SKUs that are duplicates it tells me you are not using unique constraints on SKU field.

michaelbromley commented 4 years ago

The way you setup the admin as I saw it. Is that you can't reuse these products in another other bundled product, because the variants are already defined under a product.

Thank you for the explanation. Indeed that would be a limitation of our system vs that of Magento. The Product -> ProductVariant relation in Vendure is one-to-many.

I have no plans to change this at the time being, but I will leave this issue open so others with this requirement can add their input.

Zyles commented 4 years ago

You're basically making the same mistakes other ecommerce platforms did over 10 years ago.

It is better to learn from the previous iterations instead of starting over with the same problems.

If you have a product, that is a t-shirt. It comes in 100 variations with different sizes and colors. Is it up to the catalog manager to pick one of those to be the "mother product" randomly?

In a configurable product in Magento, you can change that.

What happens when that mother product is out of stock but the children aren't?

Can you pick another product to be the main product? I could not find a way to do that.

How does direct linking to a variant product work? In the demo I could not do it.

If we upload a shopping feed to Google that needs to compare 5 types of laptops with different amounts of RAM. You can't really upload "Laptop" and link 5 products to that one. You need one unique SKU per model. "Laptop 8GB RAM" etc. Now you would link them to the exact same starting point without the correct selection when a user clicks the ad. And you would end up on "Laptop 2GB RAM", not the ad you clicked on. Google does NOT like that.

These are just some of the problems which is why this setup is going to be a huge headache for a serious store.

But I guess it works if you are small time.

michaelbromley commented 4 years ago

If you have a product, that is a t-shirt. It comes in 100 variations with different sizes and colors. Is it up to the catalog manager to pick one of those to be the "mother product" randomly?

In Vendure, it is not the case that one variant needs to be selected as the "mother product". Rather, the Product is a container of all ProductVariants. In your t-shirt example, the Product would contain a generic description and one or more images applicable to all the tshirts.

What happens when that mother product is out of stock but the children aren't?

The Product does not have any stock level, only ProductVariants.

How does direct linking to a variant product work? In the demo I could not do it.

You are correct that this is not possible in the demo. The demo is very basic. But it would be possible to implement by adding a GraphQL resolver which allows lookup based on Product slug and option codes.

If we upload a shopping feed to Google that needs to compare 5 types of laptops with different amounts of RAM. You can't really upload "Laptop" and link 5 products to that one. You need one unique SKU per model. "Laptop 8GB RAM" etc. Now you would link them to the exact same starting point without the correct selection when a user clicks the ad. And you would end up on "Laptop 2GB RAM", not the ad you clicked on. Google does NOT like that.

Again this would likely require a bit more work in your implementation of the front-end, but should certainly be possible.

But I guess it works if you are small time.

I'm not sure what your definition of "small time" is (or if it is intended as a put-down?). I'm building Vendure primarily with a particular business in mind. We have about 10k SKUs. I am solving our own problems in a way that makes sense for our use-cases and hopefully Vendure also proves useful to other businesses, both larger and smaller.

I'm considering supporting bundled products (i.e. where you can group ProductVariants from disparate Products and group them into one unit for purchase), but it not an immediate priority for me. That's why I'm leaving this issue open, to gauge interest and invite any other feedback. Thank you for yours.

amesas commented 3 years ago

I'm considering supporting bundled products (i.e. where you can group ProductVariants from disparate Products and group them into one unit for purchase), but it not an immediate priority for me. That's why I'm leaving this issue open, to gauge interest and invite any other feedback. Thank you for yours.

Post 1.0? Still on roadmap? Discarded?

michaelbromley commented 3 years ago

@amesas post 1.0 now. I can't add any more stuff otherwise I'll never release it 😆 But definitely not discarded.

seanlai commented 3 years ago

+1 for the bundle feature. A simple entity that can wrap a selection of products + quantity with a custom price would be very useful.

Examples:

  1. bundle camera body + 2 lens for a discounted bundle price.
  2. family pack of 2 adults and 2 children admission tickets
rsat commented 2 years ago

Hi, please don't forget this feature

michaelbromley commented 2 years ago

@rsat not forgotten, just not sure how to fit it in without a breaking change right now. I'm going to add it to the next minor release list so that I don't forget to work on it, but it is very possible that this feature might end up needing to wait until v2.0 (no timeline on that yet).

heiko-r commented 2 years ago

I implemented a bundle feature as a plugin a while ago. It's quite a hack and is missing many features that a generic bundle plugin would need (e.g. we completely ignore taxes, stock levels and shipping costs in our shop), but maybe the rough concept can be helpful.

Our bundles need to be configurable, i.e. the customer can choose from a list of ProductVariants for each bundle 'option'. Example: If I'm selling belts with buckles, and each belt product comes in different length variants, and with a different set of buckles to choose from, the user can pick one length and one buckle and buy them together. So I create an abstract bundle for each belt product, each with two options: The "belt" option includes a list of all the belt's length variants, and the "buckle" option includes a list of all the compatible buckle variants.

It was quite tricky to implement this without modifying the core. It should be possible to search for these bundles, and also to add them to an order. And since only ProductVariants can be added to orders, I finally chose this rather hacky (and also a bit hard to explain) approach:

For each 'abstract' bundle (meaning a bundle that has options, but no choice has been made yet), I create a new Product + ProductVariant. These aren't real, physical items, I'm just abusing them as a vehicle. This ProductVariant is my 'abstract' bundle. It has a custom field with a list of relations to "BundleOption"s (custom entities with a name such as "Belt" and a list of ProductVariants that can be chosen from for this option).

For adding bundles to orders, I added a custom mutation. Basically the frontend will present the customer with choices according to the bundle's options. Then this custom mutation will add the bundle ProductVariant to the order, and save the configuration (which choice was made for which option) in a custom field of the OrderLine. So the bundled ProductVariants will show up nicely as one line under the bundle's name in the order. The bundle price can be dynamically calculated with a custom OrderItemPriceCalculationStrategy. It is then up to the order management system to look at the OrderLine's custom field after checkout, and ship out the chosen ProductVariants.

In theory, this concept is very flexible and should allow for all imaginable kinds of bundles, but has some limitations in Vendure's plugin system, especially I think there's currently no way to integrate this into Vendure's stock tracking.

And this abuse of Products and ProductVariants is also an endless source of confusion for everybody else on the team, so it would be nice to see something more solid as a built-in feature...

michaelbromley commented 2 years ago

@heiko-r Thank you for this detailed write-up!

I'm quite impressed you managed to implement this without modifying the core, but I do agree that this is a bit hacky and we definitely need built-in support for this without all those work-arounds. As I mentioned above, I'm not sure that it is possible without breaking schema changes - in fact after reading your comment I'm fairly sure it will involve breaking changes. But in any case I will revisit this issue and give it some proper consideration soon.

ashitikov commented 2 years ago

I implemented a bundle feature as a plugin a while ago. It's quite a hack and is missing many features that a generic bundle plugin would need (e.g. we completely ignore taxes, stock levels and shipping costs in our shop), but maybe the rough concept can be helpful.

Our bundles need to be configurable, i.e. the customer can choose from a list of ProductVariants for each bundle 'option'. Example: If I'm selling belts with buckles, and each belt product comes in different length variants, and with a different set of buckles to choose from, the user can pick one length and one buckle and buy them together. So I create an abstract bundle for each belt product, each with two options: The "belt" option includes a list of all the belt's length variants, and the "buckle" option includes a list of all the compatible buckle variants.

It was quite tricky to implement this without modifying the core. It should be possible to search for these bundles, and also to add them to an order. And since only ProductVariants can be added to orders, I finally chose this rather hacky (and also a bit hard to explain) approach:

For each 'abstract' bundle (meaning a bundle that has options, but no choice has been made yet), I create a new Product + ProductVariant. These aren't real, physical items, I'm just abusing them as a vehicle. This ProductVariant is my 'abstract' bundle. It has a custom field with a list of relations to "BundleOption"s (custom entities with a name such as "Belt" and a list of ProductVariants that can be chosen from for this option).

For adding bundles to orders, I added a custom mutation. Basically the frontend will present the customer with choices according to the bundle's options. Then this custom mutation will add the bundle ProductVariant to the order, and save the configuration (which choice was made for which option) in a custom field of the OrderLine. So the bundled ProductVariants will show up nicely as one line under the bundle's name in the order. The bundle price can be dynamically calculated with a custom OrderItemPriceCalculationStrategy. It is then up to the order management system to look at the OrderLine's custom field after checkout, and ship out the chosen ProductVariants.

In theory, this concept is very flexible and should allow for all imaginable kinds of bundles, but has some limitations in Vendure's plugin system, especially I think there's currently no way to integrate this into Vendure's stock tracking.

And this abuse of Products and ProductVariants is also an endless source of confusion for everybody else on the team, so it would be nice to see something more solid as a built-in feature...

Recently, I came up to similar solution: Product -> ProductVariant -> Bundler[] -> ProductVariant[]. Each bundler is like a abstract specification, that defines how is the host ProductVariant should be bundled with its children product variants.

So the belt (host product variant) may be bundled with product variants: [1m length, leather, red color], where each option represents set of ProductVariant entitiy. Bundler may define specific rules: you can not bundle belt with two colors, like: [1m length, red color, green color].

From the shop perspective, storefront may use bundlers to show available options to customer. From the order perspective, each bundle flattened, so it comes to 4 order lines, like: [ belt, (parentBundle: null) 1m length, (parentBundle: belt) red color, (parentBundle: belt) green color (parentBundle: belt) ] where parentBundle represents a relational customField that references to bundler and/or product variant. This way storefront may render tree-like hierarchy. As bonus, you get working stock-control out-of-box.

To calculate order price I use OrderItemPriceCalculationStrategy, that honors bundles.

This way we do not abuse Product and ProductVariant entities. Administrator may use ProductVariants for more static and simple products, bundlers for more complex with wide-range options, and mix these strategies.

michaelbromley commented 1 year ago

@ashitikov I'm just returning to this now as I work through the v2.0 features.

If I understand your comment above correctly, you seem to have implemented a satisfactory product bundle plugin without the need to modify core. Is that right? Are any changes needed to the core? Or could we create an official "product bundles" plugin to handle this use-case?

timcv commented 10 months ago

@ashitikov Would you mind sharing the code for your implementation?

busyfingers commented 8 months ago

What is the status of this feature? We have a possible upcoming project where bundle products are one of the requirements.

@ashitikov: would it be possible to take a look at the source code?

devtony01 commented 1 month ago

A product bundle is a product in its own right, with its sku, stock (inventory) and price i.e it could have only one variant (default) or more. Having a separate data structure to keep track of bundles is really redundant