Getting orders to you: our evolving supply chain

Santiago Lanus
Mercadona Tech
Published in
7 min readNov 24, 2021
Photo by Joey Kyber on Unsplash

Having infinite fresh-as-can-be stock of every product in the catalog available 24/7 has to be the ideal and perfect scenario for online grocery shopping providers. The flip side to this is having to throw out unsold stale products every day. In Mercadona Tech we don’t seek perfection but rather challenge ourselves to iterate and improve constantly. This is also the case for supplying our hives (warehouses). There are explicit constraints in mind: delivering to our customers everything they ordered, reducing the stock to a minimum while also avoiding the throwing-out part. This is the story of the iteration journey behind this process, one which is far from finished.

It all started way back in 2018 with only one hive in Valencia, delivering only a few orders each day. At that time, only two applications existed: Shop and Logistics. Supplying the hive was achieved by executing a cronjob in the Logistics app, which was responsible for asking the Shop API about all the orders to be delivered the following day, right after the cut-off time; no orders can be edited or canceled after that. The API response was a JSON containing every order’s information and lines. After that, it was just a matter of grouping products together and aggregating quantities. This was all then represented in a Django form where internal users (our hive workers) could verify the information and add/remove units in case they had more information that the system was not taking into account. Sending this form would insert one record for each product in a database, which served as communication between Mercadona Tech and Mercadona’s logistics warehouses. After that, magic would happen, and products would be delivered to the hive.

Photo by Kendall Henderson on Unsplash

Months went by, and it became evident that the supply order needed a dedicated team, with its application and codebase, and in December 2018, the Supply vertical was born. Our main goal was to replace the existing features to create a solid base for the new ones while also removing code from the old codebase. In a way, it’s just like the refactoring step in TDD; rearranging and modifying code without affecting the end result, the beloved green test. Not long after this part was finished, the number of daily orders had grown significantly, and having a single thread querying all orders and storing them and every line in the database was not going to scale well. It was time to get our hands dirty!

What if instead of actively asking for all the orders for a given day at once, and then having to process that big bunch of information in one go, we could just receive them as soon as they were generated? This would mean having a constant flow of information instead of a big bang once a day, although on the other hand, it would also mean receiving confirmed orders before the cut-off time, which could have had products added or removed, had their delivery date changed, been canceled, all of which we would also need to know about. Enter Google Cloud Pub/Sub. Although this is not an article about Pub/Sub, it is important to note that its incorporation was a huge milestone in Mercadona Tech’s architecture in general and a huge improvement in Supply orders in particular. This helped boost performance, responses times and remove one of the biggest points of failure.

As time went by, the number of available slots had to be increased because more clients with bigger orders were filling our capacity, while the hive physical space remained the same. At this point, we were receiving trucks to the brim filled with products which were then unloaded and needed to be taken to their respective temperature areas.

However, since clients can receive their deliveries from 7 a.m. to 10 p.m., most of the products received were not going to be needed for preparation until many hours later. This meant having unnecessary stock for half a day taking up space that was not always available, and sometimes hindering other processes. The solution for this was to have two different supply orders, one for orders to be delivered before 3 p.m. and another one for the rest. As simple as it sounds, it was one of the biggest challenges in the vertical’s early stages.

The reason for this is, even though the two orders were created one after the other, the stock we had available for the first order was whatever we had in the hive at that time, but for the second order it had to be calculated based on the current stock, minus excesses from the first order (based on rounding).

What’s more, after having two supply orders, the idea arose of moving one of the first orders before the cut-off time. So now, not only did we have to support more than one supply order, but also take into account that some products could already have been ordered to Mercadona’s warehouses, but client orders for those products could be modified, rescheduled, or even canceled. Boy, was it an interesting day when we implemented these features…

Up until this point, n supply orders could be sent each day for any of the different temperature areas, for client orders received at any time of day for any future delivery date. So what’s the problem, amigo? Users still have to remember to access the Django form at a certain time for each of the areas, check all of the 200+ lines and in the best-case scenario, they don’t have to change what the system anticipated as the amount to be ordered, and just click the send button. The questions then arise of

“When, where, what, how, and why do they have to change what the system suggested?”

The answer to all of these questions is best represented as follows:

However, like all important answers, stocks deserve their own post. Or posts. For now, let’s just say there was a lot of data involved in figuring out which products’ suggested quantities were being modified by users, and thus, investigating the reasons behind this.

In some cases, all that was needed to avoid users changing suggested quantities was adding a safety stock, so that if 123 kg of oranges had been sold, we would consider as if 20% more of that was really needed. In some other cases, it involved stock operations being performed before the order. But ultimately… the next post.

We travel to March 2020, where COVID is hitting the world, and users are still accessing the same old Django form, modifying nothing, and sending. Unacceptable. It was time to automate this task, which had become trivial. At this point, we could end the post just by saying we created a cronjob for each supply order and that was that. However, there is no fun in that. The way we handled cronjobs at this point in our lives was by creating a file in our infrastructure-as-code codebase and applying it manually in Kubernetes.

We thought it would be interesting to implement cronjobs in our own application, so that we could manage them from the good ol’ Django admin in real-time, without having to go through all the hassle.

Cronjob configuration for supply orders

Since then, the system has been tweaked here and there but the core remains the same. Users no longer have to worry about supply orders, either changing quantities or sending the form manually. What’s more, they don’t have to worry about them failing, as we’ve been learning when they did fail and either retrying or configuring alerts when we have inconsistent product data and fixing it before orders are automatically sent. All interested parties have to do is lay back and wait for Slack notifications to be sent to the specific hive channel.

In Mercadona Tech we iterate, we make mistakes, we learn, we try new things; we think about our users, our systems, about scaling while also challenging us technically.

This has also been true for supply orders, which are living happily and quietly, doing what they do every day without any attention. They have changed a lot throughout the years, and are always open for the next iteration, for new ideas, suggestions, and improvements.

If you are interested in this or any of our many other challenges, you are more than welcome to take a look at our open positions.

--

--