Duplicate orders can happen due to accidental double-clicks, network retries, or impatient customers. This can result in operational overhead and customer dissatisfaction. To combat this, we created a custom Magento 2 extension named Klizer_CancelOrder that prevents duplicate orders placed by the same customer within 1 hour, based on the following criteria:

  1.  Same customer
  2. Same order total
  3. Same products
  4.  Same payment method
  5.  Same Shipping Address

In this post, you’ll learn how we built this extension, implemented admin-level configuration and added error handling.

 Module Features

  1. Prevents duplicate orders based on strict matching conditions
  2. Configurable per store via Magento Admin
  3. Proper error message shown on the frontend
  4. Built with Magento 2 best practices (observers, DI, helper, system.xml)

Admin Configuration (system.xml)

We added a toggle under:

Stores → Configuration → Sales → Klizer Cancel Order

Here’s the XML to create it:

<section id="klizer_cancelorder">
  <label>Klizer Cancel Order</label>
  <tab>sales</tab>
  <resource>Klizer_CancelOrder::config</resource>
  <group id="general">
    <label>General Settings</label>
    <field id="enable" type="select" source_model="Magento\Config\Model\Config\Source\Yesno">
      <label>Enable Duplicate Order Check</label>
    </field>
  </group>
</section>

Business Logic via Observer

We used the sales_model_service_quote_submit_before event to intercept the order before placement:

public function execute(Observer $observer)
{

   /** @var \Magento\Quote\Model\Quote $quote */
   $quote = $observer->getEvent()->getQuote();
   $storeId = $quote->getStoreId();

   if (!$this->helper->isEnabled($storeId)) {
       return; // Feature is disabled
   }

   $customerId = $quote->getCustomerId();
   if (!$customerId) {
       return; // Only check for logged-in users
   }

   // Order Total amount
   $grandTotal = number_format($quote->getGrandTotal(), 2, '.', '');

   // Order Payment Method
   $paymentMethod = $quote->getPayment()->getMethod();

   // Get quote product SKUs
   $quoteSkus = [];
   foreach ($quote->getAllVisibleItems() as $item) {
       $quoteSkus[] = $item->getSku();
   }
   sort($quoteSkus);
   $quoteSkuKey = implode('-', $quoteSkus);

   // Get quote shipping address
   $quoteAddress = $quote->getShippingAddress();
   $quoteStreet = implode(' ', (array)$quoteAddress->getStreet());
   $quotePostcode = $quoteAddress->getPostcode();
   $quoteCity = $quoteAddress->getCity();
   $quoteCountry = $quoteAddress->getCountryId();

   // Fetch recent orders within 1 hour
   $oneHourAgo = (new \DateTime('-1 hour'))->format('Y-m-d H:i:s');
   $orders = $this->orderCollectionFactory->create()
       ->addFieldToFilter('customer_id', $customerId)
       ->addFieldToFilter('grand_total', $grandTotal)
       ->addFieldToFilter('created_at', ['gteq' => $oneHourAgo])
       ->addFieldToFilter('store_id', $storeId);


   foreach ($orders as $order) {
       if ($order->getPayment()->getMethod() !== $paymentMethod) {
           continue;
       }

       // Get SKUs from the order
       $orderSkus = [];
       foreach ($order->getAllVisibleItems() as $item) {
           $orderSkus[] = $item->getSku();
       }
       sort($orderSkus);
       $orderSkuKey = implode('-', $orderSkus);

       // Get order shipping address
       $orderAddress = $order->getShippingAddress();
       $orderStreet = implode(' ', (array)$orderAddress->getStreet());
       $orderPostcode = $orderAddress->getPostcode();
       $orderCity = $orderAddress->getCity();
       $orderCountry = $orderAddress->getCountryId();

       if (
           $quoteSkuKey === $orderSkuKey &&
           $quoteStreet === $orderStreet &&
           $quotePostcode === $orderPostcode &&
           $quoteCity === $orderCity &&
           $quoteCountry === $orderCountry
       ) {
           throw new LocalizedException(
               __('A similar order (Order ID: #%1) has already been placed within the past hour. Please wait before trying again.', $order->getIncrementId())
           );
       }
   }
}

Configuration Check Helper

To respect store-level settings, we created a helper:

class Data extends AbstractHelper
{
    const XML_PATH_ENABLE = 'klizer_cancelorder/general/enable';

    public function isEnabled($storeId = null)
    {
        return $this->scopeConfig->isSetFlag(self::XML_PATH_ENABLE, ScopeInterface::SCOPE_STORE, $storeId);
    }
}

Frontend Error Handling

If a duplicate is detected, we throw a LocalizedException:

__('A similar order(Order ID:#%1) has already been placed within the past hour. Please try again later.',$order->getIncrementId())

Magento automatically displays this message during checkout with order Id, ensuring a smooth UX.

Optional Debug Logging

Want to confirm that everything works? Add this to the observer:

$this->logger->info('Klizer_CancelOrder: Checking duplicate orders for customer ID ' . $customerId);
$this->logger->info('Store Config Enabled: ' . ($this->helper->isEnabled($storeId) ? 'Yes' : 'No'));

View logs in:

Deployment & Testing

After deploying:

php bin/magento setup:upgrade
php bin/magento cache:flush

Test by placing an order, then trying the exact same order again within 1 hour.

Conclusion

With Klizer_CancelOrder, you get full control over duplicate order protection in Magento 2 — without relying on payment gateways or third-party plugins. The module is lightweight, configurable per store, and easy to customize.

Need help integrating this in your store? Feel free to reach out to an ecommerce solution partner like Klizer. Our team of Adobe Solution experts helps you enhance it based on your business rules.

Picture of Rashid M

Rashid M

Mohammed Rashid is an Adobe Certified Magento 2 Developer at Klizer (DCKAP) with a demonstrated ability to deliver exceptional ecommerce solutions. With over 4 years of experience in the field, Mohammed brings a wealth of expertise to his role. His commitment to ongoing learning keeps him informed about industry developments and at the forefront of Magento 2 technology and best practices.

Get Expert Advice

At Klizer, we bring over 20+ years of specialized expertise in ecommerce website development and design.

© Copyright 2025 Klizer. All Rights Reserved

Scroll to Top