Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved Multi-Vendor Marketplace Support #1329

Closed
michaelbromley opened this issue Jan 6, 2022 · 57 comments
Closed

Improved Multi-Vendor Marketplace Support #1329

michaelbromley opened this issue Jan 6, 2022 · 57 comments
Labels
design 📐 This issue deals with high-level design of a feature type: feature ✨ @vendure/core
Milestone

Comments

@michaelbromley
Copy link
Member

Is your feature request related to a problem? Please describe.
We get a lot of questions about support for multi-vendor marketplaces (MVM). In fact, this is probably the number 1 feature request at the moment. Though it technically is possible to implement this on top of the Channels feature, it is not straightforward and certain scenarios require a bit of hacking to get them working.

With certain changes to the DB schema etc we can 1) make MVM support ready to go "out of the box" and 2) support more advanced features such as multiple active orders for each vendor's products in cart.

Requested Features
I requested suggestions for features on Slack. Here's the responses:

What i would like to have, is multi warehouses.
Warehouses can have same products, but also different products. Same with prices, customers, shipping prices, orders.
I think this would be same princip as multi-tenant / merchant.

We need a feature to make a product exclusive to channel(s) so that they do not appear in the product , products or search (shop-api) query on the default-channel anymore.
Maybe we can make the enabled property channel-aware?

Maybe a tutorial on the "Permission - Role - Channel" relations would be helpful. In my case I want to have 3 Roles per Channel and thats too much. The problem is that users can have different roles per channel and that's why I need 3 unique Roles each. Maybe the relation between a User and a Role should be bound to a channel.
"UserChannelRole" table with userId, channelId, roleId

With a new table like this we could make role assignments exclusive to channels.
My usecase for this is that I want to create default roles like: Moderator, Member, Ambassador.
But I don't want to create them for every channel because a user can be a Member of one Channel and a Moderator of another.
This function userHasPermissionOnChannel in role.service should also be easy to do. Just query based on User and Channel from request context and we get all roles for the requesting user.
image (4)

Hi, maybe with currentOrder group by channel? I mean if you add 2 products from 2 different shops, you should get 2 orders

@AndersGerner
Copy link

@michaelbromley We are very interested in this feature, and we are trying to create it right now, with channels.
Currently, our setup does not require payment, but we are looking to create a cart, that is divided by the different channels.

Our current status is, that we are using Vercel Commerce as the storefront and have adjusted it, so "Designers" are channels and it sorts/filters products perfectly with name, price, and categories.

This is totally out of context so I understand if it does not make total sense, but: We would like to have a full-blown multi-vendor shop within the next 3 months, so if we can help with brainstorming you are more than welcome to reach out.
I would also like to help with the development as well, but we are just a small startup and I am currently the only developer, so I don't have much spare time, but maybe by helping you, I would make it easier for us to reach the multi-vendor store we dream of.

Just a short description of us: We are a startup in Denmark, trying to help retail stores - especially those highly affected by Covid-19 - showcase what they have in their store, and make it easy for their customers to find them and their products. Our mission is to help them keep their dream of being a store owner alive :)

Bottom line: If we can help in any way, brainstorming, testing, development, or something else, don't hesitate to reach out

@michaelbromley
Copy link
Member Author

Hi @AndersGerner! I'm definitely interested to learn more about your use-case & discuss the potential of collaboration. Reach out to me via contact[at]vendure.io or via Twitter and let's chat.

@magick93
Copy link

magick93 commented Mar 17, 2022

Hello

I'm looking for similar functionality, though to call it multi-vendor is perhaps too overloaded.

Essentially I'm looking for the ability for a product buyer to immediately be able re-list that item for sale. Essentially a marketplace where users have the ability / role of both buyers and sellers.

Could this be done as a plugin, or would it need core level changes?

@michaelbromley
Copy link
Member Author

@magick93 This could already be implemented in v1.x as a plugin - as to the exact implementation there are a number of ways to do it depending on your particular workflows & requirements. I know of several projects already under development that follow a similar model. If you join our Slack group you might be able to connect with someone about this.

@Draykee
Copy link
Contributor

Draykee commented Apr 2, 2022

I'm still pretty curious about the restructuring of the channel roles relations. Are there any updates on that?

@michaelbromley
Copy link
Member Author

@Draykee not started work on this feature yet.

@michaelbromley michaelbromley added the design 📐 This issue deals with high-level design of a feature label Apr 5, 2022
@pbalakri
Copy link

pbalakri commented Apr 9, 2022

  • As a business,
  1. I would like to create a sign up process for multiple vendors to upload KYC type documents, along with user-name and password so that I can approve/reject their accounts as an administrator.
  2. For approved vendors, I can create a default commission rate for every product sold per vendor.
  3. For approved vendors, I can create different commission rates for products sold per category per vendor.
  4. For vendors with negative reviews, I can disable the vendor from my platform.
  5. For vendors with negative reviews, after corrective actions by vendor, I can re-enable the vendor on my platform.

@pbalakri
Copy link

pbalakri commented Apr 9, 2022

  • As a Vendor,
  1. I can see the entire product catalog of the business.
  2. If the product I sell is already present in the catalog, I can create a new offer on the product where an Offer = Selling Price + Discount Price + Stock + Stock Location + Delivery Promise ( days to deliver)
  3. I can de-list an offer on a product if it goes out of stock or WILL no longer be sold
  4. If the product I see if NOT already present in the catalog, I can create the meta data of the product and submit for approval by business administrator. Once approved, I can list the offer using previous requirement.
  5. I can see shipment meta data of all orders placed that contain my (and ONLY MY) offers.
  6. I can change status of my shipments to ACCEPTED/REJECTED/PACKED/DISPATCHED (To be fleshed out some more i.e. do I want to change each item status in the shipment or the entire shipment as a whole)
  7. I can view reports on best selling items, my price competitiveness against other vendors, best selling categories, states of shipments, etc.

@pbalakri
Copy link

pbalakri commented Apr 9, 2022

  • As a Customer,
  1. If multiple vendors sell the same product, when I search for the product, I should see that product once in the search results with an indicator that there are multiple offers for that product.
  2. If multiple vendors sell the same product, when I am on the PDP of the product, I should be able to continue to see all variations of the product grouped by vendors.
  3. If multiple vendors sell the same product, when I land on the PDP of the product, I should be able to see if there are cheaper offers, faster delivery promises, or more reliable deliveries from other vendors.
  4. I should be able to review the delivery experience for a particular vendor which is available for the vendor and other future customers.

@khawarizmus
Copy link

  • As a Customer,
  1. If multiple vendors sell the same product, when I search for the product, I should see that product once in the search results with an indicator that there are multiple offers for that product.

I would say that if a customer searches for a product they should see all the products that are offered by the different vendors on the marketplace.

@Draykee
Copy link
Contributor

Draykee commented Apr 10, 2022

I would say that if a customer searches for a product they should see all the products that are offered by the different vendors on the marketplace.

For my usecase this would be bad. I need all channels to be exclusive and only accessable to selected customers.

@pbalakri
Copy link

pbalakri commented Apr 11, 2022

  • As a Customer,
  1. If multiple vendors sell the same product, when I search for the product, I should see that product once in the search results with an indicator that there are multiple offers for that product.

I would say that if a customer searches for a product they should see all the products that are offered by the different vendors on the marketplace.

Fair point to generalize this, merging some implementation detail.
When I search in Default channel, I should see all products from all channels as usual. If the same product is sold by multiple vendors, we should still see one product with each vendor's offer as a possible variant for that product.

Example 1:
Vendor A and B sell a FOOBAR brand Shirt in size XL and color RED with a globally identifiable SKU 1111.
Additionally, Vendor A and B sell exclusive private label products with SKUs '2222' and '3333' respectively.
In the DEFAULT channel, Customer when searching should see only ONE entry of "1111", instead of TWO.
In the DEFAULT channel, Customer when searching should see TWO entries with '2222' and '3333'.
In Vendor specific channels, Customer should only see that Vendor's offer as it is today.

@alexcode
Copy link
Contributor

Hi @michaelbromley, very interesting feature.
On my use-case, I'm using a Channel for each vendor. The problem I faced was to be able to retrieve multiple orders in the same cart.
To circumvent the current limitations, I'm adding acustomField relation between a Session and an Order to be able to retrieve multiple orders.

{
    name: 'session',
    type: 'relation',
    entity: AnonymousSession,
    graphQLType: 'Session',
    nullable: true,
    eager: false,
    internal: false,
}

Currently, I'm using TypeORM events to update the relations and custom GraphQL to retrieve orders.
As you imagine, in the frontend, activeOrder and activeChannel aren't that useful in my case.

On the payment side, I'm using a marketplace provider (Mangopay) with a e-wallet model which can be challenging on the payment handler side.

@michaelbromley michaelbromley pinned this issue Apr 13, 2022
@khawarizmus
Copy link

khawarizmus commented Apr 25, 2022

I wanted to go ahead and describe a multi-tenant use case that we want to make it work with Vendure.
The idea is to have a marketplace where people search for products to by and can also open a store (channel) to sell products. here are some of the point i think might need to happen for that to be possible:

  • Users who signup are by default customers then can open a store on the marketplace (channel) so have their roles upgraded to admin. I noticed that the current implementation prevents that here.
  • The above comes with onboarding, KYC, KYB etc..
  • Stores (channels) should have their own products, variants, prices, etc..
  • The default channel can be configured to be independent or other channels or an aggregator of all products
  • A global product search should be available (searching for a product across the market place i.e all channels)
  • A global search should search all matching results across the market place even if duplicate (from two different stores)
  • When browsing the marketplace a customer can add to cart multiple products from multiple stores (channels) and do a single checkout.
  • Each store (channel) can have it's own delivery fees, taxes, promotions, delivery options etc..
  • Categories are global and can be under the default channel
  • The default channel has super admins that have access to all stores (channels) for moderation purposes.

I am not sure if i listed all the points but i would be open for discussions on how to do this with the current Vendure and with this initiative right here.

@JustDenP
Copy link
Contributor

One of the necessary functions for marketplaces is the money withdraw for sellers.

In more complex systems, this is achieved by using separate payments, such as stripe Connect or PayPal marketplace. The data for withdrawal and the preferred payment system the vendor specifies in their dashboard.

In simpler systems, where the marketplace is only one of the system options and is not emphasized, the system works like this:
Each seller has a virtual wallet inside dashboard, on which the amount of orders is summarized (minus marketplace commission), then he can make a payout request, entering how much of the available to him money he wants to withdraw and chooses a payment system (paypal, bank account, etc.), then this request sees superadmin, transfers money to the vendor manually and puts the status of the request as approved

Also, the marketplaces themselves exist on commissions from the sales of vendors.
Do you plan to add this functionality in version 2.0? Thank you

@michaelbromley
Copy link
Member Author

@JustDenP Thanks for this insight.

The most important thing I want to get in v2 is that we have a correct data model to support marketplace-like apps. It's likely that we will not ship v2 with full support for all the major features of a marketplace, but as long as the underlying data model is correct we'll be able to incrementally increase support for richer marketplace features in subsequent versions (or make it much simpler for you to implement such features as plugins).

@amadeus-torwell
Copy link
Contributor

Is there a design picture of the fully fledged version of this feature? Like what happens to facets (will they be shared between channels etc.)

@dnk8n
Copy link

dnk8n commented Dec 31, 2022

Is any of the work/discussion here useful to break down some of the unknowns? https://github.com/Saleor-Multi-Vendor/saleor-multi-vendor (also see the issue tracker for more info)

@mariusa
Copy link

mariusa commented Jan 3, 2023

While this is being considered, I think another use case is Multi-tenant support, within a single schema.
This would allow a single instance of Vendore to host multiple merchants, each with their own store. Exactly like Shopify, anyone can signup to have their own shop, customers, orders, payment methods etc.

Could this be included in the redesign? It's a major request for other open source commerce apps (not supported out of the box, but with cumbersome workarounds such as https://medusajs.com/blog/medusa-extender ), and would be a great differentiator for Vendure.

@michaelbromley
Copy link
Member Author

michaelbromley commented Jan 3, 2023

@dnk8n thanks for the pointer - I was searching for existing multivendor open source implementations to study and they are hard to find! I'll definitely look into this.

@mariusa the multi-tenant story is already fairly well supported - see these docs. There might well still be some improvements we can make, but I already know of multi-tenant projects already in production.

@mariusa
Copy link

mariusa commented Jan 3, 2023

Thanks Michael,

Sorry to say this, but the current multi-tenant support seems a workaround. If you compare with Shopify, a shop can have multiple markets (currencies, countries...) and multiple users, which are managed by the merchant (shop owner). The "Ace Parts" business from the docs example could simply signup at cloud.vendure.io, create channels for themselves (eg online store, Amazon, Etsy...), define markets and so on. They wouldn't need a super admin to create an user & channel for them.

@michaelbromley
Copy link
Member Author

@mariusa I see. Yes, making Vendure as capable as a multi-tenant solution like Shopify is not a priority right now - the current multi-tenant functionality is more suitable to a project wherein the tenants are controlled by a central admin, who can grant access to owners of individual stores. But if you did want to make it self-serve like Shopify, you can create a custom mutation that does all the needed steps of creating a new channel, creating a role and admin, assigning permissions etc. I believe some projects have implemented such a feature.

michaelbromley added a commit that referenced this issue Jan 6, 2023
Relates to #1329. This implements the "partial order" concept (renamed to VendorOrder). This commit
includes just the bare minimum data model changes and assignment flow.
@michaelbromley
Copy link
Member Author

Update after experimenting for a couple of days of different approaches:

Using the Partial Order (VendorOrder) method does allow us to correctly split up OrderLines between the various vendors (channels), but there are numerous complexities that then need to be handled:

  1. Order history needs to be scoped to each vendor. I.e. we do not want a global history viewable by all vendors, as it may e.g. contain notes by Vendor A which are then visible by Vendor B.
  2. Calculation of totals. This could be done on-the-fly using a get total(): number getter, but this will very likely be a performance drag. So we'd probably end up calculating the prices for each VendorOrder whenever the order is modified. This quite significantly complicates the order calculation function.
  3. The question of order state is complex: if all VendorOrders share the state of the parent Order, it might be confusing to Vendor A why the order state is still "partially shipped" when all of their OrderLines have been shipped, yet Vendor B did not yet ship.
  4. If an Order needs modification after being placed, this will get really complex. We'd need to scope each modification to a given VendorOrder, but changes to it could affect prices for all VendorOrders, e.g. is a Order-level promotion becomes invalid, or if shipping costs change.
  5. We need to maintain both Order and VendorOrder entities, GraphQL types, and probably introduce GraphQL union types in those GraphQL queries that currently just return Order.

There are probably dozens more hidden complexities with this design. Thus I'm proposing a totally different approach which aims to eliminate all of these issues

Let's call this "nested orders"

Nested Orders

image

In this model, there are no new entities needed. Only the existing Order entity, but with a few additions:

class Order {
  type: 'regular' | 'aggregate' | 'vendor'
  vendorOrders: Order[];
  parentOrder?: Order;
}

A regular order works exactly like an Order currently works. Absolutely no changes should be needed for non-multivendor apps.

For multivendor apps, the flow would work like this:

  1. Customer adds items to Order as usual. This step works exactly as it does currently.
  2. When completing the order, we are now able to split this into an aggregate Order, and one or more vendor Orders. This would be handled by a configurable strategy, allowing each implementation to define exactly how this split should be determined. Each vendor order will be assigned to a specific Channel, and the aggregate Order will be assigned only to the default Channel.
  3. In this way, each vendor Order is totally isolated and stand-alone, containing only the lines, history, payments, fulfillments etc. that pertain to that specific vendor. This means we can basically re-use all the existing logic without needing to add all the complexity handling listed above.

michaelbromley added a commit that referenced this issue Jan 9, 2023
This commit implements an experiment on getting vendor-specific order data from the `order` query
in the Admin API. In exploring this, many complexities with this design became apparent, which I
detail here: #1329 (comment)

So I'm just committing this for future reference and then I will start on a different design, the
"nested orders" idea.
@Draykee
Copy link
Contributor

Draykee commented Jan 9, 2023

I like the idea of nested order. This would make the way migration easier!

I had a few other thoughts as well:

  • There should be custom calculation strategies for the order total. By using a configurable strategy we would be able to add vouchers, service fees and stuff like discounts for a certain quantity of products.
  • Maybe we can add a new entity for the "Payout" that gives instructions on were to distribute the money a customer payed
  • For a 'marketplace' I though that a vendor can also be a user. Is it possible to connect the vendor with a user? Both vendor and customer should then have access to an order.
  • Given the idea, that vendors can also have access to the Admin UI - I still think that the permission model needs an update (like the one ER model in your initial post)

@michaelbromley
Copy link
Member Author

@Draykee Thanks for the suggestions!

There should be custom calculation strategies for the order total. By using a configurable strategy we would be able to add vouchers, service fees and stuff like discounts for a certain quantity of products.

This sounds like a separate feature request, but may already be covered by existing & planned functionality: vouchers & discounts are handled by Promotions. Service fees can be implemented as Surcharges. Discounts based on quantity is planned as an extension to the OrderItemPriceCalculationStrategy by passing in the quantity.

Maybe we can add a new entity for the "Payout" that gives instructions on were to distribute the money a customer payed

Possibly - I've not figured out that part quite yet. Part of this depends on the business model of the marketplace: some marketplaces will not hold funds for sellers, but will use something like Stripe Connect so that the seller is paid immediately by the customer. In all cases, it might be possible to just use the existing Payment entity, and have a type of PaymentHandler which represents payouts as in your scenario. Needs further exploration.

For a 'marketplace' I though that a vendor can also be a user. Is it possible to connect the vendor with a user? Both vendor and customer should then have access to an order.
Given the idea, that vendors can also have access to the Admin UI - I still think that the permission model needs an update (like the one ER model in your initial post)

I plan to revisit permissions & especially as they relate to Customers vs Admins. For now I'm just concentrating on the Order mechanics.


Split orders: prior art

Unrelated, but I'm just gonna dump some prior art links here that I've found:

@gilesbutler
Copy link

Hi there,
I just came across this issue after looking for a multivendor marketplace solution. I'm wondering if you have a rough eta of when it will be released at all? I appreciate it's an ongoing issue and is very complex.

@michaelbromley
Copy link
Member Author

Hi @gilesbutler I'm hoping to have a beta version available around the end of February. We publish pre-releases quite regularly on the next npm tag, it's likely that the next prerelease will include the work I've done so far on multivendor, which by the end of next week should hopefully be usable.

@gilesbutler
Copy link

Amazing to hear @michaelbromley and thanks for getting back so quickly! Look forward to giving it a test on the next tag next week!

@michaelbromley
Copy link
Member Author

Video update on the latest progress (which is now merged into the major branch but not yet released to npm): https://youtu.be/jTOhzrA1baQ

@dnk8n
Copy link

dnk8n commented Jan 19, 2023

Amazing work @michaelbromley

Just watched the video. Interested to know if you were able to study Spree's multivendor functionality. You have made an evidently tricky feature so much more accessible to the open-source community. You should be very proud of those achievements!

@ivasilov
Copy link

Great work @michaelbromley!

From the video, it looks like the aggregate order doesn't have a fullfilment. This could be useful if vendors are shipping to a common distributor which packs the partial orders together and ships them out.

@JustDenP
Copy link
Contributor

Cool! Another question about future multi-vendor functionality:
Can each vendor create their own variations with attributes or will only the superadmin be able to create a predefined template for them?

@michaelbromley
Copy link
Member Author

@ivasilov It will be possible for either the aggregate order or the seller orders to control the fulfillment flow. Part of the work I did on this was to extract all the previously hard-coded logic around automatic Order state transitions etc. into the configurable order process. This means you can completely skip the default behaviour and tailor the flow exactly to your needs.

@JustDenP Yes, each seller can create their own products & variants if their role has the required permissions. So this is something you can control depending on the requirements of your marketplace app.

@yayza
Copy link

yayza commented Jan 21, 2023

In my use case I don't need one order to split between multiple vendors, but instead one cart per vendor like instacart, and also have a "global" catalog of products where vendors can just search and choose to list products from the catalog, only needing to change price and inventory information. Is this possible with v1?

@petercn
Copy link

petercn commented Feb 10, 2023

Excellent work @michaelbromley Do you have an ETA on when this functionality will be published to npm under 2.0 next versions?

@michaelbromley michaelbromley moved this from 🏗 In progress to 🔖 Ready in Vendure OS Roadmap Feb 22, 2023
@mpacary
Copy link
Contributor

mpacary commented Mar 7, 2023

@petercn In my dev env, after replacing packages versions with 2.0.0-next.28 and migrating the database with migration:generate & migration:run, I can see the new "seller" section in the admin menu 👍

EDIT: according to this Readme file, the migration:run step is even optional.

@petercn
Copy link

petercn commented Mar 7, 2023

@mpacary Thank you for confirming the feature in 2.0.0-next.28, I might have still been on 2.0.0-next.27 or failed to do the migration when I tried it out a few weeks ago. I'll give it a shot again

@adamtang79
Copy link

Hi, is multi-vendor marketplace feature included in v2 core?

@michaelbromley
Copy link
Member Author

@adamtang79 Yes - though it's not so much as single "features" as a set of APIs that unlock this kind of application. I'm right now working on a guide to these new APIs which will form part of the v2 docs when we release later this week!

@michaelbromley michaelbromley moved this from 🔖 Ready to ✅ Done in Vendure OS Roadmap Jun 22, 2023
@michaelbromley michaelbromley unpinned this issue Dec 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design 📐 This issue deals with high-level design of a feature type: feature ✨ @vendure/core
Projects
Archived in project
Development

No branches or pull requests