diff --git a/Api/AdyenStateDataInterface.php b/Api/AdyenStateDataInterface.php
index 8dbf658e3..db86c55df 100644
--- a/Api/AdyenStateDataInterface.php
+++ b/Api/AdyenStateDataInterface.php
@@ -18,13 +18,15 @@
interface AdyenStateDataInterface
{
/**
- * Persist the Adyen state data for the quote so it can be used in the payment request
+ * Persist the Adyen state data for the quote and returns the stateDataId.
+ * So it can be used in the payment request.
+ *
*
* @param string $stateData
* @param int $cartId
- * @return void
+ * @return int
*/
- public function save(string $stateData, int $cartId): void;
+ public function save(string $stateData, int $cartId): int;
/**
* Removes the Adyen state data with the given entity id
diff --git a/Api/GuestAdyenStateDataInterface.php b/Api/GuestAdyenStateDataInterface.php
index 199eebeb0..c3747e320 100644
--- a/Api/GuestAdyenStateDataInterface.php
+++ b/Api/GuestAdyenStateDataInterface.php
@@ -18,13 +18,14 @@
interface GuestAdyenStateDataInterface
{
/**
- * Persist the Adyen state data for the quote so it can be used in the payment request
+ * Persist the Adyen state data for the quote and returns the stateDataId.
+ * So it can be used in the payment request.
*
* @param string $stateData
* @param string $cartId
- * @return void
+ * @return int
*/
- public function save(string $stateData, string $cartId): void;
+ public function save(string $stateData, string $cartId): int;
/**
* Removes the Adyen state data with the given entity id
diff --git a/Gateway/Request/CaptureDataBuilder.php b/Gateway/Request/CaptureDataBuilder.php
index aa48a9b1c..dbebc144d 100644
--- a/Gateway/Request/CaptureDataBuilder.php
+++ b/Gateway/Request/CaptureDataBuilder.php
@@ -114,7 +114,7 @@ public function build(array $buildSubject): array
//Check additionaldata
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($brandCode)) {
- $openInvoiceFields = $this->openInvoiceHelper->getOpenInvoiceDataForOrder($order);
+ $openInvoiceFields = $this->openInvoiceHelper->getOpenInvoiceDataForInvoice($latestInvoice);
$requestBody = array_merge($requestBody, $openInvoiceFields);
}
$request['body'] = $requestBody;
@@ -179,7 +179,13 @@ public function buildPartialOrMultipleCaptureData($payment, $currency, $adyenOrd
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod(
$adyenOrderPayment[OrderPaymentInterface::PAYMENT_METHOD]
)) {
- $openInvoiceFields = $this->openInvoiceHelper->getOpenInvoiceDataForLastInvoice($payment);
+ $order = $payment->getOrder();
+ $invoices = $order->getInvoiceCollection();
+ // The latest invoice will contain only the selected items(and quantities) for the (partial) capture
+ /** @var Invoice $invoice */
+ $invoice = $invoices->getLastItem();
+
+ $openInvoiceFields = $this->openInvoiceHelper->getOpenInvoiceDataForInvoice($invoice);
$authToCapture = array_merge($authToCapture, $openInvoiceFields);
}
diff --git a/Gateway/Request/RefundDataBuilder.php b/Gateway/Request/RefundDataBuilder.php
index 76716c4ca..6777a2e65 100644
--- a/Gateway/Request/RefundDataBuilder.php
+++ b/Gateway/Request/RefundDataBuilder.php
@@ -165,7 +165,7 @@ public function build(array $buildSubject): array
);
if ($this->adyenHelper->isPaymentMethodOpenInvoiceMethod($brandCode)) {
- $openInvoiceFieldsCreditMemo = $this->openInvoiceHelper->getOpenInvoiceDataForCreditMemo($payment);
+ $openInvoiceFieldsCreditMemo = $this->openInvoiceHelper->getOpenInvoiceDataForCreditMemo($creditMemo);
//There is only one payment, so we add the fields to the first(and only) result
$requestBody[0] = array_merge($requestBody[0], $openInvoiceFieldsCreditMemo);
}
diff --git a/Helper/ChargedCurrency.php b/Helper/ChargedCurrency.php
index 04e83f5ef..b15925611 100644
--- a/Helper/ChargedCurrency.php
+++ b/Helper/ChargedCurrency.php
@@ -80,55 +80,57 @@ public function getQuoteAmountCurrency(Quote $quote)
return new AdyenAmountCurrency($quote->getGrandTotal(), $quote->getQuoteCurrencyCode());
}
- /**
- * @param Quote\Item $item
- * @return AdyenAmountCurrency
- */
- public function getQuoteItemAmountCurrency(Quote\Item $item)
+ public function getQuoteItemAmountCurrency(Quote\Item $item): AdyenAmountCurrency
{
$chargedCurrency = $this->config->getChargedCurrency($item->getStoreId());
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
- $item->getBasePrice(),
+ $item->getBaseRowTotal() / $item->getQty(),
$item->getQuote()->getBaseCurrencyCode(),
- $item->getBaseDiscountAmount(),
- $item->getBasePriceInclTax() - $item->getBasePrice(),
+ $item->getBaseDiscountAmount() / $item->getQty(),
+ $item->getBaseTaxAmount() / $item->getQty(),
null,
- $item->getBasePriceInclTax()
+ $item->getBaseRowTotalInclTax() / $item->getQty(),
+ $item->getBaseDiscountTaxCompensationAmount() / $item->getQty()
);
}
- $amount = $item->getRowTotal()/$item->getQty();
- $amountIncludingTax = $item->getRowTotalInclTax()/$item->getQty();
+
return new AdyenAmountCurrency(
- $amount,
+ $item->getRowTotal() / $item->getQty(),
$item->getQuote()->getQuoteCurrencyCode(),
- $item->getDiscountAmount(),
- $amountIncludingTax - $amount,
+ $item->getDiscountAmount() / $item->getQty(),
+ $item->getTaxAmount() / $item->getQty(),
null,
- $amountIncludingTax
+ $item->getRowTotalInclTax() / $item->getQty(),
+ $item->getDiscountTaxCompensationAmount() / $item->getQty()
);
}
- /**
- * @param Invoice\Item $item
- * @return AdyenAmountCurrency
- */
- public function getInvoiceItemAmountCurrency(Invoice\Item $item)
+ public function getInvoiceItemAmountCurrency(Invoice\Item $item): AdyenAmountCurrency
{
$chargedCurrency = $item->getInvoice()->getOrder()->getAdyenChargedCurrency();
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
- $item->getBasePrice(),
+ $item->getBaseRowTotal() / $item->getQty(),
$item->getInvoice()->getBaseCurrencyCode(),
+ $item->getBaseDiscountAmount() / $item->getQty(),
+ $item->getBaseTaxAmount() / $item->getQty(),
null,
- $item->getBaseTaxAmount() / $item->getQty()
+ $item->getBaseRowTotalInclTax() / $item->getQty(),
+ $item->getBaseDiscountTaxCompensationAmount() / $item->getQty()
);
}
+
return new AdyenAmountCurrency(
- $item->getPrice(),
+ $item->getRowTotal() / $item->getQty(),
$item->getInvoice()->getOrderCurrencyCode(),
+ $item->getDiscountAmount() / $item->getQty(),
+ $item->getTaxAmount() / $item->getQty(),
null,
- ($item->getQty() > 0) ? $item->getTaxAmount() / $item->getQty() : 0
+ $item->getRowTotalInclTax() / $item->getQty(),
+ $item->getDiscountTaxCompensationAmount() / $item->getQty()
);
}
@@ -175,60 +177,62 @@ public function getCreditMemoAdjustmentAmountCurrency(CreditmemoInterface $credi
);
}
- /**
- * @param CreditmemoInterface $creditMemo
- * @return AdyenAmountCurrency
- */
- public function getCreditMemoShippingAmountCurrency(CreditmemoInterface $creditMemo)
+ public function getCreditMemoShippingAmountCurrency(CreditmemoInterface $creditMemo): AdyenAmountCurrency
{
$chargedCurrency = $creditMemo->getOrder()->getAdyenChargedCurrency();
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$creditMemo->getBaseShippingAmount(),
$creditMemo->getBaseCurrencyCode(),
null,
- $creditMemo->getBaseShippingTaxAmount()
+ $creditMemo->getBaseShippingTaxAmount(),
+ null,
+ $creditMemo->getBaseShippingInclTax(),
+ $creditMemo->getBaseShippingDiscountTaxCompensationAmnt()
);
}
return new AdyenAmountCurrency(
$creditMemo->getShippingAmount(),
$creditMemo->getOrderCurrencyCode(),
null,
- $creditMemo->getShippingTaxAmount()
+ $creditMemo->getShippingTaxAmount(),
+ null,
+ $creditMemo->getShippingInclTax(),
+ $creditMemo->getShippingDiscountTaxCompensationAmount()
);
}
- /**
- * @param CreditmemoItemInterface $item
- * @return AdyenAmountCurrency
- */
- public function getCreditMemoItemAmountCurrency(CreditmemoItemInterface $item)
+ public function getCreditMemoItemAmountCurrency(CreditmemoItemInterface $item): AdyenAmountCurrency
{
$chargedCurrency = $item->getCreditMemo()->getOrder()->getAdyenChargedCurrency();
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
- $item->getBasePrice(),
+ $item->getBaseRowTotal() / $item->getQty(),
$item->getCreditMemo()->getBaseCurrencyCode(),
+ $item->getBaseDiscountAmount() / $item->getQty(),
+ $item->getBaseTaxAmount() / $item->getQty(),
null,
- $item->getBaseTaxAmount() / $item->getQty()
+ $item->getBaseRowTotalInclTax() / $item->getQty(),
+ $item->getBaseDiscountTaxCompensationAmount() / $item->getQty()
);
}
return new AdyenAmountCurrency(
- $item->getPrice(),
+ $item->getRowTotal() / $item->getQty(),
$item->getCreditMemo()->getOrderCurrencyCode(),
+ $item->getDiscountAmount() / $item->getQty(),
+ $item->getTaxAmount() / $item->getQty(),
null,
- $item->getTaxAmount() / $item->getQty()
+ $item->getRowTotalInclTax() / $item->getQty(),
+ $item->getDiscountTaxCompensationAmount() / $item->getQty()
);
}
-
- /**
- * @param Quote $quote
- * @return AdyenAmountCurrency
- */
- public function getQuoteShippingAmountCurrency(Quote $quote)
+ public function getQuoteShippingAmountCurrency(Quote $quote): AdyenAmountCurrency
{
$chargedCurrency = $this->config->getChargedCurrency($quote->getStoreId());
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$quote->getShippingAddress()->getBaseShippingAmount(),
@@ -236,39 +240,46 @@ public function getQuoteShippingAmountCurrency(Quote $quote)
$quote->getShippingAddress()->getBaseShippingDiscountAmount(),
$quote->getShippingAddress()->getBaseShippingTaxAmount(),
null,
- $quote->getShippingAddress()->getBaseShippingInclTax()
+ $quote->getShippingAddress()->getBaseShippingInclTax(),
+ $quote->getShippingAddress()->getBaseShippingDiscountTaxCompensationAmnt()
);
}
+
return new AdyenAmountCurrency(
$quote->getShippingAddress()->getShippingAmount(),
$quote->getQuoteCurrencyCode(),
$quote->getShippingAddress()->getShippingDiscountAmount(),
$quote->getShippingAddress()->getShippingTaxAmount(),
null,
- $quote->getShippingAddress()->getShippingInclTax()
+ $quote->getShippingAddress()->getShippingInclTax(),
+ $quote->getShippingAddress()->getShippingDiscountTaxCompensationAmount()
);
}
- /**
- * @param Invoice $invoice
- * @return AdyenAmountCurrency
- */
- public function getInvoiceShippingAmountCurrency(Invoice $invoice)
+ public function getInvoiceShippingAmountCurrency(Invoice $invoice): AdyenAmountCurrency
{
$chargedCurrency = $invoice->getOrder()->getAdyenChargedCurrency();
+
if ($chargedCurrency == self::BASE) {
return new AdyenAmountCurrency(
$invoice->getBaseShippingAmount(),
$invoice->getBaseCurrencyCode(),
null,
- $invoice->getBaseShippingTaxAmount()
+ $invoice->getBaseShippingTaxAmount(),
+ null,
+ $invoice->getBaseShippingInclTax(),
+ $invoice->getBaseShippingDiscountTaxCompensationAmnt()
);
}
+
return new AdyenAmountCurrency(
$invoice->getShippingAmount(),
$invoice->getOrderCurrencyCode(),
null,
- $invoice->getShippingTaxAmount()
+ $invoice->getShippingTaxAmount(),
+ null,
+ $invoice->getShippingInclTax(),
+ $invoice->getShippingDiscountTaxCompensationAmount()
);
}
diff --git a/Helper/Config.php b/Helper/Config.php
index 42bfe396b..4f0e959b6 100644
--- a/Helper/Config.php
+++ b/Helper/Config.php
@@ -54,6 +54,7 @@ class Config
const XML_WEBHOOK_NOTIFICATION_PROCESSOR = 'webhook_notification_processor';
const AUTO_CAPTURE_OPENINVOICE = 'auto';
const XML_RECURRING_CONFIGURATION = 'recurring_configuration';
+ const XML_ALLOW_MULTISTORE_TOKENS = 'allow_multistore_tokens';
protected ScopeConfigInterface $scopeConfig;
private EncryptorInterface $encryptor;
@@ -559,6 +560,16 @@ public function getRatePayId(int $storeId = null)
return $this->getConfigData("ratepay_id", self::XML_ADYEN_RATEPAY, $storeId);
}
+ public function getAllowMultistoreTokens(int $storeId = null): ?bool
+ {
+ return $this->getConfigData(
+ self::XML_ALLOW_MULTISTORE_TOKENS,
+ self::XML_ADYEN_ABSTRACT_PREFIX,
+ $storeId,
+ true
+ );
+ }
+
public function getConfigData(string $field, string $xmlPrefix, ?int $storeId, bool $flag = false): mixed
{
$path = implode("/", [self::XML_PAYMENT_PREFIX, $xmlPrefix, $field]);
diff --git a/Helper/OpenInvoice.php b/Helper/OpenInvoice.php
index 5265010a7..529b49746 100644
--- a/Helper/OpenInvoice.php
+++ b/Helper/OpenInvoice.php
@@ -14,39 +14,19 @@
use Adyen\Payment\Model\AdyenAmountCurrency;
use Magento\Catalog\Helper\Image;
-use Magento\Catalog\Model\Product;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Invoice;
-use Magento\Sales\Model\Order\Payment;
use Magento\Sales\Model\Order\Invoice\Item;
+use Magento\Quote\Model\Quote;
class OpenInvoice
{
- /**
- * @var AbstractHelper
- */
- protected $adyenHelper;
-
- /**
- * @var CartRepositoryInterface
- */
- protected $cartRepository;
-
- /**
- * @var ChargedCurrency
- */
- protected $chargedCurrency;
-
- /**
- * @var Config
- */
- protected $configHelper;
-
- /**
- * @var Image
- */
- protected $imageHelper;
+ protected Data $adyenHelper;
+ protected CartRepositoryInterface $cartRepository;
+ protected ChargedCurrency $chargedCurrency;
+ protected Config $configHelper;
+ protected Image $imageHelper;
public function __construct(
Data $adyenHelper,
@@ -54,8 +34,7 @@ public function __construct(
ChargedCurrency $chargedCurrency,
Config $configHelper,
Image $imageHelper
- )
- {
+ ) {
$this->adyenHelper = $adyenHelper;
$this->cartRepository = $cartRepository;
$this->chargedCurrency = $chargedCurrency;
@@ -63,46 +42,28 @@ public function __construct(
$this->imageHelper = $imageHelper;
}
- public function getOpenInvoiceDataForLastInvoice(Payment $payment): array
+ public function getOpenInvoiceDataForInvoice(Invoice $invoice): array
{
$formFields = ['lineItems' => []];
- $order = $payment->getOrder();
- $invoices = $order->getInvoiceCollection();
- // The latest invoice will contain only the selected items(and quantities) for the (partial) capture
- /** @var Invoice $invoice */
- $invoice = $invoices->getLastItem();
- $discountAmount = 0;
- $currency = $this->chargedCurrency->getOrderAmountCurrency($payment->getOrder(), false);
/* @var Item $invoiceItem */
foreach ($invoice->getItems() as $invoiceItem) {
$numberOfItems = (int)$invoiceItem->getQty();
$orderItem = $invoiceItem->getOrderItem();
+
if ($orderItem->getParentItem() || $numberOfItems <= 0) {
continue;
}
- $product = $orderItem->getProduct();
- $itemAmountCurrency = $this->chargedCurrency->getInvoiceItemAmountCurrency($invoiceItem);
- $discountAmount += $itemAmountCurrency->getDiscountAmount();
- $formFields['lineItems'][] = $this->formatInoviceItem(
- $itemAmountCurrency, $orderItem, $product, $numberOfItems
- );
- }
- // Discount cost
- if ($discountAmount != 0) {
- $formFields['lineItems'][] = $this->formatInvoiceDiscount(
- $discountAmount,
- $invoice->getShippingAddress()->getShippingDiscountAmount(),
- $currency
- );
+ $itemAmountCurrency = $this->chargedCurrency->getInvoiceItemAmountCurrency($invoiceItem);
+ $formFields['lineItems'][] = $this->formatLineItem($itemAmountCurrency, $orderItem, $numberOfItems);
}
if ($invoice->getShippingAmount() > 0 || $invoice->getShippingTaxAmount() > 0) {
$adyenInvoiceShippingAmount = $this->chargedCurrency->getInvoiceShippingAmountCurrency($invoice);
- $formFields['lineItems'][] = $this->formatInvoiceShippingItem(
+ $formFields['lineItems'][] = $this->formatShippingLineItem(
$adyenInvoiceShippingAmount,
- $order->getShippingDescription()
+ $invoice->getOrder()->getShippingDescription()
);
}
@@ -112,80 +73,47 @@ public function getOpenInvoiceDataForLastInvoice(Payment $payment): array
public function getOpenInvoiceDataForOrder(Order $order): array
{
$formFields = ['lineItems' => []];
- /** @var \Magento\Quote\Model\Quote $cart */
+ /** @var Quote $cart */
$cart = $this->cartRepository->get($order->getQuoteId());
- $amountCurrency = $this->chargedCurrency->getOrderAmountCurrency($order);
- $discountAmount = 0;
foreach ($cart->getAllVisibleItems() as $item) {
$itemAmountCurrency = $this->chargedCurrency->getQuoteItemAmountCurrency($item);
- $numberOfItems = (int)$item->getQty();
- $product = $item->getProduct();
- // Summarize the discount amount item by item
- $discountAmount += $itemAmountCurrency->getDiscountAmount();
- $formFields['lineItems'][] = $this->formatInoviceItem($itemAmountCurrency, $item, $product, $numberOfItems);
+ $formFields['lineItems'][] = $this->formatLineItem($itemAmountCurrency, $item);
}
- // Discount cost
- if ($discountAmount != 0) {
- $formFields['lineItems'][] = $this->formatInvoiceDiscount(
- $discountAmount,
- $cart->getShippingAddress()->getShippingDiscountAmount(),
- $amountCurrency
- );
- }
-
- // Shipping cost
- if (
- $cart->getShippingAddress()->getShippingAmount() > 0 ||
- $cart->getShippingAddress()->getShippingTaxAmount() > 0
- ) {
+ if ($cart->getShippingAddress()->getShippingAmount() > 0) {
$shippingAmountCurrency = $this->chargedCurrency->getQuoteShippingAmountCurrency($cart);
- $formFields['lineItems'][] = $this->formatInvoiceShippingItem(
- $shippingAmountCurrency, $order->getShippingDescription()
+ $formFields['lineItems'][] = $this->formatShippingLineItem(
+ $shippingAmountCurrency,
+ $order->getShippingDescription()
);
}
return $formFields;
}
- public function getOpenInvoiceDataForCreditMemo(Payment $payment)
+ public function getOpenInvoiceDataForCreditMemo(Order\Creditmemo $creditMemo)
{
$formFields = ['lineItems' => []];
- $discountAmount = 0;
- $creditMemo = $payment->getCreditMemo();
- $currency = $this->chargedCurrency->getOrderAmountCurrency($payment->getOrder(), false);
- foreach ($creditMemo->getItems() as $refundItem) {
- $numberOfItems = (int)$refundItem->getQty();
- if ($numberOfItems <= 0) {
+ foreach ($creditMemo->getItems() as $creditmemoItem) {
+ if ($creditmemoItem->getQty() <= 0) {
continue;
}
- $itemAmountCurrency = $this->chargedCurrency->getCreditMemoItemAmountCurrency($refundItem);
- $discountAmount += $itemAmountCurrency->getDiscountAmount();
- $orderItem = $refundItem->getOrderItem();
- $product = $orderItem->getProduct();
-
- $formFields['lineItems'][] = $this->formatInoviceItem(
- $itemAmountCurrency, $orderItem, $product, $numberOfItems
- );
- }
-
- // Discount cost
- if ($discountAmount != 0) {
- $formFields['lineItems'][] = $this->formatInvoiceDiscount(
- $discountAmount,
- $payment->getOrder()->getShippingAddress()->getShippingDiscountAmount(),
- $currency
+ $itemAmountCurrency = $this->chargedCurrency->getCreditMemoItemAmountCurrency($creditmemoItem);
+ $formFields['lineItems'][] = $this->formatLineItem(
+ $itemAmountCurrency,
+ $creditmemoItem->getOrderItem(),
+ $creditmemoItem->getQty()
);
}
- // Shipping cost
- $shippingAmountCurrency = $this->chargedCurrency->getCreditMemoShippingAmountCurrency($creditMemo);
- if ($shippingAmountCurrency->getAmount() > 0) {
- $formFields['lineItems'][] = $this->formatInvoiceShippingItem(
- $shippingAmountCurrency, $payment->getOrder()->getShippingDescription()
+ if ($creditMemo->getShippingAmount() > 0) {
+ $shippingAmountCurrency = $this->chargedCurrency->getCreditMemoShippingAmountCurrency($creditMemo);
+ $formFields['lineItems'][] = $this->formatShippingLineItem(
+ $shippingAmountCurrency,
+ $creditMemo->getOrder()->getShippingDescription()
);
}
@@ -206,17 +134,26 @@ protected function getImageUrl($item): string
return $imageUrl;
}
- protected function formatInvoiceShippingItem(
- AdyenAmountCurrency $shippingAmount, string $shippingDescription
- ): array
- {
+ protected function formatShippingLineItem(
+ AdyenAmountCurrency $shippingAmount,
+ string $shippingDescription
+ ): array {
$currency = $shippingAmount->getCurrencyCode();
- $formattedPriceExcludingTax = $this->adyenHelper->formatAmount($shippingAmount->getAmount(), $currency);
+
+ $formattedPriceExcludingTax = $this->adyenHelper->formatAmount(
+ $shippingAmount->getAmountWithDiscount(),
+ $currency
+ );
$formattedPriceIncludingTax = $this->adyenHelper->formatAmount(
- $shippingAmount->getAmountIncludingTax(),
+ $shippingAmount->getAmountIncludingTaxWithDiscount(),
$currency
);
+
$formattedTaxAmount = $this->adyenHelper->formatAmount($shippingAmount->getTaxAmount(), $currency);
+ $formattedTaxPercentage = $this->adyenHelper->formatAmount(
+ $shippingAmount->getCalculatedTaxPercentage(),
+ $currency
+ );
return [
'id' => 'shippingCost',
@@ -225,36 +162,35 @@ protected function formatInvoiceShippingItem(
'taxAmount' => $formattedTaxAmount,
'description' => $shippingDescription,
'quantity' => 1,
- 'taxPercentage' => (int)round(($formattedTaxAmount / $formattedPriceExcludingTax) * 100 * 100)
+ 'taxPercentage' => $formattedTaxPercentage
];
}
- /**
- * @param AdyenAmountCurrency $itemAmountCurrency
- * @param $item
- * @param Product $product
- * @param int $numberOfItems
- * @return array
- */
- protected function formatInoviceItem(
- AdyenAmountCurrency $itemAmountCurrency, $item, Product $product, int $numberOfItems
- ): array
+ protected function formatLineItem(AdyenAmountCurrency $itemAmountCurrency, $item, $qty = null): array
{
$currency = $itemAmountCurrency->getCurrencyCode();
- $formattedPriceExcludingTax = $this->adyenHelper->formatAmount($itemAmountCurrency->getAmount(), $currency);
+
+ $formattedPriceExcludingTax = $this->adyenHelper->formatAmount(
+ $itemAmountCurrency->getAmountWithDiscount(),
+ $currency
+ );
$formattedPriceIncludingTax = $this->adyenHelper->formatAmount(
- $itemAmountCurrency->getAmountIncludingTax(), $currency
+ $itemAmountCurrency->getAmountIncludingTaxWithDiscount(),
+ $currency
);
+
$formattedTaxAmount = $this->adyenHelper->formatAmount($itemAmountCurrency->getTaxAmount(), $currency);
$formattedTaxPercentage = $this->adyenHelper->formatAmount($item->getTaxPercent(), $currency);
+ $product = $item->getProduct();
+
return [
'id' => $product->getId(),
'amountExcludingTax' => $formattedPriceExcludingTax,
'amountIncludingTax' => $formattedPriceIncludingTax,
'taxAmount' => $formattedTaxAmount,
'description' => $item->getName(),
- 'quantity' => $numberOfItems,
+ 'quantity' => (int) ($qty ?? $item->getQty()),
'taxPercentage' => $formattedTaxPercentage,
'productUrl' => $product->getUrlModel()->getUrl($product),
'imageUrl' => $this->getImageUrl($item)
diff --git a/Helper/PaymentMethods.php b/Helper/PaymentMethods.php
index c358103ef..aab4e4df0 100644
--- a/Helper/PaymentMethods.php
+++ b/Helper/PaymentMethods.php
@@ -40,7 +40,8 @@
use Adyen\Payment\Helper\Data as AdyenDataHelper;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\Store;
-
+use Magento\Vault\Api\PaymentTokenRepositoryInterface;
+use Magento\Framework\Api\SearchCriteriaBuilder;
class PaymentMethods extends AbstractHelper
{
const ADYEN_HPP = 'adyen_hpp';
@@ -86,6 +87,8 @@ class PaymentMethods extends AbstractHelper
private Config $configHelper;
private ManualCapture $manualCapture;
private SerializerInterface $serializer;
+ private PaymentTokenRepositoryInterface $paymentTokenRepository;
+ private SearchCriteriaBuilder $searchCriteriaBuilder;
public function __construct(
Context $context,
@@ -104,7 +107,9 @@ public function __construct(
MagentoDataHelper $dataHelper,
ManualCapture $manualCapture,
SerializerInterface $serializer,
- AdyenDataHelper $adyenDataHelper
+ AdyenDataHelper $adyenDataHelper,
+ PaymentTokenRepositoryInterface $paymentTokenRepository,
+ SearchCriteriaBuilder $searchCriteriaBuilder
) {
parent::__construct($context);
$this->quoteRepository = $quoteRepository;
@@ -123,6 +128,8 @@ public function __construct(
$this->manualCapture = $manualCapture;
$this->serializer = $serializer;
$this->adyenDataHelper = $adyenDataHelper;
+ $this->paymentTokenRepository = $paymentTokenRepository;
+ $this->searchCriteriaBuilder = $searchCriteriaBuilder;
}
public function getPaymentMethods(int $quoteId, ?string $country = null, ?string $shopperLocale = null): string
@@ -198,6 +205,11 @@ protected function fetchPaymentMethods(?string $country = null, ?string $shopper
}
$paymentMethods = $responseData['paymentMethods'];
+
+ $allowMultistoreTokens = $this->configHelper->getAllowMultistoreTokens($store->getId());
+ $customerId = $quote->getCustomerId();
+ $responseData = $this->filterStoredPaymentMethods($allowMultistoreTokens, $responseData, $customerId);
+
$response['paymentMethodsResponse'] = $responseData;
// Add extra details per payment method
@@ -213,6 +225,30 @@ protected function fetchPaymentMethods(?string $country = null, ?string $shopper
return json_encode($response);
}
+ protected function filterStoredPaymentMethods($allowMultistoreTokens, $responseData, $customerId)
+ {
+ if (!$allowMultistoreTokens && isset($responseData['storedPaymentMethods'])) {
+ $searchCriteria = $this->searchCriteriaBuilder
+ ->addFilter('customer_id', $customerId)
+ ->create();
+
+ $paymentTokens = $this->paymentTokenRepository->getList($searchCriteria)->getItems();
+
+ $gatewayTokens = array_map(function ($paymentToken) {
+ return $paymentToken->getGatewayToken();
+ }, $paymentTokens);
+
+ $storedPaymentMethods = $responseData['storedPaymentMethods'];
+ $responseData['storedPaymentMethods'] = array_filter(
+ $storedPaymentMethods,
+ function ($method) use ($gatewayTokens) {
+ return in_array($method['id'], $gatewayTokens);
+ });
+ }
+
+ return $responseData;
+ }
+
protected function getCurrentPaymentAmount(): float
{
$total = $this->chargedCurrency->getQuoteAmountCurrency($this->getQuote())->getAmount();
diff --git a/Helper/StateData.php b/Helper/StateData.php
index 3a83fa8d2..a3675468c 100644
--- a/Helper/StateData.php
+++ b/Helper/StateData.php
@@ -16,7 +16,9 @@
use Adyen\Payment\Logger\AdyenLogger;
use Adyen\Payment\Model\ResourceModel\StateData as StateDataResourceModel;
use Adyen\Payment\Model\ResourceModel\StateData\Collection as StateDataCollection;
+use Adyen\Payment\Model\StateData as AdyenStateData;
use Adyen\Payment\Model\StateDataFactory;
+use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
@@ -80,7 +82,14 @@ public function getPaymentMethodVariant(int $quoteId): string
return $stateDataByQuoteId['paymentMethod']['type'];
}
- public function saveStateData(string $stateData, int $quoteId): void
+ /**
+ * @param string $stateData
+ * @param int $quoteId
+ * @return AdyenStateData
+ * @throws LocalizedException
+ * @throws AlreadyExistsException
+ */
+ public function saveStateData(string $stateData, int $quoteId): AdyenStateData
{
// Decode payload from frontend
$stateData = json_decode($stateData, true);
@@ -92,10 +101,11 @@ public function saveStateData(string $stateData, int $quoteId): void
$stateData = json_encode($this->checkoutStateDataValidator->getValidatedAdditionalData($stateData));
- /** @var \Adyen\Payment\Model\StateData $stateDataObj */
$stateDataObj = $this->stateDataFactory->create();
$stateDataObj->setQuoteId($quoteId)->setStateData((string)$stateData);
$this->stateDataResourceModel->save($stateDataObj);
+
+ return $stateDataObj;
}
/**
diff --git a/Model/AdyenAmountCurrency.php b/Model/AdyenAmountCurrency.php
index 83c99c5dc..5322bfb36 100644
--- a/Model/AdyenAmountCurrency.php
+++ b/Model/AdyenAmountCurrency.php
@@ -25,13 +25,16 @@ class AdyenAmountCurrency
protected $amountDue;
+ protected $discountTaxCompensationAmount;
+
public function __construct(
$amount,
$currencyCode,
$discountAmount = 0,
$taxAmount = 0,
$amountDue = 0,
- $amountIncludingTax = 0
+ $amountIncludingTax = 0,
+ $discountTaxCompensationAmount = 0
) {
$this->amount = $amount;
$this->amountIncludingTax = $amountIncludingTax;
@@ -39,6 +42,7 @@ public function __construct(
$this->discountAmount = $discountAmount;
$this->taxAmount = $taxAmount;
$this->amountDue = $amountDue;
+ $this->discountTaxCompensationAmount = $discountTaxCompensationAmount;
}
public function getAmount()
@@ -70,4 +74,29 @@ public function getAmountDue()
{
return $this->amountDue;
}
+
+ public function getDiscountTaxCompensationAmount()
+ {
+ return $this->discountTaxCompensationAmount;
+ }
+
+ public function getAmountIncludingTaxWithDiscount()
+ {
+ if ($this->getDiscountTaxCompensationAmount() > 0) {
+ return $this->getAmountIncludingTax() - $this->getDiscountAmount();
+ } else {
+ $taxCompensation = $this->getDiscountAmount() * $this->getCalculatedTaxPercentage() / 100;
+ return $this->getAmountIncludingTax() - $this->getDiscountAmount() - $taxCompensation;
+ }
+ }
+
+ public function getAmountWithDiscount()
+ {
+ return $this->getAmount() - $this->getDiscountAmount() + $this->getDiscountTaxCompensationAmount();
+ }
+
+ public function getCalculatedTaxPercentage()
+ {
+ return $this->getTaxAmount() / ($this->getAmountWithDiscount()) * 100;
+ }
}
diff --git a/Model/Api/AdyenStateData.php b/Model/Api/AdyenStateData.php
index 4233fe026..9559466a0 100644
--- a/Model/Api/AdyenStateData.php
+++ b/Model/Api/AdyenStateData.php
@@ -25,13 +25,14 @@ public function __construct(
$this->stateDataHelper = $stateDataHelper;
}
- public function save(string $stateData, int $quoteId): void
+ public function save(string $stateData, int $cartId): int
{
- $this->stateDataHelper->saveStateData($stateData, $quoteId);
+ $stateData = $this->stateDataHelper->saveStateData($stateData, $cartId);
+ return $stateData->getEntityId();
}
- public function remove(int $stateDataId, int $quoteId): bool
+ public function remove(int $stateDataId, int $cartId): bool
{
- return $this->stateDataHelper->removeStateData($stateDataId, $quoteId);
+ return $this->stateDataHelper->removeStateData($stateDataId, $cartId);
}
}
diff --git a/Model/Api/GuestAdyenStateData.php b/Model/Api/GuestAdyenStateData.php
index 0e2f02cfe..b78c9b2db 100644
--- a/Model/Api/GuestAdyenStateData.php
+++ b/Model/Api/GuestAdyenStateData.php
@@ -14,6 +14,7 @@
use Adyen\Payment\Api\GuestAdyenStateDataInterface;
use Adyen\Payment\Helper\StateData as StateDataHelper;
+use Magento\Framework\Exception\AlreadyExistsException;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
@@ -33,14 +34,19 @@ public function __construct(
}
/**
+ * @param string $stateData
+ * @param string $cartId
+ * @return int
* @throws InputException
* @throws LocalizedException
+ * @throws AlreadyExistsException
*/
- public function save(string $stateData, string $cartId): void
+ public function save(string $stateData, string $cartId): int
{
$quoteId = $this->getQuoteIdFromMaskedCartId($cartId);
+ $stateData = $this->stateDataHelper->saveStateData($stateData, $quoteId);
- $this->stateDataHelper->saveStateData($stateData, $quoteId);
+ return $stateData->getEntityId();
}
/**
diff --git a/Model/Resolver/GetAdyenPaymentMethodsBalance.php b/Model/Resolver/GetAdyenPaymentMethodsBalance.php
new file mode 100644
index 000000000..bd5baf4b6
--- /dev/null
+++ b/Model/Resolver/GetAdyenPaymentMethodsBalance.php
@@ -0,0 +1,76 @@
+
+ */
+declare(strict_types=1);
+
+namespace Adyen\Payment\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Model\Api\AdyenPaymentMethodsBalance;
+use Exception;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+
+class GetAdyenPaymentMethodsBalance implements ResolverInterface
+{
+ /**
+ * @var AdyenPaymentMethodsBalance
+ */
+ private AdyenPaymentMethodsBalance $balance;
+
+ /**
+ * @param AdyenPaymentMethodsBalance $balance
+ */
+ public function __construct(
+ AdyenPaymentMethodsBalance $balance
+ ) {
+ $this->balance = $balance;
+ }
+
+ /**
+ * @param Field $field
+ * @param $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ * @throws GraphQlAdyenException
+ * @throws GraphQlInputException
+ * @throws Exception
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ): array {
+ if (empty($args['payload'])) {
+ throw new GraphQlInputException(__('Required parameter "payload" is missing'));
+ }
+
+ $payload = $args['payload'];
+ try {
+ $balanceResponse = $this->balance->getBalance($payload);
+ } catch (Exception $e) {
+ throw new GraphQlAdyenException(
+ __('An error occurred while fetching the payment method balance.'),
+ $e
+ );
+ }
+
+ return ['balanceResponse' => $balanceResponse];
+ }
+}
+
+
diff --git a/Model/Resolver/GetAdyenRedeemedGiftcards.php b/Model/Resolver/GetAdyenRedeemedGiftcards.php
new file mode 100644
index 000000000..758174462
--- /dev/null
+++ b/Model/Resolver/GetAdyenRedeemedGiftcards.php
@@ -0,0 +1,99 @@
+
+ */
+declare(strict_types=1);
+
+namespace Adyen\Payment\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Helper\GiftcardPayment;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Framework\Serialize\Serializer\Json;
+
+class GetAdyenRedeemedGiftcards implements ResolverInterface
+{
+ /**
+ * @var GiftcardPayment
+ */
+ private GiftcardPayment $giftcardPayment;
+
+ /**
+ * @var Json
+ */
+ private Json $jsonSerializer;
+
+ /**
+ * @var QuoteIdMaskFactory
+ */
+ private QuoteIdMaskFactory $quoteIdMaskFactory;
+
+ /**
+ * @param GiftcardPayment $giftcardPayment
+ * @param Json $jsonSerializer
+ * @param QuoteIdMaskFactory $quoteIdMaskFactory
+ */
+ public function __construct(
+ GiftcardPayment $giftcardPayment,
+ Json $jsonSerializer,
+ QuoteIdMaskFactory $quoteIdMaskFactory
+ ) {
+ $this->giftcardPayment = $giftcardPayment;
+ $this->jsonSerializer = $jsonSerializer;
+ $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ }
+
+ /**
+ * @param Field $field
+ * @param $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ * @throws GraphQlAdyenException
+ * @throws GraphQlInputException
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ) {
+ if (empty($args['cartId'])) {
+ throw new GraphQlInputException(__('Required parameter "cartId" is missing'));
+ }
+
+ $cartId = $args['cartId'];
+ $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id');
+ $quoteId = $quoteIdMask->getQuoteId();
+ $quoteId = (int)$quoteId;
+
+ try {
+ $redeemedGiftcardsJson = $this->giftcardPayment->fetchRedeemedGiftcards($quoteId);
+ } catch (\Exception $e) {
+ throw new GraphQlAdyenException(
+ __('An error occurred while fetching redeemed gift cards: %1', $e->getMessage())
+ );
+ }
+
+ $redeemedGiftcardsData = $this->jsonSerializer->unserialize($redeemedGiftcardsJson);
+
+ return [
+ 'redeemedGiftcards' => $redeemedGiftcardsData['redeemedGiftcards'],
+ 'remainingAmount' => $redeemedGiftcardsData['remainingAmount'],
+ 'totalDiscount' => $redeemedGiftcardsData['totalDiscount']
+ ];
+ }
+}
diff --git a/Model/Resolver/RemoveAdyenStateData.php b/Model/Resolver/RemoveAdyenStateData.php
new file mode 100644
index 000000000..494dc36c2
--- /dev/null
+++ b/Model/Resolver/RemoveAdyenStateData.php
@@ -0,0 +1,93 @@
+
+ */
+declare(strict_types=1);
+
+namespace Adyen\Payment\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Model\Api\AdyenStateData;
+use Exception;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+
+class RemoveAdyenStateData implements ResolverInterface
+{
+ /**
+ * @var AdyenStateData
+ */
+ private AdyenStateData $adyenStateData;
+
+ /**
+ * @var QuoteIdMaskFactory
+ */
+ private QuoteIdMaskFactory $quoteIdMaskFactory;
+
+ /**
+ * @param AdyenStateData $adyenStateData
+ * @param QuoteIdMaskFactory $quoteIdMaskFactory
+ */
+ public function __construct(
+ AdyenStateData $adyenStateData,
+ QuoteIdMaskFactory $quoteIdMaskFactory
+ ) {
+ $this->adyenStateData = $adyenStateData;
+ $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ }
+
+ /**
+ * @param Field $field
+ * @param $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ * @throws GraphQlAdyenException
+ * @throws GraphQlInputException
+ * @throws LocalizedException
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ): array {
+ if (empty($args['stateDataId'])) {
+ throw new GraphQlInputException(__('Required parameter "stateDataId" is missing'));
+ }
+
+ if (empty($args['cartId'])) {
+ throw new GraphQlInputException(__('Required parameter "cartId" is missing'));
+ }
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create()->load($args['cartId'], 'masked_id');
+ $quoteId = $quoteIdMask->getQuoteId();
+
+ try {
+ $result = $this->adyenStateData->remove((int) $args['stateDataId'], (int) $quoteId);
+ } catch (Exception $e) {
+ throw new GraphQlAdyenException(__('An error occurred while removing the state data.'), $e);
+ }
+
+ if (!$result) {
+ throw new LocalizedException(__('An error occurred while removing the state data.'));
+ }
+
+ return ['stateDataId' => $args['stateDataId']];
+ }
+}
+
+
diff --git a/Model/Resolver/SaveAdyenStateData.php b/Model/Resolver/SaveAdyenStateData.php
new file mode 100644
index 000000000..7fc1c2bee
--- /dev/null
+++ b/Model/Resolver/SaveAdyenStateData.php
@@ -0,0 +1,87 @@
+
+ */
+declare(strict_types=1);
+
+namespace Adyen\Payment\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Model\Api\AdyenStateData;
+use Exception;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Query\ResolverInterface;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+
+class SaveAdyenStateData implements ResolverInterface
+{
+ /**
+ * @var AdyenStateData
+ */
+ private AdyenStateData $adyenStateData;
+
+ /**
+ * @var QuoteIdMaskFactory
+ */
+ private QuoteIdMaskFactory $quoteIdMaskFactory;
+
+ /**
+ * @param AdyenStateData $adyenStateData
+ * @param QuoteIdMaskFactory $quoteIdMaskFactory
+ */
+ public function __construct(
+ AdyenStateData $adyenStateData,
+ QuoteIdMaskFactory $quoteIdMaskFactory
+ ) {
+ $this->adyenStateData = $adyenStateData;
+ $this->quoteIdMaskFactory = $quoteIdMaskFactory;
+ }
+
+ /**
+ * @param Field $field
+ * @param $context
+ * @param ResolveInfo $info
+ * @param array|null $value
+ * @param array|null $args
+ * @return array
+ * @throws GraphQlAdyenException
+ * @throws GraphQlInputException
+ */
+ public function resolve(
+ Field $field,
+ $context,
+ ResolveInfo $info,
+ array $value = null,
+ array $args = null
+ ): array {
+ if (empty($args['stateData'])) {
+ throw new GraphQlInputException(__('Required parameter "stateData" is missing'));
+ }
+
+ if (empty($args['cartId'])) {
+ throw new GraphQlInputException(__('Required parameter "cartId" is missing'));
+ }
+
+ $quoteIdMask = $this->quoteIdMaskFactory->create()->load($args['cartId'], 'masked_id');
+ $quoteId = $quoteIdMask->getQuoteId();
+
+ try {
+ $stateDataId = $this->adyenStateData->save($args['stateData'], (int) $quoteId);
+ } catch (Exception $e) {
+ throw new GraphQlAdyenException(__('An error occurred while saving the state data.'), $e);
+ }
+
+ return ['stateDataId' => $stateDataId];
+ }
+}
+
+
diff --git a/Observer/AdyenCcDataAssignObserver.php b/Observer/AdyenCcDataAssignObserver.php
index c354be8fb..1d86fadc6 100644
--- a/Observer/AdyenCcDataAssignObserver.php
+++ b/Observer/AdyenCcDataAssignObserver.php
@@ -116,9 +116,8 @@ public function execute(Observer $observer)
// JSON decode state data from the frontend or fetch it from the DB entity with the quote ID
if (!empty($additionalData[self::STATE_DATA])) {
$stateData = json_decode((string) $additionalData[self::STATE_DATA], true);
- } else {
- $stateData = $this->stateDataCollection->getStateDataArrayWithQuoteId($paymentInfo->getData('quote_id'));
}
+
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData($stateData);
diff --git a/Observer/AdyenMotoDataAssignObserver.php b/Observer/AdyenMotoDataAssignObserver.php
index d49c162bf..09be9b649 100644
--- a/Observer/AdyenMotoDataAssignObserver.php
+++ b/Observer/AdyenMotoDataAssignObserver.php
@@ -106,9 +106,8 @@ public function execute(Observer $observer)
// JSON decode state data from the frontend or fetch it from the DB entity with the quote ID
if (!empty($additionalData[self::STATE_DATA])) {
$orderStateData = json_decode((string) $additionalData[self::STATE_DATA], true);
- } else {
- $orderStateData = $this->stateDataCollection->getStateDataArrayWithQuoteId($paymentInfo->getData('quote_id'));
}
+
// Get validated state data array
if (!empty($orderStateData)) {
$orderStateData = $this->checkoutStateDataValidator->getValidatedAdditionalData($orderStateData);
diff --git a/Observer/AdyenPaymentMethodDataAssignObserver.php b/Observer/AdyenPaymentMethodDataAssignObserver.php
index 0c18603c5..3416158d1 100644
--- a/Observer/AdyenPaymentMethodDataAssignObserver.php
+++ b/Observer/AdyenPaymentMethodDataAssignObserver.php
@@ -89,9 +89,8 @@ public function execute(Observer $observer)
} elseif (!empty($additionalData[self::CC_NUMBER])) {
$stateData = json_decode((string) $additionalData[self::CC_NUMBER], true);
$paymentInfo->setAdditionalInformation(self::BRAND_CODE, $stateData['paymentMethod']['type']);
- } else {
- $stateData = $this->stateDataCollection->getStateDataArrayWithQuoteId($paymentInfo->getData('quote_id'));
}
+
// Get validated state data array
if (!empty($stateData)) {
$stateData = $this->checkoutStateDataValidator->getValidatedAdditionalData($stateData);
diff --git a/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php b/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php
index ccbe3e091..f51334ccf 100644
--- a/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php
+++ b/Test/Unit/Gateway/Request/CaptureDataBuilderTest.php
@@ -79,6 +79,16 @@ public static function adyenOrderPaymentsProvider(): array
*/
public function testBuildCaptureRequest($adyenOrderPayments, $fullAmountAuthorized)
{
+ $adyenHelperMock = $this->createPartialMock(Data::class, ['isPaymentMethodOpenInvoiceMethod']);
+ $adyenHelperMock->method('isPaymentMethodOpenInvoiceMethod')->willReturn(true);
+
+ $lineItems = [
+ 'id' => PHP_INT_MAX
+ ];
+
+ $openInvoiceHelperMock = $this->createMock(OpenInvoice::class);
+ $openInvoiceHelperMock->method('getOpenInvoiceDataForInvoice')->willReturn($lineItems);
+
if (!$fullAmountAuthorized) {
$this->expectException(AdyenException::class);
}
@@ -121,10 +131,13 @@ public function testBuildCaptureRequest($adyenOrderPayments, $fullAmountAuthoriz
];
$captureDataBuilder = $this->buildCaptureDataBuilderObject(
- null,
+ $adyenHelperMock,
$chargedCurrencyHelperMock,
$orderPaymentResourceModelMock,
- $adyenOrderPaymentHelperMock
+ $adyenOrderPaymentHelperMock,
+ null,
+ null,
+ $openInvoiceHelperMock
);
$request = $captureDataBuilder->build($buildSubject);
diff --git a/Test/Unit/Helper/ChargedCurrencyTest.php b/Test/Unit/Helper/ChargedCurrencyTest.php
index 183a5975d..8416d9472 100755
--- a/Test/Unit/Helper/ChargedCurrencyTest.php
+++ b/Test/Unit/Helper/ChargedCurrencyTest.php
@@ -34,7 +34,8 @@ class ChargedCurrencyTest extends AbstractAdyenTestCase
'discountAmount' => 67.89,
'taxAmount' => 12.34,
'amountDue' => 56.78,
- 'amountIncludingTax' => 135.79
+ 'amountIncludingTax' => 135.79,
+ 'discountTaxCompensationAmount' => 0.05
],
'display' =>
[
@@ -43,7 +44,8 @@ class ChargedCurrencyTest extends AbstractAdyenTestCase
'discountAmount' => 98.76,
'taxAmount' => 54.32,
'amountDue' => 10.98,
- 'amountIncludingTax' => 708.64
+ 'amountIncludingTax' => 708.64,
+ 'discountTaxCompensationAmount' => 0.02
]
];
@@ -192,12 +194,16 @@ protected function setUp(): void
'getBasePrice',
'getBaseDiscountAmount',
'getBaseTaxAmount',
+ 'getBaseRowTotal',
'getRowTotal',
'getDiscountAmount',
'getTaxAmount',
'getBasePriceInclTax',
'getPriceInclTax',
- 'getRowTotalInclTax'
+ 'getRowTotalInclTax',
+ 'getBaseRowTotalInclTax',
+ 'getDiscountTaxCompensationAmount',
+ 'getBaseDiscountTaxCompensationAmount'
]
);
@@ -208,13 +214,17 @@ protected function setUp(): void
'getBaseDiscountAmount' => self::AMOUNT_CURRENCY['base']['discountAmount'],
'getBaseTaxAmount' => self::AMOUNT_CURRENCY['base']['taxAmount'],
'getRowTotal' => self::AMOUNT_CURRENCY['display']['amount'],
+ 'getBaseRowTotal' => self::AMOUNT_CURRENCY['base']['amount'],
'getQty' => 1,
'getDiscountAmount' => self::AMOUNT_CURRENCY['display']['discountAmount'],
'getTaxAmount' => self::AMOUNT_CURRENCY['display']['taxAmount'],
'getQuote' => $this->quote,
'getBasePriceInclTax' => self::AMOUNT_CURRENCY['base']['amountIncludingTax'],
'getPriceInclTax' => self::AMOUNT_CURRENCY['display']['amountIncludingTax'],
- 'getRowTotalInclTax' => self::AMOUNT_CURRENCY['display']['amountIncludingTax']
+ 'getRowTotalInclTax' => self::AMOUNT_CURRENCY['display']['amountIncludingTax'],
+ 'getBaseRowTotalInclTax' => self::AMOUNT_CURRENCY['base']['amountIncludingTax'],
+ 'getBaseDiscountTaxCompensationAmount' => self::AMOUNT_CURRENCY['base']['discountTaxCompensationAmount'],
+ 'getDiscountTaxCompensationAmount' => self::AMOUNT_CURRENCY['display']['discountTaxCompensationAmount']
]
);
@@ -231,7 +241,10 @@ protected function setUp(): void
'getGrandTotal',
'getBaseGrandTotal'
],
- []
+ [
+ 'getBaseRowTotal',
+ 'getRowTotal'
+ ]
);
$this->mockMethods($this->invoice,
@@ -244,7 +257,9 @@ protected function setUp(): void
'getShippingAmount' => self::AMOUNT_CURRENCY['display']['amount'],
'getShippingTaxAmount' => self::AMOUNT_CURRENCY['display']['taxAmount'],
'getGrandTotal' => self::AMOUNT_CURRENCY['display']['amount'],
- 'getBaseGrandTotal' => self::AMOUNT_CURRENCY['base']['amount']
+ 'getBaseGrandTotal' => self::AMOUNT_CURRENCY['base']['amount'],
+ 'getBaseRowTotal' => self::AMOUNT_CURRENCY['base']['amount'],
+ 'getRowTotal' => self::AMOUNT_CURRENCY['display']['amount'],
]
);
@@ -256,7 +271,9 @@ protected function setUp(): void
'getBaseTaxAmount',
'getPrice',
'getTaxAmount',
- 'getQty'
+ 'getQty',
+ 'getBaseRowTotal',
+ 'getRowTotal'
],
[]
);
@@ -267,7 +284,9 @@ protected function setUp(): void
'getBaseTaxAmount' => self::AMOUNT_CURRENCY['base']['taxAmount'],
'getPrice' => self::AMOUNT_CURRENCY['display']['amount'],
'getTaxAmount' => self::AMOUNT_CURRENCY['display']['taxAmount'],
- 'getQty' => 1
+ 'getQty' => 1,
+ 'getBaseRowTotal' => self::AMOUNT_CURRENCY['base']['amount'],
+ 'getRowTotal' => self::AMOUNT_CURRENCY['display']['amount']
]
);
@@ -319,7 +338,9 @@ protected function setUp(): void
'getCreditMemo',
'getBaseTaxAmount',
'getTaxAmount',
- 'getQty'
+ 'getQty',
+ 'getBaseRowTotal',
+ 'getRowTotal'
],
[
'getOrder'
@@ -333,7 +354,9 @@ protected function setUp(): void
'getBaseTaxAmount' => self::AMOUNT_CURRENCY['base']['taxAmount'],
'getPrice' => self::AMOUNT_CURRENCY['display']['amount'],
'getTaxAmount' => self::AMOUNT_CURRENCY['display']['taxAmount'],
- 'getQty' => 1
+ 'getQty' => 1,
+ 'getBaseRowTotal' => self::AMOUNT_CURRENCY['base']['amount'],
+ 'getRowTotal' => self::AMOUNT_CURRENCY['display']['amount']
]
);
@@ -423,14 +446,22 @@ public function testGetQuoteItemAmountCurrency(
$expectedResult->getCurrencyCode(),
$expectedResult->getDiscountAmount(),
$expectedResult->getTaxAmount(),
- $expectedResult->getAmountIncludingTax()
+ $expectedResult->getAmountIncludingTax(),
+ $expectedResult->getDiscountTaxCompensationAmount(),
+ $expectedResult->getAmountWithDiscount(),
+ $expectedResult->getCalculatedTaxPercentage(),
+ $expectedResult->getAmountIncludingTaxWithDiscount()
],
[
$result->getAmount(),
$result->getCurrencyCode(),
$result->getDiscountAmount(),
number_format($result->getTaxAmount(), 2, '.', ','),
- $result->getAmountIncludingTax()
+ $result->getAmountIncludingTax(),
+ $result->getDiscountTaxCompensationAmount(),
+ $result->getAmountWithDiscount(),
+ $result->getCalculatedTaxPercentage(),
+ $result->getAmountIncludingTaxWithDiscount()
]
);
} else {
@@ -700,7 +731,8 @@ public function amountCurrencyProvider(): array
self::AMOUNT_CURRENCY['base']['discountAmount'],
self::AMOUNT_CURRENCY['base']['taxAmount'],
self::AMOUNT_CURRENCY['base']['amountDue'],
- self::AMOUNT_CURRENCY['base']['amountIncludingTax']
+ self::AMOUNT_CURRENCY['base']['amountIncludingTax'],
+ self::AMOUNT_CURRENCY['base']['discountTaxCompensationAmount']
);
$adyenAmountCurrencyDisplay = new AdyenAmountCurrency(
@@ -709,7 +741,8 @@ public function amountCurrencyProvider(): array
self::AMOUNT_CURRENCY['display']['discountAmount'],
self::AMOUNT_CURRENCY['display']['taxAmount'],
self::AMOUNT_CURRENCY['display']['amountDue'],
- self::AMOUNT_CURRENCY['display']['amountIncludingTax']
+ self::AMOUNT_CURRENCY['display']['amountIncludingTax'],
+ self::AMOUNT_CURRENCY['display']['discountTaxCompensationAmount']
);
return array(
diff --git a/Test/Unit/Helper/ConfigTest.php b/Test/Unit/Helper/ConfigTest.php
index f1fde70dd..3b5d55a32 100644
--- a/Test/Unit/Helper/ConfigTest.php
+++ b/Test/Unit/Helper/ConfigTest.php
@@ -16,6 +16,7 @@
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\Serialize\SerializerInterface;
+use Magento\Store\Model\ScopeInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
class ConfigTest extends AbstractAdyenTestCase
@@ -51,4 +52,36 @@ public function testGetIsPaymentMethodsActive()
->willReturn('1');
$this->assertTrue($this->configHelper->getIsPaymentMethodsActive());
}
+
+ public function testGetAllowMultistoreTokensWithEnabledSetting()
+ {
+ $storeId = 1;
+ $expectedResult = true;
+ $path = 'payment/adyen_abstract/allow_multistore_tokens';
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('isSetFlag')
+ ->with($this->equalTo($path), $this->equalTo(ScopeInterface::SCOPE_STORE), $this->equalTo($storeId))
+ ->willReturn($expectedResult);
+
+ $result = $this->configHelper->getAllowMultistoreTokens($storeId);
+
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ public function testGetAllowMultistoreTokensWithDisabledSetting()
+ {
+ $storeId = 1;
+ $expectedResult = false;
+ $path = 'payment/adyen_abstract/allow_multistore_tokens';
+
+ $this->scopeConfigMock->expects($this->once())
+ ->method('isSetFlag')
+ ->with($this->equalTo($path), $this->equalTo(ScopeInterface::SCOPE_STORE), $this->equalTo($storeId))
+ ->willReturn($expectedResult);
+
+ $result = $this->configHelper->getAllowMultistoreTokens($storeId);
+
+ $this->assertEquals($expectedResult, $result);
+ }
}
diff --git a/Test/Unit/Helper/OpenInvoiceTest.php b/Test/Unit/Helper/OpenInvoiceTest.php
index 91dee3d42..5bfbcd04b 100644
--- a/Test/Unit/Helper/OpenInvoiceTest.php
+++ b/Test/Unit/Helper/OpenInvoiceTest.php
@@ -2,8 +2,21 @@
namespace Adyen\Payment\Test\Unit\Helper;
+use Adyen\Payment\Helper\ChargedCurrency;
+use Adyen\Payment\Helper\Config;
+use Adyen\Payment\Helper\Data;
+use Adyen\Payment\Model\AdyenAmountCurrency;
use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
use Adyen\Payment\Helper\OpenInvoice;
+use Magento\Catalog\Helper\Image;
+use Magento\Catalog\Model\Product;
+use Magento\Quote\Api\CartRepositoryInterface;
+use Magento\Quote\Model\Quote;
+use Magento\Quote\Model\Quote\Address;
+use Magento\Quote\Model\Quote\Item;
+use Magento\Sales\Model\Order;
+use Magento\Sales\Model\Order\Creditmemo;
+use Magento\Sales\Model\Order\Invoice;
class OpenInvoiceTest extends AbstractAdyenTestCase
{
@@ -16,93 +29,39 @@ class OpenInvoiceTest extends AbstractAdyenTestCase
private $cartMock;
private $itemMock;
private $productMock;
- private $paymentMock;
- private $invoiceCollectionMock;
private $invoiceMock;
private $orderItemMock;
private $invoiceItemMock;
- private $amountCurrencyMock;
private $creditmemoMock;
private $creditmemoItemMock;
+ private $shippingAddressMock;
+ private $shippingAmountCurrencyMock;
protected function setUp(): void
{
- $this->adyenHelperMock = $this->createMock(\Adyen\Payment\Helper\Data::class);
-
- $this->adyenHelperMock->method('formatAmount')
- ->will($this->returnCallback(function ($amount, $currency) {
- if ($amount === null) {
- return 0;
- }
- if ($amount == 450 && $currency == 'EUR') {
- return 4500;
- }
- if ($amount == 500.0 && $currency == 'EUR') {
- return 500; // Mocked formattedPriceExcludingTax value
- }
- if ($amount == 50.0 && $currency == 'EUR') {
- return 50; // Mocked formattedTaxAmount value
- }
- return (int)number_format($amount, 0, '', ''); // For any other calls, return this default value
- }));
-
-
- $this->cartRepositoryMock = $this->createMock(\Magento\Quote\Api\CartRepositoryInterface::class);
- $this->chargedCurrencyMock = $this->createMock(\Adyen\Payment\Helper\ChargedCurrency::class);
- $this->configHelperMock = $this->createMock(\Adyen\Payment\Helper\Config::class);
- $this->imageHelperMock = $this->createMock(\Magento\Catalog\Helper\Image::class);
- $this->orderMock = $this->createMock(\Magento\Sales\Model\Order::class);
- $this->cartMock = $this->createMock(\Magento\Quote\Model\Quote::class);
- $this->itemMock = $this->createMock(\Magento\Quote\Model\Quote\Item::class);
- $this->productMock = $this->createMock(\Magento\Catalog\Model\Product::class);
- $this->paymentMock = $this->createMock(\Magento\Sales\Model\Order\Payment::class);
- $this->invoiceCollectionMock = $this->createMock(\Magento\Sales\Model\ResourceModel\Order\Invoice\Collection::class);
- $this->invoiceMock = $this->createMock(\Magento\Sales\Model\Order\Invoice::class);
- $this->orderItemMock = $this->createMock(\Magento\Sales\Model\Order\Item::class);
- $this->invoiceItemMock = $this->createMock(\Magento\Sales\Model\Order\Invoice\Item::class);
- $this->creditmemoMock = $this->createMock(\Magento\Sales\Model\Order\Creditmemo::class);
- $this->creditmemoItemMock = $this->createMock(\Magento\Sales\Model\Order\Creditmemo\Item::class);
-
- $this->amountCurrencyMock = $this->createMock(\Adyen\Payment\Model\AdyenAmountCurrency::class);
- $this->amountCurrencyMock->method('getCurrencyCode')->willReturn('EUR');
- $this->chargedCurrencyMock->method('getOrderAmountCurrency')->willReturn($this->amountCurrencyMock);
-
- $itemAmountCurrencyMock = $this->createMock(\Adyen\Payment\Model\AdyenAmountCurrency::class);
- $itemAmountCurrencyMock->method('getAmount')->willReturn(4500);
- $itemAmountCurrencyMock->method('getAmountIncludingTax')->willReturn(4500);
- $itemAmountCurrencyMock->method('getDiscountAmount')->willReturn(0);
- $this->chargedCurrencyMock->method('getQuoteItemAmountCurrency')->willReturn($itemAmountCurrencyMock);
-
- $this->orderMock->method('getQuoteId')->willReturn('12345');
-
- $this->cartMock = $this->createMock(\Magento\Quote\Model\Quote::class);
-
- $shippingAddressMock = $this->createMock(\Magento\Quote\Model\Quote\Address::class);
-
- $shippingAddressMock->method('__call')->willReturnMap([
- ['getShippingAmount', [], 500.0],
- ['getShippingTaxAmount', [], 0.0],
- ['getShippingDescription', [], 'Flat Rate - Fixed'],
- ['getShippingAmountCurrency', [], 'EUR'],
- ['getShippingAmountCurrency', [], 'EUR'],
- ]);
-
- $shippingAmountCurrencyMock = $this->createMock(\Adyen\Payment\Model\AdyenAmountCurrency::class);
- $shippingAmountCurrencyMock->method('getAmount')->willReturn(500);
- $shippingAmountCurrencyMock->method('getAmountIncludingTax')->willReturn(500);
- $shippingAmountCurrencyMock->method('getTaxAmount')->willReturn(0);
- $this->chargedCurrencyMock->method('getQuoteShippingAmountCurrency')->willReturn($shippingAmountCurrencyMock);
- $this->chargedCurrencyMock->method('getInvoiceShippingAmountCurrency')->willReturn($shippingAmountCurrencyMock);
-
- $this->cartMock->method('getShippingAddress')->willReturn($shippingAddressMock);
-
- $this->cartRepositoryMock->method('get')->willReturn($this->cartMock);
-
+ # Constructor argument mocks
+ $this->adyenHelperMock = $this->createPartialMock(Data::class, []);
+ $this->cartRepositoryMock = $this->createMock(CartRepositoryInterface::class);
+ $this->chargedCurrencyMock = $this->createMock(ChargedCurrency::class);
+ $this->configHelperMock = $this->createMock(Config::class);
+ $this->imageHelperMock = $this->createMock(Image::class);
+
+ # Other mock property definitions
+ $this->orderMock = $this->createMock(Order::class);
+ $this->itemMock = $this->createMock(Item::class);
+ $this->productMock = $this->createMock(Product::class);
+ $this->invoiceMock = $this->createMock(Invoice::class);
+ $this->orderItemMock = $this->createMock(Order\Item::class);
+ $this->invoiceItemMock = $this->createMock(Invoice\Item::class);
+ $this->creditmemoMock = $this->createMock(Creditmemo::class);
+ $this->creditmemoItemMock = $this->createMock(Creditmemo\Item::class);
+ $this->cartMock = $this->createMock(Quote::class);
+ $this->shippingAddressMock = $this->createMock(Address::class);
+ $this->shippingAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class);
}
public function testGetOpenInvoiceDataFomOrder(): void
{
- // Arrange: Set up the object with the mocks
$openInvoice = new OpenInvoice(
$this->adyenHelperMock,
$this->cartRepositoryMock,
@@ -111,11 +70,23 @@ public function testGetOpenInvoiceDataFomOrder(): void
$this->imageHelperMock
);
- // Stub methods to return expected values
- $this->cartMock->method('getAllVisibleItems')->willReturn([$this->itemMock]);
+ $itemAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class);
+ $itemAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(100.00);
+ $itemAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(100.00);
+ $itemAmountCurrencyMock->method('getTaxAmount')->willReturn(0.00);
+ $itemAmountCurrencyMock->method('getCurrencyCode')->willReturn('EUR');
+
+ $this->chargedCurrencyMock->method('getQuoteItemAmountCurrency')->willReturn($itemAmountCurrencyMock);
+
$this->itemMock->method('getQty')->willReturn(1);
$this->itemMock->method('getProduct')->willReturn($this->productMock);
$this->itemMock->method('getName')->willReturn('Push It Messenger Bag');
+
+ $this->cartMock->method('getShippingAddress')->willReturn($this->shippingAddressMock);
+ $this->cartMock->method('getAllVisibleItems')->willReturn([$this->itemMock]);
+
+ $this->cartRepositoryMock->method('get')->willReturn($this->cartMock);
+
$this->productMock->method('getId')->willReturn('14');
$this->productMock->method('getUrlModel')->willReturn(new class {
@@ -131,29 +102,44 @@ public function getUrl()
$this->imageHelperMock->method('setImageFile')->willReturnSelf();
$this->imageHelperMock->method('getUrl')->willReturn('https://localhost.store/media/catalog/product/cache/3d0891988c4d57b25ce48fde378871d2/w/b/wb04-blue-0.jpg');
+ $this->shippingAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(500);
+ $this->shippingAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(550);
+ $this->shippingAmountCurrencyMock->method('getTaxAmount')->willReturn(50);
+ $this->shippingAmountCurrencyMock->method('getCalculatedTaxPercentage')->willReturn(10);
+
+ $this->chargedCurrencyMock->method('getQuoteShippingAmountCurrency')->willReturn($this->shippingAmountCurrencyMock);
+
+ $this->shippingAddressMock->method('__call')->willReturnMap([
+ ['getShippingAmount', [], 500.0],
+ ['getShippingTaxAmount', [], 0.0],
+ ['getShippingDescription', [], 'Flat Rate - Fixed'],
+ ['getShippingAmountCurrency', [], 'EUR'],
+ ['getShippingAmountCurrency', [], 'EUR'],
+ ]);
+
$expectedResult = [
'lineItems' => [
[
'id' => '14',
- 'amountExcludingTax' => 4500,
- 'amountIncludingTax' => 4500,
+ 'amountExcludingTax' => 10000,
+ 'amountIncludingTax' => 10000,
'taxAmount' => 0,
'description' => 'Push It Messenger Bag',
'quantity' => 1,
'taxPercentage' => 0,
'productUrl' => 'https://localhost.store/index.php/push-it-messenger-bag.html',
- 'imageUrl' => ''
+ 'imageUrl' => '',
],
[
'id' => 'shippingCost',
- 'amountExcludingTax' => 500,
- 'amountIncludingTax' => 500,
- 'taxAmount' => 0,
+ 'amountExcludingTax' => 50000,
+ 'amountIncludingTax' => 55000,
+ 'taxAmount' => 5000,
'description' => 'Flat Rate - Fixed',
'quantity' => 1,
- 'taxPercentage' => 0
- ],
- ],
+ 'taxPercentage' => 1000
+ ]
+ ]
];
// Act: Call the method with the mocked parameters
@@ -165,22 +151,12 @@ public function getUrl()
public function testGetOpenInvoiceDataForLastInvoice(): void
{
- $this->paymentMock->method('getOrder')->willReturn($this->orderMock);
- $this->orderMock->method('getInvoiceCollection')->willReturn($this->invoiceCollectionMock);
- $this->orderMock->method('getShippingDescription')->willReturn('Flat Rate - Fixed');
- $this->invoiceCollectionMock->method('getLastItem')->willReturn($this->invoiceMock);
- $this->invoiceMock->method('getItems')->willReturn([$this->invoiceItemMock]);
- $this->invoiceItemMock->method('getOrderItem')->willReturn($this->orderItemMock);
- $this->invoiceItemMock->method('getQty')->willReturn(1);
- $this->invoiceMock->method('getShippingAmount')->willReturn(100);
- $this->orderItemMock->method('getProduct')->willReturn($this->productMock);
+ $itemAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class);
+ $itemAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(100.00);
+ $itemAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(121.00);
+ $itemAmountCurrencyMock->method('getTaxAmount')->willReturn(21.00);
+
$this->productMock->method('getId')->willReturn('14');
- $itemAmountCurrencyMock = $this->createMock(\Adyen\Payment\Model\AdyenAmountCurrency::class);
- $this->chargedCurrencyMock->method('getInvoiceItemAmountCurrency')->willReturn($itemAmountCurrencyMock);
- $itemAmountCurrencyMock->method('getAmount')->willReturn(4500);
- $itemAmountCurrencyMock->method('getAmountIncludingTax')->willReturn(4500);
- $itemAmountCurrencyMock->method('getDiscountAmount')->willReturn(0);
- $this->orderItemMock->method('getName')->willReturn('Push It Messenger Bag');
$this->productMock->method('getUrlModel')->willReturn(new class {
public function getUrl()
{
@@ -188,67 +164,110 @@ public function getUrl()
}
});
- // Arrange: Set up the object with the mocks
- $openInvoice = new OpenInvoice($this->adyenHelperMock, $this->cartRepositoryMock, $this->chargedCurrencyMock, $this->configHelperMock, $this->imageHelperMock);
+ $this->orderItemMock->method('getProduct')->willReturn($this->productMock);
+ $this->orderItemMock->method('getName')->willReturn('Push It Messenger Bag');
+ $this->orderItemMock->method('getTaxPercent')->willReturn(21);
+
+ $this->invoiceItemMock->method('getOrderItem')->willReturn($this->orderItemMock);
+ $this->invoiceItemMock->method('getQty')->willReturn(1);
+
+ $this->invoiceMock->method('getItems')->willReturn([$this->invoiceItemMock]);
+ $this->invoiceMock->method('getShippingAmount')->willReturn(100);
+ $this->invoiceMock->method('getOrder')->willReturn($this->orderMock);
+
+ $this->chargedCurrencyMock->method('getInvoiceShippingAmountCurrency')->willReturn($this->shippingAmountCurrencyMock);
+ $this->chargedCurrencyMock->method('getInvoiceItemAmountCurrency')->willReturn($itemAmountCurrencyMock);
+
+ $this->orderMock->method('getShippingDescription')->willReturn('Flat Rate - Fixed');
+
+ $this->shippingAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(500);
+ $this->shippingAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(550);
+ $this->shippingAmountCurrencyMock->method('getTaxAmount')->willReturn(50);
+ $this->shippingAmountCurrencyMock->method('getCalculatedTaxPercentage')->willReturn(10);
+
+ $openInvoice = new OpenInvoice(
+ $this->adyenHelperMock,
+ $this->cartRepositoryMock,
+ $this->chargedCurrencyMock,
+ $this->configHelperMock,
+ $this->imageHelperMock
+ );
$expectedResult = [
'lineItems' => [
[
'id' => '14',
- 'amountExcludingTax' => 4500,
- 'amountIncludingTax' => 4500,
- 'taxAmount' => 0,
+ 'amountExcludingTax' => 10000,
+ 'amountIncludingTax' => 12100,
+ 'taxAmount' => 2100,
'description' => 'Push It Messenger Bag',
'quantity' => 1,
- 'taxPercentage' => 0,
+ 'taxPercentage' => 2100,
'productUrl' => 'https://localhost.store/index.php/push-it-messenger-bag.html',
- 'imageUrl' => ''
+ 'imageUrl' => '',
],
[
'id' => 'shippingCost',
- 'amountExcludingTax' => 500,
- 'amountIncludingTax' => 500,
- 'taxAmount' => 0,
+ 'amountExcludingTax' => 50000,
+ 'amountIncludingTax' => 55000,
+ 'taxAmount' => 5000,
'description' => 'Flat Rate - Fixed',
'quantity' => 1,
- 'taxPercentage' => 0
- ],
+ 'taxPercentage' => 1000
+ ]
]
];
- $result = $openInvoice->getOpenInvoiceDataForLastInvoice($this->paymentMock);
+ $result = $openInvoice->getOpenInvoiceDataForInvoice($this->invoiceMock);
+
$this->assertEquals($expectedResult, $result);
}
public function testGetOpenInvoiceDataForCreditMemo(): void
{
- $this->paymentMock->method('getOrder')->willReturn($this->orderMock);
- $this->paymentMock->method('getCreditMemo')->willReturn($this->creditmemoMock);
$this->creditmemoMock->method('getItems')->willReturn([$this->creditmemoItemMock]);
+ $this->creditmemoMock->method('getShippingAmount')->willReturn(50);
+ $this->creditmemoMock->method('getOrder')->willReturn($this->orderMock);
+
$this->creditmemoItemMock->method('getOrderItem')->willReturn($this->orderItemMock);
$this->creditmemoItemMock->method('getQty')->willReturn(1);
+
+ $this->orderItemMock->method('getName')->willReturn('Push It Messenger Bag');
$this->orderItemMock->method('getProduct')->willReturn($this->productMock);
- $itemAmountCurrencyMock = $this->createMock(\Adyen\Payment\Model\AdyenAmountCurrency::class);
+ $this->orderItemMock->method('getTaxPercent')->willReturn(0);
+
+ $itemAmountCurrencyMock = $this->createMock(AdyenAmountCurrency::class);
+ $itemAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(45);
+ $itemAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(45);
+ $itemAmountCurrencyMock->method('getTaxAmount')->willReturn(0);
+ $itemAmountCurrencyMock->method('getCurrencyCode')->willReturn('EUR');
- $itemAmountCurrencyMock->method('getAmount')->willReturn(4500);
- $itemAmountCurrencyMock->method('getAmountIncludingTax')->willReturn(4500);
- $itemAmountCurrencyMock->method('getDiscountAmount')->willReturn(10);
$this->chargedCurrencyMock->method('getCreditMemoItemAmountCurrency')->willReturn($itemAmountCurrencyMock);
- $this->chargedCurrencyMock->method('getCreditMemoShippingAmountCurrency')->willReturn($itemAmountCurrencyMock);
- $shippingAddressMock = $this->createMock(\Magento\Quote\Model\Quote\Address::class);
- $shippingAddressMock->method('__call')->willReturnMap([['getShippingDiscountAmount', [], 10.0],]);
- $this->orderMock->method('getShippingAddress')->willReturn($shippingAddressMock);
+
+ $this->shippingAmountCurrencyMock->method('getAmountWithDiscount')->willReturn(500);
+ $this->shippingAmountCurrencyMock->method('getAmountIncludingTaxWithDiscount')->willReturn(550);
+ $this->shippingAmountCurrencyMock->method('getTaxAmount')->willReturn(50);
+ $this->shippingAmountCurrencyMock->method('getCalculatedTaxPercentage')->willReturn(10);
+
+ $this->chargedCurrencyMock->method('getCreditMemoShippingAmountCurrency')->willReturn($this->shippingAmountCurrencyMock);
+
$this->orderMock->method('getShippingDescription')->willReturn('Flat Rate - Fixed');
+
$this->productMock->method('getId')->willReturn('14');
- $this->orderItemMock->method('getName')->willReturn('Push It Messenger Bag');
$this->productMock->method('getUrlModel')->willReturn(new class {
public function getUrl()
{
return 'https://localhost.store/index.php/push-it-messenger-bag.html';
}
});
- // Arrange: Set up the object with the mocks
- $openInvoice = new OpenInvoice($this->adyenHelperMock, $this->cartRepositoryMock, $this->chargedCurrencyMock, $this->configHelperMock, $this->imageHelperMock);
+
+ $openInvoice = new OpenInvoice(
+ $this->adyenHelperMock,
+ $this->cartRepositoryMock,
+ $this->chargedCurrencyMock,
+ $this->configHelperMock,
+ $this->imageHelperMock
+ );
$expectedResult = [
'lineItems' => [
@@ -263,28 +282,20 @@ public function getUrl()
'productUrl' => 'https://localhost.store/index.php/push-it-messenger-bag.html',
'imageUrl' => ''
],
- [
- 'id' => 'Discount',
- 'amountExcludingTax' => -20,
- 'amountIncludingTax' => -20,
- 'taxAmount' => 0,
- 'description' => __('Discount'),
- 'quantity' => 1,
- 'taxPercentage' => 0
- ],
[
'id' => 'shippingCost',
- 'amountExcludingTax' => 4500,
- 'amountIncludingTax' => 4500,
- 'taxAmount' => 0,
+ 'amountExcludingTax' => 50000,
+ 'amountIncludingTax' => 55000,
+ 'taxAmount' => 5000,
'description' => 'Flat Rate - Fixed',
'quantity' => 1,
- 'taxPercentage' => 0
- ],
+ 'taxPercentage' => 1000
+ ]
]
];
- $result = $openInvoice->getOpenInvoiceDataForCreditMemo($this->paymentMock);
+ $result = $openInvoice->getOpenInvoiceDataForCreditMemo($this->creditmemoMock);
+
$this->assertEquals($expectedResult, $result);
}
}
diff --git a/Test/Unit/Helper/PaymentMethodsTest.php b/Test/Unit/Helper/PaymentMethodsTest.php
index 2220072df..6794023ae 100644
--- a/Test/Unit/Helper/PaymentMethodsTest.php
+++ b/Test/Unit/Helper/PaymentMethodsTest.php
@@ -39,6 +39,8 @@
use Magento\Payment\Helper\Data as MagentoDataHelper;
use Magento\Payment\Model\MethodInterface;
use Magento\Quote\Api\CartRepositoryInterface;
+use Magento\Vault\Api\PaymentTokenRepositoryInterface;
+use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Quote\Model\Quote\Address;
use Magento\Sales\Model\Order;
use Magento\Quote\Model\Quote;
@@ -68,6 +70,8 @@ class PaymentMethodsTest extends AbstractAdyenTestCase
private ManualCapture $manualCaptureMock;
private SerializerInterface $serializerMock;
private AdyenDataHelper $adyenDataHelperMock;
+ private PaymentTokenRepositoryInterface $paymentTokenRepository;
+ private SearchCriteriaBuilder $searchCriteriaBuilder;
protected function setUp(): void
{
@@ -93,6 +97,8 @@ protected function setUp(): void
$this->manualCaptureMock = $this->createMock(ManualCapture::class);
$this->serializerMock = $this->createMock(SerializerInterface::class);
$this->adyenDataHelperMock = $this->createMock(AdyenDataHelper::class);
+ $this->paymentTokenRepository = $this->createMock(PaymentTokenRepositoryInterface::class);
+ $this->searchCriteriaBuilder = $this->createMock(SearchCriteriaBuilder::class);
$this->amountCurrencyMock = $this->createMock(AdyenAmountCurrency::class);
$this->methodMock = $this->createMock(MethodInterface::class);
$this->orderMock = $this->createMock(Order::class);
@@ -130,6 +136,8 @@ protected function setUp(): void
$this->manualCaptureMock,
$this->serializerMock,
$this->adyenDataHelperMock,
+ $this->paymentTokenRepository,
+ $this->searchCriteriaBuilder
);
}
@@ -220,6 +228,70 @@ public function testTogglePaymentMethodsActivation()
);
}
+ public function testFetchPaymentMethodsWithNoPaymentMethodsInResponse()
+ {
+ $country = 'NL';
+ $shopperLocale = 'nl_NL';
+ $expectedResult = '[]';
+
+ $storeMock = $this->createMock(Store::class);
+ $storeMock->method('getId')->willReturn(1);
+
+ $quoteMock = $this->getMockBuilder(Quote::class)
+ ->disableOriginalConstructor()
+ ->setMethods(['getStore'])
+ ->getMock();
+
+ $quoteMock->method('getStore')->willReturn($storeMock);
+ $quoteMock->setCustomerId(123);
+
+ $reflectionClass = new \ReflectionClass(get_class($this->paymentMethodsHelper));
+ $quoteProperty = $reflectionClass->getProperty('quote');
+ $quoteProperty->setAccessible(true);
+ $quoteProperty->setValue($this->paymentMethodsHelper, $quoteMock);
+
+ $method = $reflectionClass->getMethod('fetchPaymentMethods');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($this->paymentMethodsHelper, [$country, $shopperLocale]);
+
+ $this->assertEquals($expectedResult, $result);
+ }
+
+ public function testFilterStoredPaymentMethods()
+ {
+ $allowMultistoreTokens = false;
+ $customerId = 1;
+ $responseData = [
+ 'storedPaymentMethods' => [
+ ['id' => '123', 'name' => 'Visa'],
+ ['id' => '456', 'name' => 'Mastercard']
+ ]
+ ];
+ $expectedResult = [
+ 'storedPaymentMethods' => [
+ ['id' => '123', 'name' => 'Visa']
+ ]
+ ];
+
+ $paymentTokenMock = $this->createMock(\Magento\Vault\Api\Data\PaymentTokenInterface::class);
+ $paymentTokenMock->method('getGatewayToken')->willReturn('123');
+
+ $searchCriteriaMock = $this->createMock(\Magento\Framework\Api\SearchCriteriaInterface::class);
+ $this->searchCriteriaBuilder->method('addFilter')->willReturnSelf();
+ $this->searchCriteriaBuilder->method('create')->willReturn($searchCriteriaMock);
+ $this->searchCriteriaBuilder->method('addFilter')->willReturnSelf();
+ $this->searchCriteriaBuilder->method('create')->willReturn('searchCriteria');
+ $this->paymentTokenRepository->method('getList')->willReturn(new \Magento\Framework\DataObject(['items' => [$paymentTokenMock]]));
+
+ $reflectionClass = new \ReflectionClass(get_class($this->paymentMethodsHelper));
+ $method = $reflectionClass->getMethod('filterStoredPaymentMethods');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($this->paymentMethodsHelper, [$allowMultistoreTokens, $responseData, $customerId]);
+
+ $this->assertEquals($expectedResult, $result);
+ }
//Successfully retrieve payment methods for a valid quote ID. getPaymentMethods
public function testSuccessfullyRetrievePaymentMethodsForValidQuoteId()
{
@@ -1275,5 +1347,4 @@ public function testShowLogosPaymentMethods()
$this->assertArrayHasKey('icon', $result['visa']);
$this->assertArrayHasKey('isOpenInvoice', $result['visa']);
}
-
}
diff --git a/Test/Unit/Helper/WebhookTest.php b/Test/Unit/Helper/WebhookTest.php
index b94d27f3a..fc832031d 100644
--- a/Test/Unit/Helper/WebhookTest.php
+++ b/Test/Unit/Helper/WebhookTest.php
@@ -18,6 +18,8 @@
use Adyen\Payment\Helper\Webhook\WebhookHandlerFactory;
use Adyen\Payment\Logger\AdyenLogger;
use ReflectionMethod;
+use Adyen\Payment\Exception\AdyenWebhookException;
+
class WebhookTest extends AbstractAdyenTestCase
{
@@ -40,7 +42,7 @@ public function testProcessNotificationWithInvalidMerchantReference()
public function testProcessNotificationWithOrderNotFound()
{
- $merchantReference = 'TestMerchant'; // Replace with a merchant reference that does not exist
+ $merchantReference = 'TestMerchant';
$notification = $this->createMock(Notification::class);
$notification->method('getMerchantReference')->willReturn($merchantReference);
@@ -53,7 +55,6 @@ public function testProcessNotificationWithOrderNotFound()
$result = $webhookHandler->processNotification($notification);
- // Assertions for the unsuccessful processing
$this->assertFalse($result);
}
@@ -74,7 +75,6 @@ public function testProcessNotificationForInvalidDataException()
$notification->method('getPspreference')->willReturn('ABCD1234GHJK5678');
$notification->method('getPaymentMethod')->willReturn('ADYEN_CC');
- // Mocking Order and other dependencies
$payment = $this->createMock(Payment::class);
$order = $this->createMock(Order::class);
$order->method('getState')->willReturn(Order::STATE_NEW);
@@ -93,10 +93,8 @@ public function testProcessNotificationForInvalidDataException()
$logger = $this->createMock(AdyenLogger::class);
$logger->method('getOrderContext')->with($order);
- // Mock the WebhookHandlerFactory and WebhookHandler
$webhookHandlerFactory = $this->createMock(WebhookHandlerFactory::class);
- // Partially mock the Webhook class
$webhookHandler = $this->getMockBuilder(Webhook::class)
->setConstructorArgs([
$this->createMock(Data::class),
@@ -126,7 +124,6 @@ public function testProcessNotificationForInvalidDataException()
public function testAddNotificationDetailsHistoryComment()
{
- // Mock necessary dependencies
$orderMock = $this->getMockBuilder(Order::class)
->disableOriginalConstructor()
->getMock();
@@ -144,19 +141,15 @@ public function testAddNotificationDetailsHistoryComment()
public function testGetTransitionState()
{
- // Mock necessary dependencies
$notificationMock = $this->getMockBuilder(Notification::class)
->disableOriginalConstructor()
->getMock();
- // Create an instance of your class
$webhook = $this->createWebhook(null, null, null, null, null, null, null, null, null);
- // Use reflection to make the private method accessible
$method = new ReflectionMethod(Webhook::class, 'getTransitionState');
$method->setAccessible(true);
- // Set up expectations for the mocked objects
$notificationMock->expects($this->once())
->method('getEventCode')
->willReturn('AUTHORISATION');
@@ -167,10 +160,8 @@ public function testGetTransitionState()
$orderState = Order::STATE_NEW;
- // Call the private method
$result = $method->invokeArgs($webhook, [$notificationMock, $orderState]);
- // Assertions based on your logic
$this->assertNotEquals(
'STATE_NEW',
$result,
@@ -205,7 +196,6 @@ public function testUpdateAdyenAttributes()
$orderRepositoryMock = $this->createMock(OrderRepository::class);
$orderRepositoryMock->method('get')->willReturn($orderMock);
- // Create an instance of your class
$webhook = $this->createWebhook(
null,
$serializerMock,
@@ -218,7 +208,6 @@ public function testUpdateAdyenAttributes()
$orderRepositoryMock
);
- // Set up expectations for the mocked objects
$notificationMock->expects($this->once())
->method('getEventCode')
->willReturn(Notification::AUTHORISATION);
@@ -264,7 +253,6 @@ public function testProcessNotificationWithSuccess()
$orderHelper = $this->createMock(OrderHelper::class);
$orderHelper->method('getOrderByIncrementId')->willReturn($order);
- // Create a mock for the payment
$payment = $this->createMock(Payment::class);
$mockWebhookHandlerFactory = $this->createMock(WebhookHandlerFactory::class);
$webhookHandlerInterface = $this->createMock(WebhookHandlerInterface::class);
@@ -291,6 +279,280 @@ public function testProcessNotificationWithSuccess()
$this->assertTrue($result);
}
+ public function testProcessNotificationWithAdyenWebhookException()
+ {
+ $notification = $this->createMock(Notification::class);
+ $notification->method('getMerchantReference')->willReturn('TestMerchant');
+ $notification->method('getEventCode')->willReturn('AUTHORISATION : FALSE');
+ $notification->method('getEntityId')->willReturn('1234');
+ $notification->method('getPspreference')->willReturn('ABCD1234GHJK5678');
+ $notification->method('getPaymentMethod')->willReturn('ADYEN_CC');
+
+ $payment = $this->createMock(Payment::class);
+ $order = $this->createMock(Order::class);
+ $order->method('getState')->willReturn(Order::STATE_NEW);
+ $order->method('getIncrementId')->willReturn(123);
+ $order->method('getId')->willReturn(123);
+ $order->method('getStatus')->willReturn('processing');
+ $order->method('getPayment')->willReturn($payment);
+
+ $orderHelper = $this->createMock(OrderHelper::class);
+ $orderHelper->method('getOrderByIncrementId')->willReturn($order);
+
+ $payment->expects($this->once())
+ ->method('setAdditionalInformation')
+ ->with('payment_method', $notification->getPaymentMethod());
+
+ $webhookHandlerInterfaceMock = $this->createMock(WebhookHandlerInterface::class);
+ $webhookHandlerInterfaceMock->method('handleWebhook')->willThrowException(new AdyenWebhookException(
+ new \Magento\Framework\Phrase("Test Adyen webhook exception"
+ )));
+
+ $webhookHandlerFactory = $this->createMock(WebhookHandlerFactory::class);
+ $webhookHandlerFactory->method('create')
+ ->willReturn($webhookHandlerInterfaceMock);
+
+ $logger = $this->createMock(AdyenLogger::class);
+ $logger->method('getOrderContext')->with($order);
+
+ $webhookHandler = $this->getMockBuilder(Webhook::class)
+ ->setConstructorArgs([
+ $this->createMock(Data::class),
+ $this->createMock(SerializerInterface::class),
+ $this->createMock(TimezoneInterface::class),
+ $this->createMock(ConfigHelper::class),
+ $this->createMock(ChargedCurrency::class),
+ $logger,
+ $webhookHandlerFactory,
+ $orderHelper,
+ $this->createMock(OrderRepository::class)
+ ])
+ ->onlyMethods([
+ 'updateNotification',
+ 'addNotificationDetailsHistoryComment',
+ 'updateAdyenAttributes',
+ 'getCurrentState',
+ 'getTransitionState',
+ 'handleNotificationError'
+ ])
+ ->getMock();
+
+ $result = $webhookHandler->processNotification($notification);
+
+ $this->assertFalse($result);
+ }
+
+ public function testProcessNotificationWithGeneralException()
+ {
+ $notification = $this->createMock(Notification::class);
+ $notification->method('getMerchantReference')->willReturn('TestMerchant');
+ $notification->method('getEventCode')->willReturn('AUTHORISATION : FALSE');
+ $notification->method('getEntityId')->willReturn('1234');
+ $notification->method('getPspreference')->willReturn('ABCD1234GHJK5678');
+ $notification->method('getPaymentMethod')->willReturn('ADYEN_CC');
+
+ $payment = $this->createMock(Payment::class);
+ $order = $this->createMock(Order::class);
+ $order->method('getState')->willReturn(Order::STATE_NEW);
+ $order->method('getIncrementId')->willReturn(123);
+ $order->method('getId')->willReturn(123);
+ $order->method('getStatus')->willReturn('processing');
+ $order->method('getPayment')->willReturn($payment);
+
+ $orderHelper = $this->createMock(OrderHelper::class);
+ $orderHelper->method('getOrderByIncrementId')->willReturn($order);
+
+ $payment->expects($this->once())
+ ->method('setAdditionalInformation')
+ ->with('payment_method', $notification->getPaymentMethod());
+
+ $webhookHandlerInterfaceMock = $this->createMock(WebhookHandlerInterface::class);
+ $webhookHandlerInterfaceMock->method('handleWebhook')->willThrowException(new \Exception(
+ new \Magento\Framework\Phrase("Test generic exception"
+ )));
+
+ $webhookHandlerFactory = $this->createMock(WebhookHandlerFactory::class);
+ $webhookHandlerFactory->method('create')
+ ->willReturn($webhookHandlerInterfaceMock);
+
+ $logger = $this->createMock(AdyenLogger::class);
+ $logger->method('getOrderContext')->with($order);
+
+ $webhookHandler = $this->getMockBuilder(Webhook::class)
+ ->setConstructorArgs([
+ $this->createMock(Data::class),
+ $this->createMock(SerializerInterface::class),
+ $this->createMock(TimezoneInterface::class),
+ $this->createMock(ConfigHelper::class),
+ $this->createMock(ChargedCurrency::class),
+ $logger,
+ $webhookHandlerFactory,
+ $orderHelper,
+ $this->createMock(OrderRepository::class)
+ ])
+ ->onlyMethods([
+ 'updateNotification',
+ 'addNotificationDetailsHistoryComment',
+ 'updateAdyenAttributes',
+ 'getCurrentState',
+ 'getTransitionState',
+ 'handleNotificationError'
+ ])
+ ->getMock();
+
+ $result = $webhookHandler->processNotification($notification);
+
+ $this->assertFalse($result);
+ }
+
+ public function testAddNotificationDetailsHistoryCommentWithFullRefund()
+ {
+ $orderMock = $this->getMockBuilder(Order::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $notificationMock = $this->getMockBuilder(Notification::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $orderAmountCurrencyObject = new class {
+ public function getAmount() {
+ return 100;
+ }
+ public function getCurrencyCode() {
+ return 'EUR';
+ }
+ };
+
+ $chargedCurrencyMock = $this->createMock(ChargedCurrency::class);
+ $chargedCurrencyMock->method('getOrderAmountCurrency')
+ ->willReturn($orderAmountCurrencyObject);
+
+ $adyenHelperMock = $this->createMock(Data::class);
+ $adyenHelperMock->method('formatAmount')
+ ->willReturn(100);
+
+ $webhook = $this->createWebhook(
+ $adyenHelperMock,
+ null,
+ null,
+ null,
+ $chargedCurrencyMock,
+ null,
+ null,
+ null,
+ null
+ );
+
+ $notificationMock->method('getEventCode')
+ ->willReturn(Notification::REFUND);
+ $notificationMock->method('getAmountValue')
+ ->willReturn(100);
+ $notificationMock->method('isSuccessful')
+ ->willReturn(true);
+
+ $orderMock->expects($this->once())
+ ->method('setData')
+ ->with(
+ 'adyen_notification_event_code',
+ $this->stringContains('REFUND : TRUE')
+ );
+
+ $reflection = new \ReflectionClass(get_class($webhook));
+ $method = $reflection->getMethod('addNotificationDetailsHistoryComment');
+ $method->setAccessible(true);
+
+ $result = $method->invokeArgs($webhook, [$orderMock, $notificationMock]);
+
+ $this->assertInstanceOf(Order::class, $result);
+ }
+
+ public function testAddNotificationDetailsHistoryCommentWithPendingEventCode()
+ {
+ $orderMock = $this->getMockBuilder(Order::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $notificationMock = $this->getMockBuilder(Notification::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configHelperMock = $this->createMock(ConfigHelper::class);
+ $adyenHelperMock = $this->createMock(Data::class);
+ $chargedCurrencyMock = $this->createMock(ChargedCurrency::class);
+
+ $webhook = $this->createWebhook(
+ $adyenHelperMock,
+ null,
+ null,
+ $configHelperMock,
+ $chargedCurrencyMock,
+ null,
+ null,
+ null,
+ null
+ );
+
+ $notificationMock->method('getEventCode')
+ ->willReturn(Notification::PENDING);
+ $notificationMock->method('getPspreference')
+ ->willReturn('some_psp_reference');
+ $orderMock->method('getStoreId')
+ ->willReturn(1);
+
+ $configHelperMock->method('getConfigData')
+ ->with('pending_status', 'adyen_abstract', 1)
+ ->willReturn('pending_status_value');
+
+ $reflection = new \ReflectionClass(get_class($webhook));
+ $method = $reflection->getMethod('addNotificationDetailsHistoryComment');
+ $method->setAccessible(true);
+
+ $orderMock->expects($this->once())
+ ->method('addStatusHistoryComment')
+ ->with(
+ $this->anything(),
+ 'pending_status_value'
+ );
+
+ $result = $method->invokeArgs($webhook, [$orderMock, $notificationMock]);
+
+ $this->assertInstanceOf(Order::class, $result);
+ }
+
+ public function testUpdateOrderPaymentWithAdyenAttributes()
+ {
+ $paymentMock = $this->getMockBuilder(Order\Payment::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $notificationMock = $this->getMockBuilder(Notification::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $webhook = $this->createWebhook(null,null,null,null,null,null,null,null,null);
+
+ $additionalData = [
+ 'avsResult' => 'avs_result_value',
+ 'cvcResult' => 'cvc_result_value',
+ ];
+
+ $notificationMock->method('getPspreference')->willReturn('pspReference');
+ $notificationMock->method('getReason')->willReturn('card summary reason');
+
+ $reflection = new \ReflectionClass(get_class($webhook));
+ $method = $reflection->getMethod('updateOrderPaymentWithAdyenAttributes');
+ $method->setAccessible(true);
+
+ $paymentMock->expects($this->exactly(4))
+ ->method('setAdditionalInformation')
+ ->withConsecutive(
+ ['adyen_avs_result', 'avs_result_value'],
+ ['adyen_cvc_result', 'cvc_result_value'],
+ ['pspReference', 'pspReference'],
+ ['adyen_ratepay_descriptor', $this->anything()]
+ );
+
+ $method->invokeArgs($webhook, [$paymentMock, $notificationMock, $additionalData]);
+ }
+
+
protected function createWebhook(
$mockAdyenHelper = null,
$mockSerializer = null,
diff --git a/Test/Unit/Model/Api/AdyenStateDataTest.php b/Test/Unit/Model/Api/AdyenStateDataTest.php
new file mode 100644
index 000000000..ef8bddffb
--- /dev/null
+++ b/Test/Unit/Model/Api/AdyenStateDataTest.php
@@ -0,0 +1,59 @@
+
+ */
+
+namespace Adyen\Payment\Test\Unit\Model\Api;
+
+use Adyen\Payment\Helper\StateData;
+use Adyen\Payment\Model\Api\AdyenStateData;
+use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class AdyenStateDataTest extends AbstractAdyenTestCase
+{
+ private $objectManager;
+ private $stateDataHelperMock;
+ private $adyenStateDataModel;
+
+ protected function setUp(): void
+ {
+ $this->objectManager = new ObjectManager($this);
+
+ $this->stateDataHelperMock = $this->createMock(StateData::class);
+
+ $this->adyenStateDataModel = $this->objectManager->getObject(AdyenStateData::class, [
+ 'stateDataHelper' => $this->stateDataHelperMock
+ ]);
+ }
+
+ public function testSaveSuccessful()
+ {
+ $stateData = '{"stateData":"dummyData"}';
+ $cartId = 100;
+
+ $stateDataMock = $this->createMock(\Adyen\Payment\Model\StateData::class);
+ $stateDataMock->method('getEntityId')->willReturn(1);
+
+ $this->stateDataHelperMock->expects($this->once())
+ ->method('saveStateData')
+ ->willReturn($stateDataMock);
+
+ $this->adyenStateDataModel->save($stateData, $cartId);
+ }
+
+ public function testRemoveSuccessful()
+ {
+ $stateDataId = 1;
+ $cartId = 100;
+
+ $this->stateDataHelperMock->expects($this->once())->method('removeStateData');
+ $this->adyenStateDataModel->remove($stateDataId, $cartId);
+ }
+}
diff --git a/Test/Unit/Model/Api/GuestAdyenStateDataTest.php b/Test/Unit/Model/Api/GuestAdyenStateDataTest.php
index d2a9110a9..b440dc058 100644
--- a/Test/Unit/Model/Api/GuestAdyenStateDataTest.php
+++ b/Test/Unit/Model/Api/GuestAdyenStateDataTest.php
@@ -51,8 +51,11 @@ public function testSaveSuccessful()
$stateData = '{"stateData":"dummyData"}';
$cartId = 'ABC123456789';
+ $stateDataMock = $this->createMock(\Adyen\Payment\Model\StateData::class);
+ $stateDataMock->method('getEntityId')->willReturn(1);
+
$this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock);
- $this->stateDataHelperMock->expects($this->once())->method('saveStateData');
+ $this->stateDataHelperMock->expects($this->once())->method('saveStateData')->willReturn($stateDataMock);
$this->guestAdyenStateDataModel->save($stateData, $cartId);
}
@@ -64,7 +67,6 @@ public function testRemoveSuccessful()
$this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock);
$this->stateDataHelperMock->expects($this->once())->method('removeStateData');
-
$this->guestAdyenStateDataModel->remove($stateDataId, $cartId);
}
diff --git a/Test/Unit/Model/Resolver/GetAdyenPaymentMethodsBalanceTest.php b/Test/Unit/Model/Resolver/GetAdyenPaymentMethodsBalanceTest.php
new file mode 100644
index 000000000..51002e804
--- /dev/null
+++ b/Test/Unit/Model/Resolver/GetAdyenPaymentMethodsBalanceTest.php
@@ -0,0 +1,84 @@
+
+ */
+namespace Adyen\Payment\Test\Model\Resolver;
+
+use Adyen\Payment\Model\Api\AdyenPaymentMethodsBalance;
+use Adyen\Payment\Model\Resolver\GetAdyenPaymentMethodsBalance;
+use Magento\Catalog\Model\Layer\ContextInterface;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use PHPUnit\Framework\TestCase;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Magento\Framework\GraphQl\Query;
+
+class GetAdyenPaymentMethodsBalanceTest extends TestCase
+{
+ private $balanceMock;
+ private $contextMock;
+ private $fieldMock;
+ private $infoMock;
+ private $getAdyenPaymentMethodsBalance;
+
+ protected function setUp(): void
+ {
+ $this->balanceMock = $this->createMock(AdyenPaymentMethodsBalance::class);
+ $this->contextMock = $this->createMock(ContextInterface::class);
+ $this->fieldMock = $this->createMock(Field::class);
+ $this->infoMock = $this->createMock(ResolveInfo::class);
+
+ $this->getAdyenPaymentMethodsBalance = new GetAdyenPaymentMethodsBalance(
+ $this->balanceMock
+ );
+ }
+
+ public function testWithMissingPayloadArgument()
+ {
+ $this->expectException(GraphQlInputException::class);
+ $this->expectExceptionMessage('Required parameter "payload" is missing');
+
+ $this->getAdyenPaymentMethodsBalance->resolve($this->fieldMock, $this->contextMock, $this->infoMock, [], []);
+ }
+
+ public function testWithValidPayloadArgument()
+ {
+ $payload = '{\"paymentMethod\":{\"type\":\"giftcard\",\"brand\":\"svs\",\"encryptedCardNumber\":\"abc…\",\"encryptedSecurityCode\":\"xyz…\"},\"amount\":{\"currency\":\"EUR\",\"value\":1000}}';
+ $args = ['payload' => $payload];
+ $expectedBalanceResponse = '10';
+
+ $this->balanceMock->expects($this->once())
+ ->method('getBalance')
+ ->with($payload)
+ ->willReturn($expectedBalanceResponse);
+
+ $result = $this->getAdyenPaymentMethodsBalance->resolve($this->fieldMock, $this->contextMock, $this->infoMock, [], $args);
+
+ $this->assertEquals(['balanceResponse' => $expectedBalanceResponse], $result);
+ }
+
+ public function testWithFailingApiCall()
+ {
+ $this->expectException(GraphQlAdyenException::class);
+
+ $args = [
+ 'payload' => "{}"
+ ];
+
+ $this->balanceMock->method('getBalance')->willThrowException(new \Exception());
+
+ $this->getAdyenPaymentMethodsBalance->resolve($this->fieldMock, $this->contextMock, $this->infoMock, [], $args);
+ }
+}
+
+
+
+
+
diff --git a/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php b/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php
new file mode 100644
index 000000000..3f491ec4a
--- /dev/null
+++ b/Test/Unit/Model/Resolver/GetAdyenRedeemedGiftcardsTest.php
@@ -0,0 +1,133 @@
+
+ */
+namespace Adyen\Payment\Test\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Helper\GiftcardPayment;
+use Adyen\Payment\Model\Resolver\GetAdyenRedeemedGiftcards;
+use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
+use Exception;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Query\Resolver\ContextInterface;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Framework\Serialize\Serializer\Json;
+use Magento\Quote\Model\QuoteIdMask;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+
+class GetAdyenRedeemedGiftcardsTest extends AbstractAdyenTestCase
+{
+ private $giftcardPaymentMock;
+ private $jsonSerializerMock;
+ private $quoteIdMaskFactoryMock;
+ private $quoteIdMaskMock;
+ private $getAdyenRedeemedGiftcards;
+ private $fieldMock;
+ private $contextMock;
+ private $resolveInfoMock;
+
+ protected function setUp(): void
+ {
+ $this->giftcardPaymentMock = $this->createMock(GiftcardPayment::class);
+ $this->jsonSerializerMock = $this->createMock(Json::class);
+ $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(
+ QuoteIdMaskFactory::class,
+ ['create']
+ );
+ $this->quoteIdMaskMock = $this->createMock(QuoteIdMask::class);
+ $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock);
+
+ $this->fieldMock = $this->createMock(Field::class);
+ $this->contextMock = $this->createMock(ContextInterface::class);
+ $this->resolveInfoMock = $this->createMock(ResolveInfo::class);
+
+ $this->getAdyenRedeemedGiftcards = new GetAdyenRedeemedGiftcards(
+ $this->giftcardPaymentMock,
+ $this->jsonSerializerMock,
+ $this->quoteIdMaskFactoryMock
+ );
+ }
+
+ public function testSuccessfulRetrievalOfRedeemedGiftCardDetailsWithValidCartId()
+ {
+ $cartId = 'test_cart_id';
+ $quoteId = 0;
+ $args = ['cartId' => $cartId];
+ $redeemedGiftcardsJson = '{"redeemedGiftcards": [], "remainingAmount": 100, "totalDiscount": 10}';
+ $redeemedGiftcardsData = json_decode($redeemedGiftcardsJson, true);
+
+ $this->quoteIdMaskMock->expects($this->once())
+ ->method('load')
+ ->with($cartId, 'masked_id')
+ ->willReturn($this->quoteIdMaskMock);
+
+ $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']);
+ $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock);
+ $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1);
+
+ $this->giftcardPaymentMock->expects($this->once())
+ ->method('fetchRedeemedGiftcards')
+ ->with($quoteId)
+ ->willReturn($redeemedGiftcardsJson);
+
+ $this->jsonSerializerMock->expects($this->once())
+ ->method('unserialize')
+ ->with($redeemedGiftcardsJson)
+ ->willReturn($redeemedGiftcardsData);
+
+ $result = $this->getAdyenRedeemedGiftcards->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, [], $args);
+
+ $this->assertEquals(
+ [
+ 'redeemedGiftcards' => $redeemedGiftcardsData['redeemedGiftcards'],
+ 'remainingAmount' => $redeemedGiftcardsData['remainingAmount'],
+ 'totalDiscount' => $redeemedGiftcardsData['totalDiscount']
+ ],
+ $result
+ );
+ }
+
+ public function testFailedRetrievalOfRedeemedGiftCards()
+ {
+ $this->expectException(GraphQlAdyenException::class);
+
+ $cartId = 'test_cart_id';
+ $args = ['cartId' => $cartId];
+
+ $this->quoteIdMaskMock->expects($this->once())
+ ->method('load')
+ ->with($cartId, 'masked_id')
+ ->willReturn($this->quoteIdMaskMock);
+
+ $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']);
+ $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock);
+ $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1);
+
+ $this->giftcardPaymentMock->method('fetchRedeemedGiftcards')
+ ->willThrowException(new Exception());
+
+ $this->getAdyenRedeemedGiftcards->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, [], $args);
+ }
+
+ public function testFailedRetrievalOfRedeemedGiftCardsWithNullCartId()
+ {
+ $this->expectException(GraphQlInputException::class);
+
+ $args = ['cartId' => ""];
+
+ $this->getAdyenRedeemedGiftcards->resolve($this->fieldMock, $this->contextMock, $this->resolveInfoMock, [], $args);
+ }
+}
+
+
+
+
+
diff --git a/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php
new file mode 100644
index 000000000..d4aa02201
--- /dev/null
+++ b/Test/Unit/Model/Resolver/RemoveAdyenStateDataTest.php
@@ -0,0 +1,175 @@
+
+ */
+namespace Adyen\Payment\Test\Model\Resolver;
+
+use Adyen\Payment\Exception\GraphQlAdyenException;
+use Adyen\Payment\Model\Api\AdyenStateData;
+use Adyen\Payment\Model\Resolver\RemoveAdyenStateData;
+use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
+use Exception;
+use Magento\Catalog\Model\Layer\ContextInterface;
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Quote\Model\QuoteIdMask;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+
+class RemoveAdyenStateDataTest extends AbstractAdyenTestCase
+{
+ private $removeAdyenStateDataResolver;
+ private $adyenStateDataHelperMock;
+ private $quoteIdMaskFactoryMock;
+ private $quoteIdMaskMock;
+ private $fieldMock;
+ private $contextMock;
+ private $infoMock;
+
+ public function setUp(): void
+ {
+ $this->objectManager = new ObjectManager($this);
+
+ $this->adyenStateDataHelperMock = $this->createMock(AdyenStateData::class);
+ $this->fieldMock = $this->createMock(Field::class);
+ $this->contextMock = $this->createMock(ContextInterface::class);
+ $this->infoMock = $this->createMock(ResolveInfo::class);
+
+ $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']);
+ $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock);
+ $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1);
+
+ $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, [
+ 'create'
+ ]);
+ $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock);
+
+ $this->removeAdyenStateDataResolver = $this->objectManager->getObject(RemoveAdyenStateData::class, [
+ 'adyenStateData' => $this->adyenStateDataHelperMock,
+ 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock
+ ]);
+ }
+
+ public function testResolve()
+ {
+ $stateDataId = 1;
+
+ $args = [
+ 'stateDataId' => $stateDataId,
+ 'cartId' => 1
+ ];
+
+ $this->adyenStateDataHelperMock->expects($this->once())->method('remove')->willReturn(true);
+
+ $result = $this->removeAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+
+ $this->assertArrayHasKey('stateDataId', $result);
+ $this->assertEquals($stateDataId, $result['stateDataId']);
+ }
+
+ public function testResolveWithLocalizedException()
+ {
+ $this->expectException(LocalizedException::class);
+
+ $stateDataId = 1;
+
+ $args = [
+ 'stateDataId' => $stateDataId,
+ 'cartId' => 1
+ ];
+
+ $this->adyenStateDataHelperMock->expects($this->once())->method('remove')->willReturn(false);
+
+ $result = $this->removeAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+ }
+
+ public function testResolveWithGraphQLAdyenException()
+ {
+ $this->expectException(GraphQlAdyenException::class);
+
+ $args = [
+ 'stateDataId' => 1,
+ 'cartId' => 1
+ ];
+
+ $this->adyenStateDataHelperMock->expects($this->once())
+ ->method('remove')
+ ->willThrowException(new Exception());
+
+ $this->removeAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+ }
+
+ /**
+ * @dataProvider inputFailureDataProvider
+ */
+ public function testResolveFailureWithWrongInput($stateDataId, $cartId)
+ {
+ $this->expectException(GraphQlInputException::class);
+
+ $args = [
+ 'stateDataId' => $stateDataId,
+ 'cartId' => $cartId
+ ];
+
+ $this->removeAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+ }
+
+ /**
+ * Data provider for testResolveFailureWithWrongInput test method
+ *
+ * @return array
+ */
+ private static function inputFailureDataProvider(): array
+ {
+ return [
+ [
+ 'stateDataId' => '',
+ 'cartId' => 1
+ ],
+ [
+ 'stateDataId' => 1,
+ 'cartId' => ''
+ ],
+ [
+ 'stateDataId' => '',
+ 'cartId' => ''
+ ],
+ [
+ 'stateDataId' => null,
+ 'cartId' => 1
+ ]
+ ];
+ }
+}
diff --git a/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php
new file mode 100644
index 000000000..871e291f5
--- /dev/null
+++ b/Test/Unit/Model/Resolver/SaveAdyenStateDataTest.php
@@ -0,0 +1,152 @@
+
+ */
+namespace Adyen\Payment\Test\Model\Resolver;
+
+use Adyen\Payment\Model\Api\AdyenStateData;
+use Adyen\Payment\Model\Resolver\SaveAdyenStateData;
+use Adyen\Payment\Test\Unit\AbstractAdyenTestCase;
+use Exception;
+use Magento\Catalog\Model\Layer\ContextInterface;
+use Magento\Framework\GraphQl\Config\Element\Field;
+use Magento\Framework\GraphQl\Exception\GraphQlInputException;
+use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Quote\Model\QuoteIdMask;
+use Magento\Quote\Model\QuoteIdMaskFactory;
+
+class SaveAdyenStateDataTest extends AbstractAdyenTestCase
+{
+ private $saveAdyenStateDataResolver;
+ private $adyenStateDataHelperMock;
+ private $quoteIdMaskFactoryMock;
+ private $quoteIdMaskMock;
+ private $fieldMock;
+ private $contextMock;
+ private $infoMock;
+
+ public function setUp(): void
+ {
+ $this->objectManager = new ObjectManager($this);
+
+ $this->adyenStateDataHelperMock = $this->createMock(AdyenStateData::class);
+ $this->fieldMock = $this->createMock(Field::class);
+ $this->contextMock = $this->createMock(ContextInterface::class);
+ $this->infoMock = $this->createMock(ResolveInfo::class);
+
+ $this->quoteIdMaskMock = $this->createGeneratedMock(QuoteIdMask::class, ['load', 'getQuoteId']);
+ $this->quoteIdMaskMock->method('load')->willReturn($this->quoteIdMaskMock);
+ $this->quoteIdMaskMock->method('getQuoteId')->willReturn(1);
+
+ $this->quoteIdMaskFactoryMock = $this->createGeneratedMock(QuoteIdMaskFactory::class, [
+ 'create'
+ ]);
+ $this->quoteIdMaskFactoryMock->method('create')->willReturn($this->quoteIdMaskMock);
+
+ $this->saveAdyenStateDataResolver = $this->objectManager->getObject(SaveAdyenStateData::class, [
+ 'adyenStateData' => $this->adyenStateDataHelperMock,
+ 'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock
+ ]);
+ }
+
+ public function testResolve()
+ {
+ $stateData = "{\"paymentMethod\":{\"type\":\"giftcard\",\"brand\":\"svs\",\"encryptedCardNumber\":\"abd...\",\"encryptedSecurityCode\":\"xyz...\"},\"giftcard\":{\"balance\":{\"currency\":\"EUR\",\"value\":5000},\"title\":\"SVS\"}}";
+ $stateDataId = 1;
+
+ $args = [
+ 'stateData' => $stateData,
+ 'cartId' => 1
+ ];
+
+ $this->adyenStateDataHelperMock->expects($this->once())->method('save')->willReturn($stateDataId);
+
+ $result = $this->saveAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+
+ $this->assertArrayHasKey('stateDataId', $result);
+ $this->assertEquals($stateDataId, $result['stateDataId']);
+ }
+
+ public function testResolveFailedWithException()
+ {
+ $this->expectException(Exception::class);
+
+ $args = [
+ 'stateData' => "{}",
+ 'cartId' => 1
+ ];
+
+ $this->adyenStateDataHelperMock->expects($this->once())
+ ->method('save')
+ ->willThrowException(new Exception());
+
+ $result = $this->saveAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+ }
+
+ /**
+ * @dataProvider inputFailureDataProvider
+ */
+ public function testResolveFailureWithWrongInput($stateData, $cartId)
+ {
+ $this->expectException(GraphQlInputException::class);
+
+ $args = [
+ 'stateData' => $stateData,
+ 'cartId' => $cartId
+ ];
+
+ $this->saveAdyenStateDataResolver->resolve(
+ $this->fieldMock,
+ $this->contextMock,
+ $this->infoMock,
+ null,
+ $args
+ );
+ }
+
+ /**
+ * Data provider for testResolveFailureWithWrongInput test method
+ *
+ * @return array
+ */
+ private static function inputFailureDataProvider(): array
+ {
+ return [
+ [
+ 'stateData' => '',
+ 'cartId' => 1
+ ],
+ [
+ 'stateData' => "{}",
+ 'cartId' => ''
+ ],
+ [
+ 'stateData' => '',
+ 'cartId' => ''
+ ],
+ [
+ 'stateData' => null,
+ 'cartId' => 1
+ ]
+ ];
+ }
+}
diff --git a/Test/Unit/Setup/RecurringDataTest.php b/Test/Unit/Setup/RecurringDataTest.php
index 142f21b58..51f9a45de 100644
--- a/Test/Unit/Setup/RecurringDataTest.php
+++ b/Test/Unit/Setup/RecurringDataTest.php
@@ -18,7 +18,7 @@
use Adyen\Payment\Helper\PaymentMethodsFactory;
use Adyen\Payment\Helper\PaymentMethods;
-class RecurringTest extends AbstractAdyenTestCase
+class RecurringDataTest extends AbstractAdyenTestCase
{
private RecurringData $recurringData;
diff --git a/composer.json b/composer.json
index 489bd0082..51b7683dd 100755
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "adyen/module-payment",
"description": "Official Magento2 Plugin to connect to Payment Service Provider Adyen.",
"type": "magento2-module",
- "version": "9.3.0",
+ "version": "9.4.0",
"license": "MIT",
"repositories": [
{
diff --git a/etc/adminhtml/system/adyen_tokenization.xml b/etc/adminhtml/system/adyen_tokenization.xml
index 80a32185f..c178682c8 100755
--- a/etc/adminhtml/system/adyen_tokenization.xml
+++ b/etc/adminhtml/system/adyen_tokenization.xml
@@ -28,5 +28,12 @@
{\n public readonly _id = `${this.constructor['type']}-${uuid()}`;\n public props: P;\n public state;\n protected static defaultProps = {};\n public _node;\n public _component;\n public eventEmitter = new EventEmitter();\n protected readonly _parentInstance: Core;\n\n protected resources: Resources;\n\n protected constructor(props: P) {\n this.props = this.formatProps({ ...this.constructor['defaultProps'], setStatusAutomatically: true, ...props });\n this._parentInstance = this.props._parentInstance;\n this._node = null;\n this.state = {};\n this.resources = this.props.modules ? this.props.modules.resources : undefined;\n }\n\n /**\n * Executed during creation of any payment element.\n * Gives a chance to any paymentMethod to format the props we're receiving.\n */\n protected formatProps(props: P) {\n return props;\n }\n\n /**\n * Executed on the `data` getter.\n * Returns the component data necessary for the /payments request\n *\n * TODO: Replace 'any' by type PaymentMethodData extends BaseElement implements IUIElement {\n protected componentRef: any;\n public elementRef: UIElement;\n\n constructor(props: P) {\n super(props);\n this.submit = this.submit.bind(this);\n this.setState = this.setState.bind(this);\n this.onValid = this.onValid.bind(this);\n this.onComplete = this.onComplete.bind(this);\n this.onSubmit = this.onSubmit.bind(this);\n this.handleAction = this.handleAction.bind(this);\n this.handleOrder = this.handleOrder.bind(this);\n this.handleResponse = this.handleResponse.bind(this);\n this.setElementStatus = this.setElementStatus.bind(this);\n\n this.elementRef = (props && props.elementRef) || this;\n }\n\n public setState(newState: object): void {\n this.state = { ...this.state, ...newState };\n this.onChange();\n }\n\n protected onChange(): object {\n const isValid = this.isValid;\n const state = { data: this.data, errors: this.state.errors, valid: this.state.valid, isValid };\n if (this.props.onChange) this.props.onChange(state, this.elementRef);\n if (isValid) this.onValid();\n\n return state;\n }\n\n private onSubmit(): void {\n //TODO: refactor this, instant payment methods are part of Dropin logic not UIElement\n if (this.props.isInstantPayment) {\n const dropinElementRef = this.elementRef as DropinElement;\n dropinElementRef.closeActivePaymentMethod();\n }\n\n if (this.props.setStatusAutomatically) {\n this.setElementStatus('loading');\n }\n\n if (this.props.onSubmit) {\n // Classic flow\n this.props.onSubmit({ data: this.data, isValid: this.isValid }, this.elementRef);\n } else if (this._parentInstance.session) {\n // Session flow\n // wrap beforeSubmit callback in a promise\n const beforeSubmitEvent = this.props.beforeSubmit\n ? new Promise((resolve, reject) =>\n this.props.beforeSubmit(this.data, this.elementRef, {\n resolve,\n reject\n })\n )\n : Promise.resolve(this.data);\n\n beforeSubmitEvent\n .then(data => this.submitPayment(data))\n .catch(() => {\n // set state as ready to submit if the merchant cancels the action\n this.elementRef.setStatus('ready');\n });\n } else {\n this.handleError(new AdyenCheckoutError('IMPLEMENTATION_ERROR', 'Could not submit the payment'));\n }\n }\n\n private onValid() {\n const state = { data: this.data };\n if (this.props.onValid) this.props.onValid(state, this.elementRef);\n return state;\n }\n\n onComplete(state): void {\n if (this.props.onComplete) this.props.onComplete(state, this.elementRef);\n }\n\n /**\n * Submit payment method data. If the form is not valid, it will trigger validation.\n */\n public submit(): void {\n if (!this.isValid) {\n this.showValidation();\n return;\n }\n\n this.onSubmit();\n }\n\n public showValidation(): this {\n if (this.componentRef && this.componentRef.showValidation) this.componentRef.showValidation();\n return this;\n }\n\n public setElementStatus(status: UIElementStatus, props?: any): this {\n this.elementRef?.setStatus(status, props);\n return this;\n }\n\n public setStatus(status: UIElementStatus, props?): this {\n if (this.componentRef?.setStatus) {\n this.componentRef.setStatus(status, props);\n }\n return this;\n }\n\n private submitPayment(data): Promise