Implement Order Splitting
Build your own marketplace from scratch using Medusa
Many of you have been waiting for this part, so here we’re going to cover how to manage orders for each seller. Indeed, the most logical and widely used way is the one outlined by @Shahed Nasser in her tutorial series that inspired perseides.
What’s the goal here ?
To ensure that our vendors can process their orders independently, we’re going to extend the Order entity to add some new features, for example, we will split an Order into multiple child orders, allowing a vendor to only access its order and the items they need to fulfill.
Extend the Order
Extend the Order entity
First, we’ll extend the entity we’re getting used to :
Here we have added :
-
a
store_id
as on our previous entities -
a new
order_parent_id
column, which is nullable, allowing us to know whether an order has a parent or not -
relations that allow us to find out the parent or children of an order
Updating the Store entity
As usual, we’ve added a relationship that points to our Store, so we’ll need to update it to add the orders property to the Store entity :
Create the migration
Once the entity and repository have been extended, it’s time for the migration :
We can add thoses new features by updating the up and down functions :
We can apply our changes by launching the server with yarn build
and npx medusa migrations run
.
Extend the OrderService
Ready to start integrating our features ? We’ll make sure to only list the orders linked to a Store
, and for the first time we’ll also see how to prevent a Store
from accessing an Order
that do not belongs to it :
Three functions have been overrided in the above code. For the first two, if you’ve followed the previous sections, they simply add a WHERE
condition to our SQL query to target a specific store_id
if we have a logged in user with a store id.
For the retrieve
function, which allows us to retrieve an order, here we retrieve the Order with its associated store (or not, in the case of a parent Order) with the original function.
And we take care to validate after we have the Order, to compare the store_id
of the order with that of the logged-in user.
Don’t forget that in our marketplace logic, if a user doesn’t have a store_id
, they considered admin.
Create Order’s subscribers
Ok so get ready, this part will be a little longer, but I assure you it’s essential to your marketplace.
As I said at the beginning of this part, the idea is to split an order into several child orders, based on each store in an order.
For example, if the customer has created an order with 3 different products, all from a different store (3 different stores), we’d expect 3 different orders.
Order Placed Event
Create the Order placed subscriber
Here, I’ll create a folder inside the src/subscribers
folder and name it orders
, so that all subscribers linked to orders will be inside.
We can now create the order-placed.ts
subscriber inside that new folder :
For the moment, we’re going to keep things very simple and simply have this piece of code that we’ll feed in as we go along.
By the way, it reminds me that this is the first time we’re going to use the manager
.
The manager will enable us to create a transaction, which will be very useful here and we have already used in the previous part quickly.
A transaction is a way to ensure that multiple database operations are executed as a single atomic unit of work.
This means that either all operations succeed and are committed to the database, or if any operation fails, all operations are rolled back and the database remains unchanged.
(Pretty cool, right?)
Retrieve the Order placed
First, we’ll retrieve the order that has just been created and intercepted by our subscriber :
Grouping LineItems by Store
It’s easier to group products by store so you know how many distinct stores there are, and it will make creating a child order easier :
Creating a child Order for each store
Just below the code above, we will begin a loop on each item in our Map to construct a child order for each of the shops, including all of the LineItems indicated above :
Create a ShippingMethod for each child order
Still inside the loop, we’ll create a ShippingMethod for each store, so that each store can manage the progress of the delivery independently. If you don’t know the difference between a ShippingMethod and a ShippingOption, I invite you to read this part of the documentation
Complete implementation
Perfect! We now have a way of splitting an Order into several child Orders!
However, we still need to listen to other Order events.
Order Updated Event
Here, we’re going to intercept an order whenever it has been updated. The idea is to be able to update the parent Order according to the status of its children :
Create a subscriber that will update the child order’s status
Medusa doesn’t implement any predefined conditions for setting the status of an order to completed
, in our example below.
In our example below, we’ll set the status of an Order
to complete
when :
-
This order has a
payment_status
ofcompleted
. -
This order has a
fulfillment_status
ofcompleted
. -
We’ll also make sure that the order in question hasn’t been
canceled
,archived
or alreadycompleted
This is an example, you can of course adjust to your needs.
And now you’ve successfully implemented the splitting of one order into several for each Store! Granted, this part of the program was rather heavy and involved a lot of different concepts, so don’t hesitate to take the time to reread the code and try to understand the integrated flow.
If you have any questions, you can send me a DM on Twitter/X or on the official Medusa Discord!
Common Issues
I have types errors!
Do not forget to update you index.d.ts
file created earlier, at this point, and what we have used, you should have an index.d.ts
file that looks like this :
GitHub Branch
You can access the complete part’s code here.
Next Steps
The next part will be a little special, we’ll be looking at Payments entity, and we’ll be extending it, but this will be more of an exercise for you, of course the solution will also be included, but it might be nice to practice customizing an entity on your own.
Was this page helpful?