diff --git a/vendor/magento/module-sales-rule/Model/Coupon/Quote/UpdateCouponUsages.php b/vendor/magento/module-sales-rule/Model/Coupon/Quote/UpdateCouponUsages.php
index 02da921e032e..236006bc521b 100644
--- a/vendor/magento/module-sales-rule/Model/Coupon/Quote/UpdateCouponUsages.php
+++ b/vendor/magento/module-sales-rule/Model/Coupon/Quote/UpdateCouponUsages.php
@@ -8,6 +8,7 @@
 namespace Magento\SalesRule\Model\Coupon\Quote;
 
 use Magento\Quote\Api\Data\CartInterface;
+use Magento\SalesRule\Model\Coupon\Usage\Processor as CouponUsageProcessor;
 use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo;
 use Magento\SalesRule\Model\Coupon\Usage\UpdateInfoFactory;
 use Magento\SalesRule\Model\Service\CouponUsagePublisher;
@@ -27,16 +28,24 @@ class UpdateCouponUsages
      */
     private $couponUsagePublisher;
 
+    /**
+     * @var CouponUsageProcessor
+     */
+    private $processor;
+
     /**
      * @param CouponUsagePublisher $couponUsagePublisher
      * @param UpdateInfoFactory $updateInfoFactory
+     * @param CouponUsageProcessor $processor
      */
     public function __construct(
         CouponUsagePublisher $couponUsagePublisher,
-        UpdateInfoFactory $updateInfoFactory
+        UpdateInfoFactory $updateInfoFactory,
+        CouponUsageProcessor $processor
     ) {
         $this->couponUsagePublisher = $couponUsagePublisher;
         $this->updateInfoFactory = $updateInfoFactory;
+        $this->processor = $processor;
     }
 
     /**
@@ -54,11 +63,15 @@ public function execute(CartInterface $quote, bool $increment): void
 
         /** @var UpdateInfo $updateInfo */
         $updateInfo = $this->updateInfoFactory->create();
-        $updateInfo->setAppliedRuleIds(explode(',', $quote->getAppliedRuleIds()));
+        $appliedRuleIds = explode(',', $quote->getAppliedRuleIds());
+        $appliedRuleIds = array_filter(array_map('intval', array_unique($appliedRuleIds)));
+        $updateInfo->setAppliedRuleIds($appliedRuleIds);
         $updateInfo->setCouponCode((string)$quote->getCouponCode());
         $updateInfo->setCustomerId((int)$quote->getCustomerId());
         $updateInfo->setIsIncrement($increment);
 
         $this->couponUsagePublisher->publish($updateInfo);
+        $this->processor->updateCustomerRulesUsages($updateInfo);
+        $this->processor->updateCouponUsages($updateInfo);
     }
 }
diff --git a/vendor/magento/module-sales-rule/Model/Coupon/UpdateCouponUsages.php b/vendor/magento/module-sales-rule/Model/Coupon/UpdateCouponUsages.php
index d664cf30f570..7255b455c90a 100644
--- a/vendor/magento/module-sales-rule/Model/Coupon/UpdateCouponUsages.php
+++ b/vendor/magento/module-sales-rule/Model/Coupon/UpdateCouponUsages.php
@@ -8,9 +8,11 @@
 namespace Magento\SalesRule\Model\Coupon;
 
 use Magento\Sales\Api\Data\OrderInterface;
+use Magento\Sales\Model\Order;
 use Magento\SalesRule\Model\Coupon\Usage\Processor as CouponUsageProcessor;
 use Magento\SalesRule\Model\Coupon\Usage\UpdateInfo;
 use Magento\SalesRule\Model\Coupon\Usage\UpdateInfoFactory;
+use Magento\SalesRule\Model\Service\CouponUsagePublisher;
 
 /**
  * Updates the coupon usages
@@ -27,16 +29,25 @@ class UpdateCouponUsages
      */
     private $updateInfoFactory;
 
+    /**
+     * @var CouponUsagePublisher
+     */
+    private $couponUsagePublisher;
+
     /**
      * @param CouponUsageProcessor $couponUsageProcessor
      * @param UpdateInfoFactory $updateInfoFactory
+     * @param ?CouponUsagePublisher $couponUsagePublisher
      */
     public function __construct(
         CouponUsageProcessor $couponUsageProcessor,
-        UpdateInfoFactory $updateInfoFactory
+        UpdateInfoFactory $updateInfoFactory,
+        ?CouponUsagePublisher $couponUsagePublisher = null
     ) {
         $this->couponUsageProcessor = $couponUsageProcessor;
         $this->updateInfoFactory = $updateInfoFactory;
+        $this->couponUsagePublisher = $couponUsagePublisher
+            ?? \Magento\Framework\App\ObjectManager::getInstance()->get(CouponUsagePublisher::class);
     }
 
     /**
@@ -54,16 +65,20 @@ public function execute(OrderInterface $subject, bool $increment): OrderInterfac
 
         /** @var UpdateInfo $updateInfo */
         $updateInfo = $this->updateInfoFactory->create();
-        $updateInfo->setAppliedRuleIds(explode(',', $subject->getAppliedRuleIds()));
+        $appliedRuleIds = explode(',', $subject->getAppliedRuleIds());
+        $appliedRuleIds = array_filter(array_map('intval', array_unique($appliedRuleIds)));
+        $updateInfo->setAppliedRuleIds($appliedRuleIds);
         $updateInfo->setCouponCode((string)$subject->getCouponCode());
         $updateInfo->setCustomerId((int)$subject->getCustomerId());
         $updateInfo->setIsIncrement($increment);
 
-        if ($subject->getOrigData('coupon_code') !== null) {
+        if ($subject->getOrigData('coupon_code') !== null && $subject->getStatus() !== Order::STATE_CANCELED) {
             $updateInfo->setCouponAlreadyApplied(true);
         }
 
-        $this->couponUsageProcessor->process($updateInfo);
+        $this->couponUsagePublisher->publish($updateInfo);
+        $this->couponUsageProcessor->updateCustomerRulesUsages($updateInfo);
+        $this->couponUsageProcessor->updateCouponUsages($updateInfo);
 
         return $subject;
     }
diff --git a/vendor/magento/module-sales-rule/Model/Coupon/Usage/Processor.php b/vendor/magento/module-sales-rule/Model/Coupon/Usage/Processor.php
index 3845ace8639c..686d15aa8e0a 100644
--- a/vendor/magento/module-sales-rule/Model/Coupon/Usage/Processor.php
+++ b/vendor/magento/module-sales-rule/Model/Coupon/Usage/Processor.php
@@ -8,6 +8,7 @@
 namespace Magento\SalesRule\Model\Coupon\Usage;
 
 use Magento\SalesRule\Model\Coupon;
+use Magento\SalesRule\Model\CouponFactory;
 use Magento\SalesRule\Model\ResourceModel\Coupon\Usage;
 use Magento\SalesRule\Model\Rule\CustomerFactory;
 use Magento\SalesRule\Model\RuleFactory;
@@ -28,9 +29,9 @@ class Processor
     private $ruleCustomerFactory;
 
     /**
-     * @var Coupon
+     * @var CouponFactory
      */
-    private $coupon;
+    private $couponFactory;
 
     /**
      * @var Usage
@@ -40,18 +41,18 @@ class Processor
     /**
      * @param RuleFactory $ruleFactory
      * @param CustomerFactory $ruleCustomerFactory
-     * @param Coupon $coupon
+     * @param CouponFactory $couponFactory
      * @param Usage $couponUsage
      */
     public function __construct(
         RuleFactory $ruleFactory,
         CustomerFactory $ruleCustomerFactory,
-        Coupon $coupon,
+        CouponFactory $couponFactory,
         Usage $couponUsage
     ) {
         $this->ruleFactory = $ruleFactory;
         $this->ruleCustomerFactory = $ruleCustomerFactory;
-        $this->coupon = $coupon;
+        $this->couponFactory = $couponFactory;
         $this->couponUsage = $couponUsage;
     }
 
@@ -66,21 +67,9 @@ public function process(UpdateInfo $updateInfo): void
             return;
         }
 
-        if (!empty($updateInfo->getCouponCode())) {
-            $this->updateCouponUsages($updateInfo);
-        }
-        $isIncrement = $updateInfo->isIncrement();
-        $customerId = $updateInfo->getCustomerId();
-        // use each rule (and apply to customer, if applicable)
-        foreach (array_unique($updateInfo->getAppliedRuleIds()) as $ruleId) {
-            if (!(int)$ruleId) {
-                continue;
-            }
-            $this->updateRuleUsages($isIncrement, (int)$ruleId);
-            if ($customerId) {
-                $this->updateCustomerRuleUsages($isIncrement, (int)$ruleId, $customerId);
-            }
-        }
+        $this->updateCouponUsages($updateInfo);
+        $this->updateRuleUsages($updateInfo);
+        $this->updateCustomerRulesUsages($updateInfo);
     }
 
     /**
@@ -88,45 +77,67 @@ public function process(UpdateInfo $updateInfo): void
      *
      * @param UpdateInfo $updateInfo
      */
-    private function updateCouponUsages(UpdateInfo $updateInfo): void
+    public function updateCouponUsages(UpdateInfo $updateInfo): void
     {
+        $coupon = $this->retrieveCoupon($updateInfo);
+        if (!$coupon) {
+            return;
+        }
+
         $isIncrement = $updateInfo->isIncrement();
-        $this->coupon->load($updateInfo->getCouponCode(), 'code');
-        if ($this->coupon->getId()) {
-            if (!$updateInfo->isCouponAlreadyApplied()
-                && ($updateInfo->isIncrement() || $this->coupon->getTimesUsed() > 0)) {
-                $this->coupon->setTimesUsed($this->coupon->getTimesUsed() + ($isIncrement ? 1 : -1));
-                $this->coupon->save();
-            }
-            if ($updateInfo->getCustomerId()) {
-                $this->couponUsage->updateCustomerCouponTimesUsed(
-                    $updateInfo->getCustomerId(),
-                    $this->coupon->getId(),
-                    $isIncrement
-                );
-            }
+        if (!$updateInfo->isCouponAlreadyApplied()
+            && ($updateInfo->isIncrement() || $coupon->getTimesUsed() > 0)) {
+            $coupon->setTimesUsed($coupon->getTimesUsed() + ($isIncrement ? 1 : -1));
+            $coupon->save();
         }
     }
 
     /**
      * Update the number of rule usages
      *
-     * @param bool $isIncrement
-     * @param int $ruleId
+     * @param UpdateInfo $updateInfo
      */
-    private function updateRuleUsages(bool $isIncrement, int $ruleId): void
+    public function updateRuleUsages(UpdateInfo $updateInfo): void
     {
-        $rule = $this->ruleFactory->create();
-        $rule->load($ruleId);
-        if ($rule->getId()) {
+        $isIncrement = $updateInfo->isIncrement();
+        foreach ($updateInfo->getAppliedRuleIds() as $ruleId) {
+            $rule = $this->ruleFactory->create();
+            $rule->load($ruleId);
+            if (!$rule->getId()) {
+                continue;
+            }
+
             $rule->loadCouponCode();
-            if ($isIncrement || $rule->getTimesUsed() > 0) {
+            if ((!$updateInfo->isCouponAlreadyApplied() && $isIncrement) || !$isIncrement) {
                 $rule->setTimesUsed($rule->getTimesUsed() + ($isIncrement ? 1 : -1));
                 $rule->save();
             }
         }
     }
 
+    /**
+     * Update the number of rules usages per customer
+     *
+     * @param UpdateInfo $updateInfo
+     */
+    public function updateCustomerRulesUsages(UpdateInfo $updateInfo): void
+    {
+        $customerId = $updateInfo->getCustomerId();
+        if (!$customerId) {
+            return;
+        }
+
+        $isIncrement = $updateInfo->isIncrement();
+        foreach ($updateInfo->getAppliedRuleIds() as $ruleId) {
+            $this->updateCustomerRuleUsages($isIncrement, $ruleId, $customerId);
+        }
+
+        $coupon = $this->retrieveCoupon($updateInfo);
+        if ($coupon) {
+            $this->couponUsage->updateCustomerCouponTimesUsed($customerId, $coupon->getId(), $isIncrement);
+        }
+    }
+
     /**
      * Update the number of rule usages per customer
      *
@@ -151,4 +162,22 @@ private function updateCustomerRuleUsages(bool $isIncrement, int $ruleId, int $c
             $ruleCustomer->save();
         }
     }
+
+    /**
+     * Retrieve coupon from update info
+     *
+     * @param UpdateInfo $updateInfo
+     * @return Coupon|null
+     */
+    private function retrieveCoupon(UpdateInfo $updateInfo): ?Coupon
+    {
+        if (!$updateInfo->getCouponCode()) {
+            return null;
+        }
+
+        $coupon = $this->couponFactory->create();
+        $coupon->loadByCode($updateInfo->getCouponCode());
+
+        return $coupon->getId() ? $coupon : null;
+    }
 }
diff --git a/vendor/magento/module-sales-rule/Model/CouponUsageConsumer.php b/vendor/magento/module-sales-rule/Model/CouponUsageConsumer.php
index 0520cb658e40..266e9ddf97cc 100644
--- a/vendor/magento/module-sales-rule/Model/CouponUsageConsumer.php
+++ b/vendor/magento/module-sales-rule/Model/CouponUsageConsumer.php
@@ -80,7 +80,7 @@ public function process(OperationInterface $operation): void
             $data = $this->serializer->unserialize($serializedData);
             $updateInfo = $this->updateInfoFactory->create();
             $updateInfo->setData($data);
-            $this->processor->process($updateInfo);
+            $this->processor->updateRuleUsages($updateInfo);
         } catch (NotFoundException $e) {
             $this->logger->critical($e->getMessage());
             $status = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
diff --git a/vendor/magento/module-sales-rule/etc/db_schema.xml b/vendor/magento/module-sales-rule/etc/db_schema.xml
index 3912ba3642ba..8c33870de493 100644
--- a/vendor/magento/module-sales-rule/etc/db_schema.xml
+++ b/vendor/magento/module-sales-rule/etc/db_schema.xml
@@ -36,7 +36,7 @@
                 default="0" comment="Discount Step"/>
         <column xsi:type="smallint" name="apply_to_shipping" unsigned="true" nullable="false"
                 identity="false" default="0" comment="Apply To Shipping"/>
-        <column xsi:type="int" name="times_used" unsigned="true" nullable="false" identity="false"
+        <column xsi:type="int" name="times_used" unsigned="false" nullable="false" identity="false"
                 default="0" comment="Times Used"/>
         <column xsi:type="smallint" name="is_rss" unsigned="false" nullable="false" identity="false"
                 default="0" comment="Is Rss"/>
