diff --git a/app/code/Magento/Sales/Model/Order/CustomerAssignment.php b/app/code/Magento/Sales/Model/Order/CustomerAssignment.php
new file mode 100644
index 0000000000000..b6ae86461c398
--- /dev/null
+++ b/app/code/Magento/Sales/Model/Order/CustomerAssignment.php
@@ -0,0 +1,58 @@
+eventManager = $eventManager;
+ $this->orderRepository = $orderRepository;
+ }
+
+ /**
+ * @param OrderInterface $order
+ * @param CustomerInterface $customer
+ */
+ public function execute(OrderInterface $order, CustomerInterface $customer)/*: void*/
+ {
+ $order->setCustomerId($customer->getId());
+ $order->setCustomerIsGuest(false);
+ $this->orderRepository->save($order);
+
+ $this->eventManager->dispatch(
+ 'sales_order_customer_assign_after', [
+ 'order' => $order,
+ 'customer' => $customer
+ ]
+ );
+ }
+}
diff --git a/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php
index f41ea6888264f..aba7d551d5330 100644
--- a/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php
+++ b/app/code/Magento/Sales/Observer/AssignOrderToCustomerObserver.php
@@ -12,6 +12,7 @@
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
+use Magento\Sales\Model\Order\CustomerAssignment;
/**
* Assign order to customer created after issuing guest order.
@@ -24,11 +25,22 @@ class AssignOrderToCustomerObserver implements ObserverInterface
private $orderRepository;
/**
+ * @var CustomerAssignment
+ */
+ private $customerAssignmentService;
+
+ /**
+ * AssignOrderToCustomerObserver constructor.
+ *
* @param OrderRepositoryInterface $orderRepository
+ * @param CustomerAssignment $customerAssignmentService
*/
- public function __construct(OrderRepositoryInterface $orderRepository)
- {
+ public function __construct(
+ OrderRepositoryInterface $orderRepository,
+ CustomerAssignment $customerAssignmentService
+ ) {
$this->orderRepository = $orderRepository;
+ $this->customerAssignmentService = $customerAssignmentService;
}
/**
@@ -44,11 +56,8 @@ public function execute(Observer $observer)
if (array_key_exists('__sales_assign_order_id', $delegateData)) {
$orderId = $delegateData['__sales_assign_order_id'];
$order = $this->orderRepository->get($orderId);
- if (!$order->getCustomerId()) {
- //if customer ID wasn't already assigned then assigning.
- $order->setCustomerId($customer->getId());
- $order->setCustomerIsGuest(0);
- $this->orderRepository->save($order);
+ if (!$order->getCustomerId() && $customer->getId()) {
+ $this->customerAssignmentService->execute($order, $customer);
}
}
}
diff --git a/app/code/Magento/SalesRule/Observer/AssignCouponDataAfterOrderCustomerAssignObserver.php b/app/code/Magento/SalesRule/Observer/AssignCouponDataAfterOrderCustomerAssignObserver.php
new file mode 100644
index 0000000000000..d9699d334ff6a
--- /dev/null
+++ b/app/code/Magento/SalesRule/Observer/AssignCouponDataAfterOrderCustomerAssignObserver.php
@@ -0,0 +1,52 @@
+updateCouponUsages = $updateCouponUsages;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function execute(Observer $observer)
+ {
+ $event = $observer->getEvent();
+ /** @var OrderInterface $order */
+ $order = $event->getData(self::EVENT_KEY_ORDER);
+
+ if ($order->getCustomerId()) {
+ $this->updateCouponUsages->execute($order, true);
+ }
+ }
+}
diff --git a/app/code/Magento/SalesRule/etc/events.xml b/app/code/Magento/SalesRule/etc/events.xml
index 8261860bbb7ce..eec0da74f619e 100644
--- a/app/code/Magento/SalesRule/etc/events.xml
+++ b/app/code/Magento/SalesRule/etc/events.xml
@@ -24,4 +24,7 @@
+
+
+
diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Observer/AssignCouponDataAfterOrderCustomerAssignTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Observer/AssignCouponDataAfterOrderCustomerAssignTest.php
new file mode 100644
index 0000000000000..d04423daabdf9
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Observer/AssignCouponDataAfterOrderCustomerAssignTest.php
@@ -0,0 +1,269 @@
+objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+ $this->eventManager = $this->createMock(\Magento\Framework\Event\ManagerInterface::class);
+ $this->orderRepository = $this->objectManager->get(Magento\Sales\Model\OrderRepository::class);
+ $this->delegateCustomerService = $this->objectManager->get(Order\OrderCustomerDelegate::class);
+ $this->customerRepository = $this->objectManager->get(\Magento\Customer\Api\CustomerRepositoryInterface::class);
+ $this->ruleCustomerFactory = $this->objectManager->get(Magento\SalesRule\Model\Rule\CustomerFactory::class);;
+ $this->assignCouponToCustomerObserver = $this->objectManager->get(
+ Magento\SalesRule\Observer\AssignCouponDataAfterOrderCustomerAssignObserver::class
+ );
+ }
+
+ /**
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Sales/_files/order.php
+ */
+ public function testCouponDataHasBeenAssignedTest()
+ {
+ $rule = $this->prepareSalesRule();
+ $coupon = $this->attachSalesruleCoupon($rule);
+
+ $order = $this->makeOrderWithCouponAsGuest($coupon);
+ $this->delegateOrderToBeAssigned($order);
+
+ $customer = $this->registerNewCustomer();
+ $ruleCustomer = $this->getSalesruleCustomerUsage($customer, $rule);
+
+ // Assert, that rule customer model has been created for specific customer
+ $this->assertEquals(
+ $ruleCustomer->getCustomerId(),
+ $customer->getId()
+ );
+
+ // Assert, that customer has increased coupon usage of specific rule
+ $this->assertEquals(
+ 1,
+ $ruleCustomer->getTimesUsed()
+ );
+ }
+
+ /**
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/Sales/_files/order.php
+ */
+ public function testOrderCancelingDecreasesCouponUsages()
+ {
+ $rule = $this->prepareSalesRule();
+ $coupon = $this->attachSalesruleCoupon($rule);
+
+ $order = $this->makeOrderWithCouponAsGuest($coupon);
+ $this->delegateOrderToBeAssigned($order);
+
+ $customer = $this->registerNewCustomer();
+
+ $order->setCustomerId($customer->getId());
+ $this->processOrder($order);
+
+ // Should not throw exception as bux is fixed now
+ $this->cancelOrder($order);
+ $ruleCustomer = $this->getSalesruleCustomerUsage($customer, $rule);
+
+ // Assert, that rule customer model has been created for specific customer
+ $this->assertEquals(
+ $ruleCustomer->getCustomerId(),
+ $customer->getId()
+ );
+
+ // Assert, that customer has increased coupon usage of specific rule
+ $this->assertEquals(
+ 0,
+ $ruleCustomer->getTimesUsed()
+ );
+
+ }
+
+ /**
+ * @param Order $order
+ * @return \Magento\Sales\Api\Data\OrderInterface
+ */
+ private function processOrder(Order $order)
+ {
+ $order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING);
+ $order->setStatus(\Magento\Sales\Model\Order::STATE_PROCESSING);
+ return $this->orderRepository->save($order);
+ }
+
+ /**
+ * @param Order $order
+ */
+ private function cancelOrder(Order $order)
+ {
+ $order->cancel();
+ }
+
+ /**
+ * @param Customer $customer
+ * @param Rule $rule
+ * @return Rule\Customer
+ */
+ private function getSalesruleCustomerUsage(Customer $customer, Rule $rule) : Magento\SalesRule\Model\Rule\Customer
+ {
+ $ruleCustomer = $this->ruleCustomerFactory->create();
+ return $ruleCustomer->loadByCustomerRule($customer->getId(), $rule->getRuleId());
+ }
+
+ /**
+ * @return Rule
+ */
+ private function prepareSalesRule() : Rule
+ {
+ /** @var Rule $salesRule */
+ $salesRule = $this->objectManager->create(Rule::class);
+ $salesRule->setData(
+ [
+ 'name' => '15$ fixed discount on whole cart',
+ 'is_active' => 1,
+ 'customer_group_ids' => [GroupManagement::NOT_LOGGED_IN_ID],
+ 'coupon_type' => Rule::COUPON_TYPE_SPECIFIC,
+ 'conditions' => [
+ [
+ 'type' => \Magento\SalesRule\Model\Rule\Condition\Address::class,
+ 'attribute' => 'base_subtotal',
+ 'operator' => '>',
+ 'value' => 45,
+ ],
+ ],
+ 'simple_action' => Rule::CART_FIXED_ACTION,
+ 'discount_amount' => 15,
+ 'discount_step' => 0,
+ 'stop_rules_processing' => 1,
+ 'website_ids' => [
+ $this->objectManager->get(StoreManagerInterface::class)->getWebsite()->getId(),
+ ],
+ ]
+ );
+ $this->objectManager->get(
+ \Magento\SalesRule\Model\ResourceModel\Rule::class
+ )->save($salesRule);
+
+ return $salesRule;
+ }
+
+ /**
+ * @param Rule $salesRule
+ * @return Coupon
+ */
+ private function attachSalesruleCoupon(Rule $salesRule) : Coupon
+ {
+ $coupon = $this->objectManager->create(Coupon::class);
+ $coupon->setRuleId($salesRule->getId())
+ ->setCode('CART_FIXED_DISCOUNT_15')
+ ->setType(0);
+
+ $this->objectManager->get(CouponRepositoryInterface::class)->save($coupon);
+
+ return $coupon;
+ }
+
+ /**
+ * @param Coupon $coupon
+ * @return Order
+ */
+ private function makeOrderWithCouponAsGuest(Coupon $coupon) : Order
+ {
+ $order = $this->objectManager->create(\Magento\Sales\Model\Order::class);
+ $order->loadByIncrementId('100000001')
+ ->setCustomerIsGuest(true)
+ ->setCouponCode($coupon->getCode())
+ ->setCreatedAt('2014-10-25 10:10:10')
+ ->setAppliedRuleIds($coupon->getRuleId())
+ ->save();
+
+ return $order;
+ }
+
+ /**
+ * @param Order $order
+ */
+ private function delegateOrderToBeAssigned(Order $order)
+ {
+ $this->delegateCustomerService->delegateNew($order->getId());
+ }
+
+ /**
+ * @return Customer
+ * @throws \Magento\Framework\Exception\InputException
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\State\InputMismatchException
+ */
+ private function registerNewCustomer() : Customer
+ {
+ $customer = $this->objectManager->create(
+ \Magento\Customer\Api\Data\CustomerInterface::class
+ );
+
+ /** @var Magento\Customer\Api\Data\CustomerInterface $customer */
+ $customer->setWebsiteId(1)
+ ->setEmail('customer@example.com')
+ ->setGroupId(1)
+ ->setStoreId(1)
+ ->setPrefix('Mr.')
+ ->setFirstname('John')
+ ->setMiddlename('A')
+ ->setLastname('Smith')
+ ->setSuffix('Esq.')
+ ->setDefaultBilling(1)
+ ->setDefaultShipping(1)
+ ->setTaxvat('12')
+ ->setGender(0);
+
+ $customer = $this->customerRepository->save($customer, 'password');
+
+ return $customer;
+ }
+}
+