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:
- Same customer
- Same order total
- Same products
- Same payment method
- Same Shipping Address
In this post, you’ll learn how we built this extension, implemented admin-level configuration and added error handling.
ON THIS PAGE
Module Features
- Prevents duplicate orders based on strict matching conditions
- Configurable per store via Magento Admin
- Proper error message shown on the frontend
- 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.


