Requisition Lists in Magento 2: Understanding Recurring Order Lists Technically
AI generated
M2
di.xml
Magento 2 · B2B Suite
Requisition Lists
Understanding recurring order lists at a technical level

Requisition Lists are the B2B tool for repeat customers who regularly order the same line items, with their own data model, their own API, and a clear functional distinction from wishlists. Building a custom frontend integration means knowing how the data model is structured, which API operations are available, and where the default feature reaches its limits.

11 min read Requisition Lists · B2B Suite Magento 2.4.x Commerce

1. Placing Requisition Lists in the B2B module

Requisition Lists are part of the Magento_RequisitionList module from the B2B Suite and solve a very concrete problem: company customers frequently order the same or very similar line items again and again, such as consumables or spare parts, and do not want to search the catalog from scratch every time. At its core, a Requisition List is a named, reusable collection of SKUs with fixed quantities attached, which can be pulled into the cart in full or in part.

Unlike many other B2B features, a Requisition List is not tied to a company but to the individual customer. Two employees of the same company therefore do not see the same lists by default, even when connected through the same company, which is a relevant design decision for many projects once shared order templates within a team come into play.

2. The data model: requisition_list and requisition_list_item

Technically a Requisition List consists of two tables: requisition_list with the fields requisition_list_id, customer_id, name, and description, and requisition_list_item with sku, qty, requisition_list_id as a foreign key, and a serialized additional_options field for product options such as configurable attributes or custom text fields. The actual product reference is made through the SKU, not the internal product ID, which matters when SKUs change in the catalog.

Because additional_options is stored serialized, a saved item cannot simply be filtered by a specific product option through a plain SQL filter. For custom reporting, such as a report on the most frequently stored configurations across lists, the serialized data first has to be deserialized through the corresponding serializer classes before it can be analyzed in a structured way.

3. Requisition List vs. wishlist: the functional difference

At first glance, Requisition Lists and wishlists look similar; both store a named list of products for a customer. The key difference is purpose: a wishlist is built for saving and potentially sharing, with optional comments and a sharing function through a public link. A Requisition List, in contrast, has a purely operational purpose: fast, repeated ordering with a fixed quantity stored per line item.

In practice this shows up in the available actions. Requisition Lists allow adding the entire list to the cart, including quantity adjustments, in a single step, while a wishlist is geared more toward adding individual products one at a time. A Requisition List also does not support public visibility or sharing with other users out of the box; it stays strictly bound to the customer who created it.

4. API access for custom frontend integrations

For custom frontends, both service contracts like RequisitionListRepositoryInterface and RequisitionListItemRepositoryInterface, and a GraphQL layer, are available. The requisitionLists GraphQL query returns a logged-in customer's lists including their items, while mutations such as createRequisitionList and addProductsToRequisitionList handle creation and populating them.

For the actual ordering step, the addRequisitionListToCart mutation matters, validating either the full list or a selected subset of items and moving them into the active cart. Validation runs per item separately, so a single faulty item, for example a product that has since been disabled, does not necessarily block the entire action but is reported back as an individual error in the result.


mutation AddRequisitionListToCart {
  addRequisitionListToCart(
    cartId: "abc123cartid"
    requisitionListId: "42"
    requisitionListItemIds: ["101", "102", "103"]
  ) {
    cart {
      id
      total_quantity
    }
    userErrors {
      requisition_list_item_id
      message
      code
    }
  }
}

5. Adding custom quantity rules via plugin

A common extension case is an additional quantity validation, for example when a product may only be ordered in multiples of a pack size. A plugin on RequisitionListItemRepositoryInterface::save is the right fit, checking before the actual save whether the stored quantity matches the product's configured pack size, and throwing a LocalizedException otherwise.

This check should consistently apply at the same point where the item later gets added to the cart, since otherwise invalid quantities, while not stored in the list, could still be ordered through another path such as direct product detail page access. A consistent rule therefore belongs in a central, reusable validator rather than in a single isolated plugin.


<?php

declare(strict_types=1);

namespace Mironsoft\RequisitionListExtension\Plugin;

use Magento\Framework\Exception\LocalizedException;
use Magento\RequisitionList\Api\Data\RequisitionListItemInterface;
use Magento\RequisitionList\Api\RequisitionListItemRepositoryInterface;
use Mironsoft\RequisitionListExtension\Model\PackSizeValidator;

/**
 * Ensures quantities on requisition list items are a multiple of the
 * product's configured pack size.
 */
class ValidatePackSizePlugin
{
    /**
     * @param PackSizeValidator $packSizeValidator
     */
    public function __construct(private readonly PackSizeValidator $packSizeValidator)
    {
    }

    /**
     * @param RequisitionListItemRepositoryInterface $subject
     * @param RequisitionListItemInterface $item
     * @return array{RequisitionListItemInterface}
     * @throws LocalizedException
     */
    public function beforeSave(
        RequisitionListItemRepositoryInterface $subject,
        RequisitionListItemInterface $item,
    ): array {
        if (!$this->packSizeValidator->isValidQty($item->getSku(), (float) $item->getQty())) {
            throw new LocalizedException(__('Quantity must be a multiple of the pack size.'));
        }

        return [$item];
    }
}

6. Typical use cases for repeat customers

In practice, Requisition Lists pay off most where orders occur regularly and predictably. A classic example is maintenance teams ordering the same spare parts for a given machine every month, or branch locations regularly reordering a standardized set of consumables in fixed quantities, without having to gather the right products from scratch every time.

Another common use case is quickly repeating a previous order: instead of manually duplicating a past order, the customer creates the relevant items as a Requisition List once and only adjusts quantities on each subsequent order, which noticeably speeds up the ordering process and reduces SKU typos that are more likely when searching the catalog manually.

7. Permissions: no team sharing out of the box

An important limitation that is often overlooked when planning custom extensions: Requisition Lists are strictly bound to the creating customer in the default feature set and are not automatically visible to other members of the same company. Anyone wanting a shared order template across a team has to add that functionality explicitly, for example through an extra visibility attribute at the company level and a correspondingly extended repository query.

For such an extension, it makes sense to add a visibility column to the existing requisition_list table and extend the default collection with an additional filter through a plugin, rather than replacing the entire repository implementation. That keeps compatibility with future Magento updates and the existing GraphQL layer largely intact.

8. Performance with large lists

For lists with several hundred items, validation when adding to cart noticeably affects response time, because price, availability, and configuration options are checked individually for every item. For very large lists, it is worth calling addRequisitionListToCart in smaller batches instead of the full list at once, to limit both response time and the risk of a timeout with slow external price sources.

For recurring, plannable use, such as an automated nightly conversion of certain requisition lists into orders through an external procurement system, it is also worth reusing the same validation path as the frontend rather than implementing separate, diverging logic, so frontend and automation behavior do not drift apart over time.

9. Maintaining stale lists

Since Requisition Lists persist indefinitely and do not expire automatically, lists accumulate over the years that contain items referencing products that have since been disabled or discontinued. Without custom maintenance, such orphaned entries persist indefinitely and lead to validation errors when the list is added to the cart, errors that are hard for the customer to understand without context.

A worthwhile addition is a regular batch job that identifies items referencing SKUs that no longer exist or are permanently disabled, and either removes them automatically or flags them for the customer on next login as stale, so the list retains its practical value as a reliable order template.

Feature Wishlist Requisition List
Primary purpose Saving and sharing Fast, repeated ordering
Team sharing Public link possible Not without custom extension
Quantity per item Usually 1, editable Fixed, meant for reordering
Full cart transfer Not built in by default Through addRequisitionListToCart
Ownership Bound to the customer Bound to the customer, not the company
Typical user End customer in a B2C context Company customer with recurring demand

Mironsoft

Magento development, module consulting, and system architecture

A Magento project that needs a second opinion or experienced execution?

We build custom Magento modules, advise on architecture decisions, and take on complex implementations, from service contract planning to production-ready deployment.

Architecture Consulting

Have module and system architecture thought through properly before you build.

Custom Module Development

Build custom Magento modules cleanly, following best practices.

Code Review & Audit

Have existing modules reviewed for performance, security, and maintainability.

10. Summary

Requisition Lists

Data model

requisition_list and requisition_list_item store name, customer, SKU, quantity, and serialized product options.

Distinction

Unlike the wishlist, the Requisition List is built for fast reordering rather than saving and sharing.

API

GraphQL mutations such as addRequisitionListToCart validate every item individually and report errors granularly.

Limits

No team sharing out of the box, no automatic cleanup of stale items without a custom extension.

11. FAQ: Requisition Lists

1What does the data model of a Requisition List consist of?
Of the tables requisition_list with name, customer, and description, and requisition_list_item with SKU, quantity, and serialized product options per item.
2Can multiple employees of the same company see the same Requisition List?
Not in the default feature set. Requisition Lists are bound to the individual customer, not the company, so team sharing has to be added separately.
3What functionally distinguishes a Requisition List from a wishlist?
The wishlist is built for saving and sharing, the Requisition List for fast, repeated ordering with fixed quantities stored per item.
4How can an entire list be added to the cart?
Through the addRequisitionListToCart GraphQL mutation, which validates and transfers either the full list or a selected subset of items.
5What happens if an item on the list is no longer orderable?
Validation runs per item separately, so a faulty item is reported back as an individual error instead of blocking the entire action.
6How can custom quantity rules, such as pack sizes, be enforced?
Through a plugin on RequisitionListItemRepositoryInterface::save that checks the quantity against the product's configured pack size before saving and throws a LocalizedException on violation.
7Which use cases are Requisition Lists particularly well suited for?
For recurring orders with high predictability, such as regular spare part orders or standardized reorders of consumables.
8Are stale items removed automatically?
No, Requisition Lists do not expire automatically. A custom cleanup routine for items referencing disabled SKUs is recommended.
9How do very large lists affect performance?
Validation on adding to cart checks every item individually, so splitting into smaller batches is recommended once lists reach several hundred items.
10Is the product reference made through the internal ID or the SKU?
Through the SKU. That matters when SKUs change in the catalog, since stored items otherwise stop resolving correctly.