Skip to content

Commit

Permalink
Bugfix: Add support for configurable child products
Browse files Browse the repository at this point in the history
  • Loading branch information
michielgerritsen committed Dec 17, 2024
1 parent 5dd2315 commit af1fcbc
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 19 deletions.
22 changes: 8 additions & 14 deletions Service/Magento/CreateOrderFromSubscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ class CreateOrderFromSubscription
* @var ProductInterface
*/
private $product;
/**
* @var SubscriptionAddProductToCart
*/
private $subscriptionAddToCart;

public function __construct(
Config $config,
Expand All @@ -101,7 +105,8 @@ public function __construct(
ProductRepositoryInterface $productRepository,
AddressInterfaceFactory $addressFactory,
MollieLogger $mollieLogger,
OrderAddressRepositoryInterface $orderAddressRepository
OrderAddressRepositoryInterface $orderAddressRepository,
SubscriptionAddProductToCart $addProductToCart
) {
$this->mollieCustomerRepository = $mollieCustomerRepository;
$this->customerRepository = $customerRepository;
Expand All @@ -114,6 +119,7 @@ public function __construct(
$this->config = $config;
$this->mollieLogger = $mollieLogger;
$this->orderAddressRepository = $orderAddressRepository;
$this->subscriptionAddToCart = $addProductToCart;
}

public function execute(MollieApiClient $api, Payment $molliePayment, Subscription $subscription): OrderInterface
Expand All @@ -131,7 +137,7 @@ public function execute(MollieApiClient $api, Payment $molliePayment, Subscripti
$this->customer = $this->customerRepository->getById($mollieCustomer->getCustomerId());

$cart = $this->getCart();
$this->addProduct($cart);
$this->product = $this->subscriptionAddToCart->execute($cart, $this->subscription->metadata);

$cart->setBillingAddress($this->formatAddress($this->getAddress('billing')));

Expand Down Expand Up @@ -163,18 +169,6 @@ private function getCart(): CartInterface
return $cart;
}

private function addProduct(CartInterface $cart)
{
$sku = $this->subscription->metadata->sku;
$quantity = isset($this->subscription->metadata) && isset($this->subscription->metadata->quantity) ?
(float)$this->subscription->metadata->quantity : 1;
$this->product = $this->productRepository->get($sku);

$cart->addProduct($this->product, $quantity);

$cart->setIsVirtual($this->product->getIsVirtual());
}

/**
* @param CustomerAddressInterface|OrderAddressInterface $address
* @return AddressInterface
Expand Down
56 changes: 56 additions & 0 deletions Service/Magento/SubscriptionAddProductToCart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

namespace Mollie\Subscriptions\Service\Magento;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\DataObject;
use Magento\Quote\Api\Data\CartInterface;

class SubscriptionAddProductToCart
{
/**
* @var ProductRepositoryInterface
*/
private $productRepository;

public function __construct(
ProductRepositoryInterface $productRepository
) {
$this->productRepository = $productRepository;
}

public function execute(CartInterface $cart, object $metadata): ProductInterface
{
$sku = $metadata->sku;
$parentSku = isset($metadata->parent_sku) ? $metadata->parent_sku : null;
$quantity = isset($metadata->quantity) ? (float)$metadata->quantity : 1;

$product = $this->productRepository->get($parentSku ?: $sku);
$cart->setIsVirtual($product->getIsVirtual());

if (!$parentSku) {
$cart->addProduct($product, $quantity);

return $product;
}

$childProduct = $this->productRepository->get($sku);
$productAttributeOptions = $product->getTypeInstance(true)->getConfigurableAttributesAsArray($product);

$options = [];
foreach($productAttributeOptions as $option) {
$options[$option['attribute_id']] = $childProduct->getData($option['attribute_code']);
}

$cart->addProduct($product, new DataObject([
'product' => $product->getId(),
'qty' => $quantity,
'super_attribute' => $options,
]));

return $product;
}
}
8 changes: 7 additions & 1 deletion Service/Mollie/SubscriptionOptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,18 @@ private function addDescription(): void
private function addMetadata(): void
{
$product = $this->orderItem->getProduct();
$this->options['metadata'] = [
$metadata = [
'sku' => $product->getSku(),
'quantity' => $this->orderItem->getQtyOrdered(),
'billingAddressId' => $this->order->getBillingAddressId(),
];

if ($parent = $this->orderItem->getParentItem()) {
$metadata['parent_sku'] = $parent->getProduct()->getSku();
}

$this->options['metadata'] = $metadata;

if (!$this->orderItem->getIsVirtual()) {
$this->options['metadata']['shippingAddressId'] = $this->order->getshippingAddressId();
}
Expand Down
61 changes: 57 additions & 4 deletions Test/Integration/Controller/Api/WebhookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Mollie\Subscriptions\Test\Integration\Controller\Api;

use Magento\Catalog\Model\ProductRepository;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Encryption\Encryptor;
Expand Down Expand Up @@ -89,6 +90,54 @@ public function testPlacesOrderFromTransaction(): void
$this->assertSame($ordersCount + 1, count($orders));
}

/**
* @magentoDataFixture Magento/Customer/_files/customer_with_addresses.php
* @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
* @magentoConfigFixture default_store mollie_subscriptions/general/shipping_method flatrate_flatrate
*/
public function testPlacesOrderFromTransactionWithConfigurableProduct(): void
{
$transactionId = 'tr_testtransaction';

$this->createMollieCustomer();

// We need a configurable product, so change the subscription.
$api = $this->getApi($transactionId, function (Subscription $subscription) {
/** @var ProductRepository $repository */
$repository = $this->_objectManager->get(ProductRepository::class);
$product = $repository->get('configurable');
$childProducts = $product->getTypeInstance()->getUsedProducts($product);

$subscription->metadata->sku = $childProducts[0]->getSku();
$subscription->metadata->parent_sku = 'configurable';
});

$mollieSubscriptionApi = $this->createMock(MollieSubscriptionApi::class);
$mollieSubscriptionApi->method('loadByStore')->willReturn($api);
$this->_objectManager->addSharedInstance($mollieSubscriptionApi, MollieSubscriptionApi::class);

// Check how many orders there are before the webhook is called
$ordersCount = count($this->getOrderIdsByTransactionId($transactionId));

$mollieMock = $this->createMock(Mollie::class);
$mollieMock->method('processTransactionForOrder');
$this->_objectManager->addSharedInstance($mollieMock, Mollie::class);

$this->dispatch('mollie-subscriptions/api/webhook?id=' . $transactionId);
$this->assertEquals(200, $this->getResponse()->getStatusCode());

$orders = $this->getOrderIdsByTransactionId($transactionId);
$this->assertSame($ordersCount + 1, count($orders));

/** @var OrderInterface $lastOrder */
$lastOrder = end($orders);

$items = $lastOrder->getItems();
$lastItem = end($items);

$this->assertNotNull($lastItem->getParentItem());
}

/**
* @magentoDataFixture Magento/Sales/_files/order.php
* @magentoDataFixture Magento/Customer/_files/customer_with_addresses.php
Expand Down Expand Up @@ -190,7 +239,7 @@ private function getOrderIdsByTransactionId(string $transactionId): array
return $list->getItems();
}

private function getSubscription(): Subscription
private function getSubscription(?callable $customize = null): Subscription
{
/** @var Subscription $subscription */
$subscription = $this->_objectManager->get(Subscription::class);
Expand All @@ -199,6 +248,11 @@ private function getSubscription(): Subscription
$subscription->metadata = new \stdClass();
$subscription->metadata->sku = 'simple';
$subscription->nextPaymentDate = '2019-11-19';

if ($customize) {
$customize($subscription);
}

return $subscription;
}

Expand All @@ -218,10 +272,9 @@ private function getPayment(string $transactionId): Payment
return $payment;
}

private function getApi(string $transactionId): MollieApiClient
private function getApi(string $transactionId, ?callable $customize = null): MollieApiClient
{
$subscription = $this->getSubscription();
$this->subscription = $subscription;
$subscription = $this->getSubscription($customize);

$this->createSubscriptionDatabaseRecord();

Expand Down
31 changes: 31 additions & 0 deletions Test/Integration/Service/Mollie/SubscriptionOptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,37 @@ public function testAddsSku()
$this->assertEquals('example-sku', $subscription->toArray()['metadata']['sku']);
}

/**
* @magentoDataFixture Magento/Sales/_files/order_configurable_product.php
*/
public function testAddsParentSku()
{
$order = $this->loadOrder('100000001');
$items = $order->getItems();

/** @var OrderItemInterface $orderItem */
$orderItem = end($items);

$this->setOptionIdOnOrderItem($orderItem, 'weekly-finite');
$this->setTheSubscriptionOnTheProduct($orderItem->getProduct());

$orderItem->getProduct()->setData('sku', 'example-sku');
$orderItem->getParentItem()->getProduct()->setData('sku', 'example-parent-sku');

/** @var SubscriptionOptions $instance */
$instance = $this->objectManager->create(SubscriptionOptions::class);
$result = $instance->forOrder($order);

$this->assertCount(1, $result);
$subscription = $result[0];
$this->assertInstanceOf(SubscriptionOption::class, $subscription);
$this->assertArrayHasKey('metadata', $subscription->toArray());
$this->assertArrayHasKey('sku', $subscription->toArray()['metadata']);
$this->assertArrayHasKey('parent_sku', $subscription->toArray()['metadata']);
$this->assertEquals('example-sku', $subscription->toArray()['metadata']['sku']);
$this->assertEquals('example-parent-sku', $subscription->toArray()['metadata']['parent_sku']);
}

/**
* @magentoDataFixture Magento/Sales/_files/order.php
*/
Expand Down

0 comments on commit af1fcbc

Please sign in to comment.