From c666d46b55cc708769f659449b83ddadf43c5e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Fri, 25 Oct 2024 18:11:47 +0200 Subject: [PATCH 1/3] MAG2-319 - Added PayPal V2 integration --- Api/Data/PayPalResponseInterface.php | 58 +++++ Api/PayPalInterface.php | 38 +++ Block/Paypal/Base.php | 154 ++++++++++++ Block/Paypal/ExpressButton.php | 87 +------ Block/Paypal/ExpressButtonV2.php | 224 ++++++++++++++++++ Controller/Onepage/Review.php | 1 + Helper/Api.php | 11 +- Helper/Payment.php | 14 +- .../Request/Genericpayment/PayPalExpress.php | 55 ++++- .../Request/Genericpayment/UpdateOrder.php | 74 ++++++ Model/Methods/AliPay.php | 9 +- Model/Methods/AmazonPay.php | 9 +- Model/Methods/AmazonPayV2.php | 9 +- Model/Methods/ApplePay.php | 9 +- Model/Methods/BaseMethod.php | 7 + Model/Methods/Paydirekt.php | 9 +- Model/Methods/PayoneMethod.php | 10 + Model/Methods/Paypal.php | 9 +- Model/Methods/PaypalV2.php | 108 +++++++++ Model/Methods/WeChatPay.php | 9 +- Model/PayoneConfig.php | 1 + Model/Paypal/ReturnHandler.php | 41 +++- Model/Source/PayPalButtonColor.php | 66 ++++++ Model/Source/PayPalButtonShape.php | 58 +++++ Observer/AddPaypalExpressButtons.php | 16 +- Service/V1/Data/PayPalResponse.php | 75 ++++++ Service/V1/PayPal.php | 135 +++++++++++ Test/Unit/Block/Paypal/ExpressButtonTest.php | 15 ++ .../Unit/Block/Paypal/ExpressButtonV2Test.php | 142 +++++++++++ Test/Unit/Helper/PaymentTest.php | 54 ++++- .../Genericpayment/PayPalExpressTest.php | 4 +- .../Genericpayment/UpdateOrderTest.php | 97 ++++++++ Test/Unit/Model/Methods/PaypalV2Test.php | 111 +++++++++ Test/Unit/Model/Paypal/ReturnHandlerTest.php | 29 ++- .../Model/Source/PayPalButtonColorTest.php | 52 ++++ .../Model/Source/PayPalButtonShapeTest.php | 52 ++++ .../Observer/AddPaypalExpressButtonTest.php | 2 + .../Service/V1/Data/PayPalResponseTest.php | 84 +++++++ Test/Unit/Service/V1/PayPalTest.php | 143 +++++++++++ etc/adminhtml/system.xml | 6 + etc/adminhtml/system/payone_paypalv2.xml | 92 +++++++ etc/config.xml | 17 ++ etc/di.xml | 2 + etc/payment.xml | 3 + etc/webapi.xml | 17 ++ i18n/de_DE.csv | 1 + view/frontend/layout/checkout_index_index.xml | 3 + view/frontend/layout/default.xml | 3 + .../templates/paypal/express_buttonv2.phtml | 110 +++++++++ view/frontend/web/css/payone.css | 4 + .../web/js/action/startpaypalexpress.js | 55 +++++ .../method-renderer/paypalv2-method.js | 41 ++++ .../web/js/view/payment/payone-payments.js | 4 + .../web/template/payment/paypalv2.html | 89 +++++++ 54 files changed, 2404 insertions(+), 124 deletions(-) create mode 100644 Api/Data/PayPalResponseInterface.php create mode 100644 Api/PayPalInterface.php create mode 100644 Block/Paypal/Base.php create mode 100644 Block/Paypal/ExpressButtonV2.php create mode 100644 Model/Api/Request/Genericpayment/UpdateOrder.php create mode 100644 Model/Methods/PaypalV2.php create mode 100644 Model/Source/PayPalButtonColor.php create mode 100644 Model/Source/PayPalButtonShape.php create mode 100644 Service/V1/Data/PayPalResponse.php create mode 100644 Service/V1/PayPal.php create mode 100644 Test/Unit/Block/Paypal/ExpressButtonV2Test.php create mode 100644 Test/Unit/Model/Api/Request/Genericpayment/UpdateOrderTest.php create mode 100644 Test/Unit/Model/Methods/PaypalV2Test.php create mode 100644 Test/Unit/Model/Source/PayPalButtonColorTest.php create mode 100644 Test/Unit/Model/Source/PayPalButtonShapeTest.php create mode 100644 Test/Unit/Service/V1/Data/PayPalResponseTest.php create mode 100644 Test/Unit/Service/V1/PayPalTest.php create mode 100644 etc/adminhtml/system/payone_paypalv2.xml create mode 100644 view/frontend/templates/paypal/express_buttonv2.phtml create mode 100644 view/frontend/web/js/action/startpaypalexpress.js create mode 100644 view/frontend/web/js/view/payment/method-renderer/paypalv2-method.js create mode 100644 view/frontend/web/template/payment/paypalv2.html diff --git a/Api/Data/PayPalResponseInterface.php b/Api/Data/PayPalResponseInterface.php new file mode 100644 index 00000000..d1a142cf --- /dev/null +++ b/Api/Data/PayPalResponseInterface.php @@ -0,0 +1,58 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Api\Data; + +interface PayPalResponseInterface +{ + /** + * Returns the PAYONE workorder id + * + * @return string + */ + public function getWorkorderId(); + + /** + * Returns if the call was successful + * + * @return bool + */ + public function getSuccess(); + + /** + * Return paypal order id + * + * @return string + */ + public function getOrderId(); + + /** + * Returns errormessage + * + * @return string + */ + public function getErrormessage(); +} diff --git a/Api/PayPalInterface.php b/Api/PayPalInterface.php new file mode 100644 index 00000000..2a319795 --- /dev/null +++ b/Api/PayPalInterface.php @@ -0,0 +1,38 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Api; + +interface PayPalInterface +{ + /** + * Trigger PayPal Express v2 process + * + * @param string $cartId + * @return \Payone\Core\Service\V1\Data\PayPalResponse + */ + public function startPayPalExpress($cartId); +} diff --git a/Block/Paypal/Base.php b/Block/Paypal/Base.php new file mode 100644 index 00000000..ab1081bc --- /dev/null +++ b/Block/Paypal/Base.php @@ -0,0 +1,154 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Block\Paypal; + +use Magento\Framework\View\Element\Template; + +class Base extends Template implements \Magento\Catalog\Block\ShortcutInterface +{ + /** + * Shortcut alias + * + * @var string + */ + protected $alias; + + /** + * @var string + */ + protected $name; + + /** + * @var \Magento\Framework\Locale\ResolverInterface + */ + protected $localeResolver; + + /** + * Locale codes supported by misc images (marks, shortcuts etc) + * + * @var array + */ + protected $aSupportedLocales = [ + 'de_DE', + 'en_AU', + 'en_GB', + 'en_US', + 'es_ES', + 'es_XC', + 'fr_FR', + 'fr_XC', + 'it_IT', + 'ja_JP', + 'nl_NL', + 'pl_PL', + 'zh_CN', + 'zh_XC', + ]; + + /** + * Constructor + * + * @param \Magento\Framework\View\Element\Template\Context $context + * @param \Magento\Framework\Locale\ResolverInterface $localeResolver + * @param array $data + */ + public function __construct( + \Magento\Framework\View\Element\Template\Context $context, + \Magento\Framework\Locale\ResolverInterface $localeResolver, + array $data = [] + ) { + parent::__construct($context, $data); + $this->localeResolver = $localeResolver; + $this->setTemplate($this->sTemplate); + } + + /** + * Get shortcut alias + * + * @return string + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param string $sName + * @return void + */ + public function setName($sName) + { + $this->name = $sName; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + + /** + * @return string + */ + public function getButtonIdent() + { + $sButtonIdent = "payone-paypal-button-container"; + if (strpos($this->getName(), "checkout.cart.shortcut.buttons") !== false) { + $sButtonIdent = "payone-paypal-button-basket"; + } elseif (strpos($this->getName(), "shortcutbuttons") !== false) { + $sButtonIdent = "payone-paypal-button-minibasket"; + } + return $sButtonIdent; + } + + /** + * Check whether specified locale code is supported. Fallback to en_US + * + * @param string $sLocale + * @return string + */ + protected function getSupportedLocaleCode($sLocale = null) + { + if (!$sLocale || !in_array($sLocale, $this->aSupportedLocales)) { + return 'en_US'; + } + return $sLocale; + } + + /** + * @return string + */ + protected function getLocale() + { + $sCurrentLocal = $this->localeResolver->getLocale(); + $sPayPalLocal = $this->getSupportedLocaleCode($sCurrentLocal); + return $sPayPalLocal; + } +} \ No newline at end of file diff --git a/Block/Paypal/ExpressButton.php b/Block/Paypal/ExpressButton.php index 516969f0..93a6311d 100644 --- a/Block/Paypal/ExpressButton.php +++ b/Block/Paypal/ExpressButton.php @@ -31,7 +31,7 @@ /** * Block class for the PayPal Express button */ -class ExpressButton extends Template implements \Magento\Catalog\Block\ShortcutInterface +class ExpressButton extends Base { /** * Shortcut alias @@ -41,72 +41,9 @@ class ExpressButton extends Template implements \Magento\Catalog\Block\ShortcutI protected $alias = 'payone.block.paypal.expressbutton'; /** - * Is mandate link to be shown? - * - * @var bool|null - */ - protected $blShowMandateLink = null; - - /** - * Instruction notes - * - * @var string|bool - */ - protected $sInstructionNotes = false; - - /** - * @var \Magento\Framework\Locale\ResolverInterface - */ - protected $localeResolver; - - /** - * Locale codes supported by misc images (marks, shortcuts etc) - * - * @var array - */ - protected $aSupportedLocales = [ - 'de_DE', - 'en_AU', - 'en_GB', - 'en_US', - 'es_ES', - 'es_XC', - 'fr_FR', - 'fr_XC', - 'it_IT', - 'ja_JP', - 'nl_NL', - 'pl_PL', - 'zh_CN', - 'zh_XC', - ]; - - /** - * Constructor - * - * @param \Magento\Framework\View\Element\Template\Context $context - * @param \Magento\Framework\Locale\ResolverInterface $localeResolver - * @param array $data - */ - public function __construct( - \Magento\Framework\View\Element\Template\Context $context, - \Magento\Framework\Locale\ResolverInterface $localeResolver, - array $data = [] - ) { - parent::__construct($context, $data); - $this->localeResolver = $localeResolver; - $this->setTemplate('paypal/express_button.phtml'); - } - - /** - * Get shortcut alias - * - * @return string + * @var string */ - public function getAlias() - { - return $this->alias; - } + protected $sTemplate = 'paypal/express_button.phtml'; /** * URL to paypal start controller @@ -118,20 +55,6 @@ public function getPayPalExpressLink() return $this->getUrl('payone/paypal/express'); } - /** - * Check whether specified locale code is supported. Fallback to en_US - * - * @param string $sLocale - * @return string - */ - protected function getSupportedLocaleCode($sLocale = null) - { - if (!$sLocale || !in_array($sLocale, $this->aSupportedLocales)) { - return 'en_US'; - } - return $sLocale; - } - /** * Return URL to PayPal Express logo * @@ -139,8 +62,6 @@ protected function getSupportedLocaleCode($sLocale = null) */ public function getPayPalExpressLogoUrl() { - $sCurrentLocal = $this->localeResolver->getLocale(); - $sPayPalLocal = $this->getSupportedLocaleCode($sCurrentLocal); - return sprintf('https://www.paypal.com/%s/i/btn/btn_xpressCheckout.gif', $sPayPalLocal); + return sprintf('https://www.paypal.com/%s/i/btn/btn_xpressCheckout.gif', $this->getLocale()); } } diff --git a/Block/Paypal/ExpressButtonV2.php b/Block/Paypal/ExpressButtonV2.php new file mode 100644 index 00000000..10b1ae8f --- /dev/null +++ b/Block/Paypal/ExpressButtonV2.php @@ -0,0 +1,224 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Block\Paypal; + +use Magento\Framework\View\Element\Template; +use Payone\Core\Model\Methods\PayoneMethod; +use Payone\Core\Model\PayoneConfig; + +/** + * Block class for the PayPal Express V2 button + */ +class ExpressButtonV2 extends Base +{ + /** + * Shortcut alias + * + * @var string + */ + protected $alias = 'payone.block.paypal.expressbuttonv2'; + + /** + * @var string + */ + protected $sTemplate = 'paypal/express_buttonv2.phtml'; + + /** + * PAYONE payment helper + * + * @var \Payone\Core\Helper\Payment + */ + protected $paymentHelper; + + /** + * PAYONE API helper + * + * @var \Payone\Core\Helper\Api + */ + protected $apiHelper; + + /** + * Payment helper object + * + * @var \Magento\Payment\Helper\Data + */ + protected $dataHelper; + + /** + * @var \Magento\Checkout\Model\Session; + */ + protected $checkoutSession; + + /** + * @var PayoneMethod + */ + protected $methodInstance = null; + + /** + * Constructor + * + * @param \Magento\Framework\View\Element\Template\Context $context + * @param \Magento\Framework\Locale\ResolverInterface $localeResolver + * @param \Payone\Core\Helper\Payment $paymentHelper + * @param \Payone\Core\Helper\Api $apiHelper + * @param \Magento\Payment\Helper\Data $dataHelper + * @param \Magento\Checkout\Model\Session $checkoutSession + * @param array $data + */ + public function __construct( + \Magento\Framework\View\Element\Template\Context $context, + \Magento\Framework\Locale\ResolverInterface $localeResolver, + \Payone\Core\Helper\Payment $paymentHelper, + \Payone\Core\Helper\Api $apiHelper, + \Magento\Payment\Helper\Data $dataHelper, + \Magento\Checkout\Model\Session $checkoutSession, + array $data = [] + ) { + parent::__construct($context, $localeResolver, $data); + $this->paymentHelper = $paymentHelper; + $this->apiHelper = $apiHelper; + $this->dataHelper = $dataHelper; + $this->checkoutSession = $checkoutSession; + } + + /** + * @return PayoneMethod + */ + public function getMethodInstance() + { + if ($this->methodInstance === null) { + $this->methodInstance = $this->dataHelper->getMethodInstance(PayoneConfig::METHOD_PAYPALV2); + } + return $this->methodInstance; + } + + /** + * @return string + */ + public function getStoreCode() + { + return $this->checkoutSession->getQuote()->getStore()->getCode(); + } + + /** + * @return int|mixed + */ + public function getQuoteId() + { + return $this->checkoutSession->getQuote()->getId(); + } + + /** + * @return string + */ + public function getButtonColor() + { + return $this->getMethodInstance()->getCustomConfigParam('button_color'); + } + + /** + * @return string + */ + public function getButtonShape() + { + return $this->getMethodInstance()->getCustomConfigParam('button_shape'); + } + + /** + * @return bool + */ + protected function showBNPLButton() + { + $blReturn = false; + if ($this->paymentHelper->getConfigParam('show_bnpl_button', PayoneConfig::METHOD_PAYPALV2, 'payone_payment')) { + $blReturn = true; + } + return $blReturn; + } + + /** + * @return string + */ + protected function getIntent() + { + $oMethodInstance = $this->getMethodInstance(); + + $sIntent = "authorize"; // authorize = preauthorize + if ($oMethodInstance && $oMethodInstance->getAuthorizationMode() == PayoneConfig::REQUEST_TYPE_AUTHORIZATION) { + $sIntent = "capture"; // capture = authorize + } + return $sIntent; + } + + /** + * @return string + */ + protected function getCurrency() + { + return $this->apiHelper->getCurrencyFromQuote($this->checkoutSession->getQuote()); + } + + /** + * @return string + */ + protected function getMerchantId() + { + $sMerchantId = "3QK84QGGJE5HW"; // Default for testmode (fixed) + + $oMethodInstance = $this->getMethodInstance(); + if ($oMethodInstance && $oMethodInstance->getOperationMode() == 'live') { + $sMerchantId = $oMethodInstance->getCustomConfigParam('merchant_id'); // Get from config for live + } + return $sMerchantId; + } + + /** + * @return string + */ + protected function getClientId() + { + $sClientId = "AUn5n-4qxBUkdzQBv6f8yd8F4AWdEvV6nLzbAifDILhKGCjOS62qQLiKbUbpIKH_O2Z3OL8CvX7ucZfh"; // Default for testmode (fixed) + + $oMethodInstance = $this->getMethodInstance(); + if ($oMethodInstance && $oMethodInstance->getOperationMode() == 'live') { + $sClientId = "AVNBj3ypjSFZ8jE7shhaY2mVydsWsSrjmHk0qJxmgJoWgHESqyoG35jLOhH3GzgEPHmw7dMFnspH6vim"; // Livemode (fixed) + } + return $sClientId; + } + + /** + * @return string + */ + public function getJavascriptUrl() + { + $sUrl = "https://www.paypal.com/sdk/js?client-id=".$this->getClientId()."&merchant-id=".$this->getMerchantId()."¤cy=".$this->getCurrency()."&intent=".$this->getIntent()."&locale=".$this->getLocale()."&commit=true&vault=false&disable-funding=card,sepa,bancontact"; + if ($this->showBNPLButton() === true) { + $sUrl .= "&enable-funding=paylater"; + } + return $sUrl; + } +} diff --git a/Controller/Onepage/Review.php b/Controller/Onepage/Review.php index d74e7ec7..494bf149 100644 --- a/Controller/Onepage/Review.php +++ b/Controller/Onepage/Review.php @@ -69,6 +69,7 @@ class Review extends \Magento\Framework\App\Action\Action */ protected $availableReviewMethods = [ PayoneConfig::METHOD_PAYPAL, + PayoneConfig::METHOD_PAYPALV2, PayoneConfig::METHOD_PAYDIREKT, PayoneConfig::METHOD_AMAZONPAYV2, ]; diff --git a/Helper/Api.php b/Helper/Api.php index 32699363..2f8432d5 100644 --- a/Helper/Api.php +++ b/Helper/Api.php @@ -283,9 +283,16 @@ public function addPayoneOrderData(SalesOrder $oOrder, $aRequest, $aResponse) */ public function isInvoiceDataNeeded(PayoneMethod $oPayment, $aPositions = null) { + $oInfoInstance = false; + try { + $oInfoInstance = $oPayment->getInfoInstance(); // using getInfoInstance when it is not set will throw an exception + } catch (\Exception $exc) { + // do nothing + } + $sStoreCode = null; - if ($oPayment->getInfoInstance()->getOrder()) { - $sStoreCode = $oPayment->getInfoInstance()->getOrder()->getStore()->getCode(); + if ($oInfoInstance && $oInfoInstance->getOrder()) { + $sStoreCode = $oInfoInstance->getOrder()->getStore()->getCode(); } if ($oPayment instanceof RatepayBase && is_array($aPositions) && empty($aPositions)) { // empty array means products and shipping costs were deselected diff --git a/Helper/Payment.php b/Helper/Payment.php index bec510df..91f3d0ec 100644 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -44,6 +44,7 @@ class Payment extends \Payone\Core\Helper\Base PayoneConfig::METHOD_CREDITCARD, PayoneConfig::METHOD_DEBIT, PayoneConfig::METHOD_PAYPAL, + PayoneConfig::METHOD_PAYPALV2, PayoneConfig::METHOD_CASH_ON_DELIVERY, PayoneConfig::METHOD_ADVANCE_PAYMENT, PayoneConfig::METHOD_INVOICE, @@ -96,6 +97,7 @@ class Payment extends \Payone\Core\Helper\Base PayoneConfig::METHOD_OBT_IDEAL => 'sb', PayoneConfig::METHOD_OBT_PRZELEWY => 'sb', PayoneConfig::METHOD_PAYPAL => 'wlt', + PayoneConfig::METHOD_PAYPALV2 => 'wlt', PayoneConfig::METHOD_PAYDIREKT => 'wlt', PayoneConfig::METHOD_BARZAHLEN => 'csh', PayoneConfig::METHOD_SAFE_INVOICE => 'rec', @@ -240,7 +242,17 @@ public function getBankaccountCheckBlockedMessage() */ public function isPayPalExpressActive() { - return (bool)$this->getConfigParam('express_active', PayoneConfig::METHOD_PAYPAL, 'payone_payment'); + return (bool)$this->getConfigParam('express_active', PayoneConfig::METHOD_PAYPAL, 'payone_payment') && $this->isPaymentMethodActive(PayoneConfig::METHOD_PAYPAL); + } + + /** + * Return is PayPal Express V2 is activated in the configuration + * + * @return bool + */ + public function isPayPalExpressV2Active() + { + return (bool)$this->getConfigParam('express_active', PayoneConfig::METHOD_PAYPALV2, 'payone_payment') && $this->isPaymentMethodActive(PayoneConfig::METHOD_PAYPALV2); } /** diff --git a/Model/Api/Request/Genericpayment/PayPalExpress.php b/Model/Api/Request/Genericpayment/PayPalExpress.php index 65b4b45a..2094ba63 100644 --- a/Model/Api/Request/Genericpayment/PayPalExpress.php +++ b/Model/Api/Request/Genericpayment/PayPalExpress.php @@ -27,29 +27,62 @@ namespace Payone\Core\Model\Api\Request\Genericpayment; use Magento\Quote\Model\Quote; -use Payone\Core\Model\Methods\Paypal; +use Payone\Core\Model\Methods\PayoneMethod; +use Payone\Core\Model\Methods\PaypalV2; +use Payone\Core\Model\PayoneConfig; /** * Class for the PAYONE Server API request genericpayment - "setexpresscheckout" and "getexpresscheckoutdetails" */ class PayPalExpress extends Base { + /** + * Invoice generator + * + * @var \Payone\Core\Model\Api\Invoice + */ + protected $invoiceGenerator; + + /** + * Constructor + * + * @param \Payone\Core\Helper\Shop $shopHelper + * @param \Payone\Core\Helper\Environment $environmentHelper + * @param \Payone\Core\Helper\Api $apiHelper + * @param \Payone\Core\Helper\Toolkit $toolkitHelper + * @param \Payone\Core\Model\ResourceModel\ApiLog $apiLog + * @param \Payone\Core\Helper\Customer $customerHelper + * @param \Payone\Core\Model\Api\Invoice $invoiceGenerator + */ + public function __construct( + \Payone\Core\Helper\Shop $shopHelper, + \Payone\Core\Helper\Environment $environmentHelper, + \Payone\Core\Helper\Api $apiHelper, + \Payone\Core\Helper\Toolkit $toolkitHelper, + \Payone\Core\Model\ResourceModel\ApiLog $apiLog, + \Payone\Core\Helper\Customer $customerHelper, + \Payone\Core\Model\Api\Invoice $invoiceGenerator + ) { + parent::__construct($shopHelper, $environmentHelper, $apiHelper, $toolkitHelper, $apiLog, $customerHelper); + $this->invoiceGenerator = $invoiceGenerator; + } + /** * Send request to PAYONE Server-API with * request-type "genericpayment" * - * @param Quote $oQuote - * @param Paypal $oPayment - * @param string|bool $sWorkorderId + * @param Quote $oQuote + * @param PayoneMethod $oPayment + * @param string|bool $sWorkorderId * @return array Response */ - public function sendRequest(Quote $oQuote, Paypal $oPayment, $sWorkorderId = false) + public function sendRequest(Quote $oQuote, PayoneMethod $oPayment, $sWorkorderId = false) { $this->addParameter('request', 'genericpayment'); $this->addParameter('mode', $oPayment->getOperationMode()); $this->addParameter('aid', $this->shopHelper->getConfigParam('aid')); // ID of PayOne Sub-Account - $this->addParameter('clearingtype', 'wlt'); - $this->addParameter('wallettype', 'PPE'); + $this->addParameter('clearingtype', $oPayment->getClearingtype()); + $this->addParameter('wallettype', $oPayment->getWallettype()); $this->addParameter('narrative_text', 'Test'); $this->addParameter('amount', number_format($this->apiHelper->getQuoteAmount($oQuote), 2, '.', '') * 100); // add price to request @@ -60,6 +93,14 @@ public function sendRequest(Quote $oQuote, Paypal $oPayment, $sWorkorderId = fal $this->addParameter('add_paydata[action]', 'getexpresscheckoutdetails'); } else { $this->addParameter('add_paydata[action]', 'setexpresscheckout'); + + if ($oPayment instanceof PaypalV2) { + $this->addParameter('add_paydata[payment_action]', $oPayment->getAuthorizationMode() == PayoneConfig::REQUEST_TYPE_AUTHORIZATION ? 'Capture' : 'Authorize'); # Is either Capture (for Authorization call) or Authorize (for preauthorization call) + } + } + + if ($this->apiHelper->isInvoiceDataNeeded($oPayment)) { + $this->invoiceGenerator->addProductInfo($this, $oQuote); } $this->addRedirectUrls($oPayment); diff --git a/Model/Api/Request/Genericpayment/UpdateOrder.php b/Model/Api/Request/Genericpayment/UpdateOrder.php new file mode 100644 index 00000000..b9b2b83c --- /dev/null +++ b/Model/Api/Request/Genericpayment/UpdateOrder.php @@ -0,0 +1,74 @@ +invoiceGenerator = $invoiceGenerator; + } + + /** + * Send request to PAYONE Server-API with + * request-type "genericpayment" + * + * @param Quote $oQuote + * @param PayoneMethod $oPayment + * @param string|bool $sWorkorderId + * @return array Response + */ + public function sendRequest(Quote $oQuote, PayoneMethod $oPayment, $sWorkorderId = false) + { + $this->addParameter('request', 'genericpayment'); + $this->addParameter('add_paydata[action]', 'update_order'); + $this->addParameter('workorderid', $sWorkorderId); + $this->addParameter('mode', $oPayment->getOperationMode()); + $this->addParameter('aid', $this->shopHelper->getConfigParam('aid')); // ID of PayOne Sub-Account + $this->addParameter('clearingtype', $oPayment->getClearingtype()); + $this->addParameter('wallettype', $oPayment->getWallettype()); + + $this->addParameter('amount', number_format($this->apiHelper->getQuoteAmount($oQuote), 2, '.', '') * 100); // add price to request + $this->addParameter('currency', $this->apiHelper->getCurrencyFromQuote($oQuote)); // add currency to request + + $this->addParameter('add_paydata[payment_action]', $oPayment->getAuthorizationMode() == PayoneConfig::REQUEST_TYPE_AUTHORIZATION ? 'Capture' : 'Authorize'); # Is either Capture (for Authorization call) or Authorize (for preauthorization call) + $this->addParameter('add_paydata[request_id]', 'TODO'); + + $this->addRedirectUrls($oPayment); + + $this->invoiceGenerator->addProductInfo($this, $oQuote); + + return $this->send($oPayment); + } +} \ No newline at end of file diff --git a/Model/Methods/AliPay.php b/Model/Methods/AliPay.php index 62baf35c..0f6281e1 100644 --- a/Model/Methods/AliPay.php +++ b/Model/Methods/AliPay.php @@ -48,6 +48,13 @@ class AliPay extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'ALP'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -64,6 +71,6 @@ class AliPay extends PayoneMethod */ public function getPaymentSpecificParameters(Order $oOrder) { - return ['wallettype' => 'ALP']; + return ['wallettype' => $this->getWallettype()]; } } diff --git a/Model/Methods/AmazonPay.php b/Model/Methods/AmazonPay.php index 4b64ef6e..db9cf3c1 100644 --- a/Model/Methods/AmazonPay.php +++ b/Model/Methods/AmazonPay.php @@ -48,6 +48,13 @@ class AmazonPay extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'AMZ'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -120,7 +127,7 @@ protected function addAmazonModeParameters($aParams) */ public function getPaymentSpecificParameters(Order $oOrder) { - $aParams = ['wallettype' => 'AMZ']; + $aParams = ['wallettype' => $this->getWallettype()]; $aParams['api_version'] = '3.10'; $sWorkorderId = $this->checkoutSession->getAmazonWorkorderId(); diff --git a/Model/Methods/AmazonPayV2.php b/Model/Methods/AmazonPayV2.php index ea1ac998..75638a02 100644 --- a/Model/Methods/AmazonPayV2.php +++ b/Model/Methods/AmazonPayV2.php @@ -51,6 +51,13 @@ class AmazonPayV2 extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'AMP'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -182,7 +189,7 @@ public function assignData(DataObject $data) */ public function getPaymentSpecificParameters(Order $oOrder) { - $aParams = ['wallettype' => 'AMP']; + $aParams = ['wallettype' => $this->getWallettype()]; $sWorkorderId = $this->checkoutSession->getPayoneWorkorderId(); if ($sWorkorderId) { diff --git a/Model/Methods/ApplePay.php b/Model/Methods/ApplePay.php index fd326da4..7f71ccfa 100644 --- a/Model/Methods/ApplePay.php +++ b/Model/Methods/ApplePay.php @@ -49,6 +49,13 @@ class ApplePay extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'APL'; + /** * @var \Payone\Core\Helper\ApplePay */ @@ -165,7 +172,7 @@ public function getPaymentSpecificParameters(Order $oOrder) } $aParams = [ - 'wallettype' => 'APL', + 'wallettype' => $this->getWallettype(), 'api_version' => '3.11', 'cardtype' => $this->getPayoneCardType($aToken), 'add_paydata[paymentdata_token_data]' => $aToken['paymentData']['data'], diff --git a/Model/Methods/BaseMethod.php b/Model/Methods/BaseMethod.php index b6c28c47..89d26597 100644 --- a/Model/Methods/BaseMethod.php +++ b/Model/Methods/BaseMethod.php @@ -106,6 +106,13 @@ abstract class BaseMethod extends AbstractMethod */ protected $sClearingtype = false; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = false; + /** * Determines if the redirect-parameters have to be added * to the authorization-request diff --git a/Model/Methods/Paydirekt.php b/Model/Methods/Paydirekt.php index 506688a8..efbab193 100644 --- a/Model/Methods/Paydirekt.php +++ b/Model/Methods/Paydirekt.php @@ -48,6 +48,13 @@ class Paydirekt extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'PDT'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -71,7 +78,7 @@ class Paydirekt extends PayoneMethod */ public function getPaymentSpecificParameters(Order $oOrder) { - $aParams = ['wallettype' => 'PDT']; + $aParams = ['wallettype' => $this->getWallettype()]; $blSecuredOrder = (bool)$this->getCustomConfigParam('order_secured'); if ($blSecuredOrder === true && $this->getAuthorizationMode() == PayoneConfig::REQUEST_TYPE_PREAUTHORIZATION) { // params only available with preauth diff --git a/Model/Methods/PayoneMethod.php b/Model/Methods/PayoneMethod.php index 3344b351..c09cfca7 100644 --- a/Model/Methods/PayoneMethod.php +++ b/Model/Methods/PayoneMethod.php @@ -47,6 +47,16 @@ public function getClearingtype() return $this->sClearingtype; } + /** + * Returns wallettype + * + * @return string + */ + public function getWallettype() + { + return $this->sWallettype; + } + /** * Returns authorization-mode * preauthorization or authorization diff --git a/Model/Methods/Paypal.php b/Model/Methods/Paypal.php index 0d728fe8..4e6a4761 100644 --- a/Model/Methods/Paypal.php +++ b/Model/Methods/Paypal.php @@ -48,6 +48,13 @@ class Paypal extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'PPE'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -85,7 +92,7 @@ public function getSuccessUrl(Order $oOrder = null) */ public function getPaymentSpecificParameters(Order $oOrder) { - $aParams = ['wallettype' => 'PPE']; + $aParams = ['wallettype' => $this->getWallettype()]; if ($this->checkoutSession->getIsPayonePayPalExpress() === true) { $sWorkorderId = $this->checkoutSession->getPayoneWorkorderId(); diff --git a/Model/Methods/PaypalV2.php b/Model/Methods/PaypalV2.php new file mode 100644 index 00000000..b05070dd --- /dev/null +++ b/Model/Methods/PaypalV2.php @@ -0,0 +1,108 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Model\Methods; + +use Payone\Core\Model\PayoneConfig; +use Magento\Sales\Model\Order; + +/** + * Model for PayPalV2 payment method + */ +class PaypalV2 extends PayoneMethod +{ + /** + * Payment method code + * + * @var string + */ + protected $_code = PayoneConfig::METHOD_PAYPALV2; + + /** + * Clearingtype for PAYONE authorization request + * + * @var string + */ + protected $sClearingtype = 'wlt'; + + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'PAL'; + + /** + * Determines if the redirect-parameters have to be added + * to the authorization-request + * + * @var bool + */ + protected $blNeedsRedirectUrls = true; + + /** + * Return success url for redirect payment types + * + * @param Order $oOrder + * @return string + */ + public function getSuccessUrl(Order $oOrder = null) + { + if ($this->checkoutSession->getIsPayonePayPalExpress() === true) { + return $this->getReturnedUrl(); + } + return parent::getSuccessUrl($oOrder); + } + + /** + * @return string + */ + public function getReturnedUrl() + { + return $this->url->getUrl('payone/paypal/returned'); + } + + /** + * Return parameters specific to this payment type + * + * @param Order $oOrder + * @return array + */ + public function getPaymentSpecificParameters(Order $oOrder) + { + $aParams = [ + 'wallettype' => $this->getWallettype(), + ]; + + if ($this->checkoutSession->getIsPayonePayPalExpress() === true) { + $sWorkorderId = $this->checkoutSession->getPayoneWorkorderId(); + if ($sWorkorderId) { + $aParams['workorderid'] = $sWorkorderId; + } + } + return $aParams; + } +} diff --git a/Model/Methods/WeChatPay.php b/Model/Methods/WeChatPay.php index 13cc2708..31420198 100644 --- a/Model/Methods/WeChatPay.php +++ b/Model/Methods/WeChatPay.php @@ -48,6 +48,13 @@ class WeChatPay extends PayoneMethod */ protected $sClearingtype = 'wlt'; + /** + * Wallettype for PAYONE requests + * + * @var string|bool + */ + protected $sWallettype = 'WCP'; + /** * Determines if the redirect-parameters have to be added * to the authorization-request @@ -65,7 +72,7 @@ class WeChatPay extends PayoneMethod public function getPaymentSpecificParameters(Order $oOrder) { return [ - 'wallettype' => 'WCP', + 'wallettype' => $this->getWallettype(), 'api_version' => '3.10' ]; } diff --git a/Model/PayoneConfig.php b/Model/PayoneConfig.php index 5687d4de..199f47f3 100644 --- a/Model/PayoneConfig.php +++ b/Model/PayoneConfig.php @@ -68,6 +68,7 @@ abstract class PayoneConfig const METHOD_ADVANCE_PAYMENT = 'payone_advance_payment'; const METHOD_INVOICE = 'payone_invoice'; const METHOD_PAYPAL = 'payone_paypal'; + const METHOD_PAYPALV2 = 'payone_paypalv2'; const METHOD_OBT_SOFORTUEBERWEISUNG = 'payone_obt_sofortueberweisung'; const METHOD_OBT_GIROPAY = 'payone_obt_giropay'; const METHOD_OBT_EPS = 'payone_obt_eps'; diff --git a/Model/Paypal/ReturnHandler.php b/Model/Paypal/ReturnHandler.php index 49b73d4d..be8e2d3f 100644 --- a/Model/Paypal/ReturnHandler.php +++ b/Model/Paypal/ReturnHandler.php @@ -26,6 +26,7 @@ namespace Payone\Core\Model\Paypal; +use Payone\Core\Model\Methods\PayoneMethod; use Payone\Core\Model\PayoneConfig; use Magento\Quote\Model\Quote\Address; use Magento\Quote\Model\Quote; @@ -52,11 +53,11 @@ class ReturnHandler protected $genericRequest; /** - * PayPal payment model + * Payment helper object * - * @var \Payone\Core\Model\Methods\Paypal + * @var \Magento\Payment\Helper\Data */ - protected $paypalPayment; + protected $dataHelper; /** * PAYONE order helper @@ -72,25 +73,33 @@ class ReturnHandler */ protected $checkoutHelper; + /** + * @var array + */ + protected $aAllowedMethods = [ + PayoneConfig::METHOD_PAYPAL, + PayoneConfig::METHOD_PAYPALV2, + ]; + /** * Constructor * * @param \Magento\Checkout\Model\Session $checkoutSession * @param \Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress $genericRequest - * @param \Payone\Core\Model\Methods\Paypal $paypalPayment + * @param \Magento\Payment\Helper\Data $dataHelper * @param \Payone\Core\Helper\Order $orderHelper * @param \Payone\Core\Helper\Checkout $checkoutHelper */ public function __construct( \Magento\Checkout\Model\Session $checkoutSession, \Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress $genericRequest, - \Payone\Core\Model\Methods\Paypal $paypalPayment, + \Magento\Payment\Helper\Data $dataHelper, \Payone\Core\Helper\Order $orderHelper, \Payone\Core\Helper\Checkout $checkoutHelper ) { $this->checkoutSession = $checkoutSession; $this->genericRequest = $genericRequest; - $this->paypalPayment = $paypalPayment; + $this->dataHelper = $dataHelper; $this->orderHelper = $orderHelper; $this->checkoutHelper = $checkoutHelper; } @@ -113,16 +122,26 @@ protected function handleQuote(Quote $oQuote, $aResponse) ->setCustomerGroupId(Group::NOT_LOGGED_IN_ID); } - $oPayment = $oQuote->getPayment(); - $oPayment->setMethod(PayoneConfig::METHOD_PAYPAL); - - $oQuote->setPayment($oPayment); $oQuote->setInventoryProcessed(false); $oQuote->collectTotals()->save(); return $oQuote; } + /** + * @return PayoneMethod + * @throws \Exception + */ + protected function getMethodInstance() + { + $sMethodCode = $this->checkoutSession->getQuote()->getPayment()->getMethod(); + if (!in_array($sMethodCode, $this->aAllowedMethods)) { + throw new \Exception("Unexpected payment method"); + } + + return $this->dataHelper->getMethodInstance($sMethodCode); + } + /** * Quote handling for PayPal return * @@ -132,7 +151,7 @@ protected function handleQuote(Quote $oQuote, $aResponse) public function handlePayPalReturn($sWorkorderId) { $oQuote = $this->checkoutSession->getQuote(); - $aResponse = $this->genericRequest->sendRequest($oQuote, $this->paypalPayment, $sWorkorderId); + $aResponse = $this->genericRequest->sendRequest($oQuote, $this->getMethodInstance(), $sWorkorderId); $this->handleQuote($oQuote, $aResponse); } diff --git a/Model/Source/PayPalButtonColor.php b/Model/Source/PayPalButtonColor.php new file mode 100644 index 00000000..0cbcc2f0 --- /dev/null +++ b/Model/Source/PayPalButtonColor.php @@ -0,0 +1,66 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Model\Source; + +use Magento\Framework\Option\ArrayInterface; + +/** + * Source class for PayPal Express button color + */ +class PayPalButtonColor implements ArrayInterface +{ + /** + * Return existing Amazon button types + * + * @return array + */ + public function toOptionArray() + { + return [ + [ + 'value' => 'gold', + 'label' => __('Gold'), + ], + [ + 'value' => 'blue', + 'label' => __('Blue') + ], + [ + 'value' => 'silver', + 'label' => __('Silver') + ], + [ + 'value' => 'white', + 'label' => __('White') + ], + [ + 'value' => 'black', + 'label' => __('Black') + ] + ]; + } +} diff --git a/Model/Source/PayPalButtonShape.php b/Model/Source/PayPalButtonShape.php new file mode 100644 index 00000000..ab1ff5d7 --- /dev/null +++ b/Model/Source/PayPalButtonShape.php @@ -0,0 +1,58 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Model\Source; + +use Magento\Framework\Option\ArrayInterface; + +/** + * Source class for PayPal Express button shape + */ +class PayPalButtonShape implements ArrayInterface +{ + /** + * Return existing Amazon button types + * + * @return array + */ + public function toOptionArray() + { + return [ + [ + 'value' => 'rect', + 'label' => __('Default button shape') + ], + [ + 'value' => 'pill', + 'label' => __('Round corners') + ], + [ + 'value' => 'sharp', + 'label' => __('Sharp corners') + ] + ]; + } +} diff --git a/Observer/AddPaypalExpressButtons.php b/Observer/AddPaypalExpressButtons.php index 5fcc9f9a..8494c8fb 100644 --- a/Observer/AddPaypalExpressButtons.php +++ b/Observer/AddPaypalExpressButtons.php @@ -61,23 +61,25 @@ public function __construct(Payment $paymentHelper) */ public function execute(Observer $observer) { - if ($this->paymentHelper->isPayPalExpressActive() === false) { + if ($this->paymentHelper->isPayPalExpressActive() === false && $this->paymentHelper->isPayPalExpressV2Active() === false) { return; } /** @var \Magento\Catalog\Block\ShortcutButtons $shortcutButtons */ $shortcutButtons = $observer->getEvent()->getContainer(); - if (in_array($shortcutButtons->getNameInLayout(), ['addtocart.shortcut.buttons', 'addtocart.shortcut.buttons.additional'])) { + if (in_array($shortcutButtons->getNameInLayout(), ['addtocart.shortcut.buttons', 'addtocart.shortcut.buttons.additional', 'map.shortcut.buttons'])) { return; } + $sBlock = 'Payone\Core\Block\Paypal\ExpressButton'; + if ($this->paymentHelper->isPayPalExpressV2Active() === true) { + $sBlock = 'Payone\Core\Block\Paypal\ExpressButtonV2'; + } + /** @var Shortcut $shortcut */ - $shortcut = $shortcutButtons->getLayout()->createBlock( - 'Payone\Core\Block\Paypal\ExpressButton', - '', - [] - ); + $shortcut = $shortcutButtons->getLayout()->createBlock($sBlock, '', []); + $shortcut->setName($shortcutButtons->getNameInLayout()); $shortcutButtons->addShortcut($shortcut); } diff --git a/Service/V1/Data/PayPalResponse.php b/Service/V1/Data/PayPalResponse.php new file mode 100644 index 00000000..b30080f3 --- /dev/null +++ b/Service/V1/Data/PayPalResponse.php @@ -0,0 +1,75 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Service\V1\Data; + +use Payone\Core\Api\Data\PayPalResponseInterface; + +/** + * Object for PayPal Express V2 response + */ +class PayPalResponse extends \Magento\Framework\Api\AbstractExtensibleObject implements PayPalResponseInterface +{ + /** + * Returns if the installment plan request was a success + * + * @return string + */ + public function getWorkorderId() + { + return $this->_get('workorderId'); + } + + /** + * Returns if the call was successful + * + * @return bool + */ + public function getSuccess() + { + return $this->_get('success'); + } + + /** + * Return paypal order id + * + * @return string + */ + public function getOrderId() + { + return $this->_get('orderId'); + } + + /** + * Returns errormessage + * + * @return string + */ + public function getErrormessage() + { + return $this->_get('errormessage'); + } +} diff --git a/Service/V1/PayPal.php b/Service/V1/PayPal.php new file mode 100644 index 00000000..fef6ec78 --- /dev/null +++ b/Service/V1/PayPal.php @@ -0,0 +1,135 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Service\V1; + +use Payone\Core\Api\PayPalInterface; +use Payone\Core\Model\PayoneConfig; +use Magento\Checkout\Model\Type\Onepage; +use Magento\Customer\Model\Group; + +/** + * Web API model for the PAYONE PayPal express + */ +class PayPal implements PayPalInterface +{ + /** + * Factory for the response object + * + * @var \Payone\Core\Api\Data\PayPalResponseInterfaceFactory + */ + protected $responseFactory; + + /** + * Checkout session + * + * @var \Magento\Checkout\Model\Session + */ + protected $checkoutSession; + + /** + * Request object + * + * @var \Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress + */ + protected $paypalRequest; + + /** + * @var \Payone\Core\Helper\Checkout + */ + protected $checkoutHelper; + + /** + * @var \Magento\Payment\Helper\Data + */ + protected $dataHelper; + + /** + * Constructor. + * + * @param \Payone\Core\Api\Data\PayPalResponseInterfaceFactory $responseFactory + * @param \Magento\Checkout\Model\Session $checkoutSession + * @param \Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress $paypalRequest + * @param \Payone\Core\Helper\Checkout $checkoutHelper + * @param \Magento\Payment\Helper\Data $dataHelper + */ + public function __construct( + \Payone\Core\Api\Data\PayPalResponseInterfaceFactory $responseFactory, + \Magento\Checkout\Model\Session $checkoutSession, + \Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress $paypalRequest, + \Payone\Core\Helper\Checkout $checkoutHelper, + \Magento\Payment\Helper\Data $dataHelper + ) { + $this->responseFactory = $responseFactory; + $this->checkoutSession = $checkoutSession; + $this->paypalRequest = $paypalRequest; + $this->checkoutHelper = $checkoutHelper; + $this->dataHelper = $dataHelper; + } + + /** + * Trigger PayPal Express v2 process + * + * @param string $cartId + * @return \Payone\Core\Service\V1\Data\PayPalResponse + */ + public function startPayPalExpress($cartId) + { + $blSuccess = false; + $oResponse = $this->responseFactory->create(); + + $oQuote = $this->checkoutSession->getQuote(); + + $oPayment = $oQuote->getPayment(); + $oPayment->setMethod(PayoneConfig::METHOD_PAYPALV2); + + $oQuote->setPayment($oPayment); + $oQuote->save(); + + $oMethodInstance = $this->dataHelper->getMethodInstance(PayoneConfig::METHOD_PAYPALV2); + $oMethodInstance->setMethodInstance($oQuote->getPayment()); + + $aResponse = $this->paypalRequest->sendRequest($oQuote, $oMethodInstance); + if (isset($aResponse['status'], $aResponse['workorderid'], $aResponse['add_paydata[orderId]']) && $aResponse['status'] == 'REDIRECT') { + $blSuccess = true; + + $oResponse->setData('orderId', $aResponse['add_paydata[orderId]']); + + if (!empty($aResponse['workorderid'])) { + $this->checkoutSession->setIsPayonePayPalExpress(true); + $this->checkoutSession->setPayoneWorkorderId($aResponse['workorderid']); + $this->checkoutSession->setPayoneQuoteComparisonString($this->checkoutHelper->getQuoteComparisonString($oQuote)); + } + } + + if (isset($aResponse['status'], $aResponse['customermessage']) && $aResponse['status'] == 'ERROR') { + $oResponse->setData('errormessage', $aResponse['customermessage']); + } + + $oResponse->setData('success', $blSuccess); + return $oResponse; + } +} diff --git a/Test/Unit/Block/Paypal/ExpressButtonTest.php b/Test/Unit/Block/Paypal/ExpressButtonTest.php index d4f39204..d46a9b78 100644 --- a/Test/Unit/Block/Paypal/ExpressButtonTest.php +++ b/Test/Unit/Block/Paypal/ExpressButtonTest.php @@ -105,4 +105,19 @@ public function testGetPayPalExpressLogoUrlDefault() $expected = 'https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif'; $this->assertEquals($expected, $result); } + + public function testGetButtonIdent() + { + $testArray = [ + 'anything' => 'payone-paypal-button-container', + 'checkout.cart.shortcut.buttons' => 'payone-paypal-button-basket', + 'shortcutbuttons' => 'payone-paypal-button-minibasket', + ]; + + foreach ($testArray as $input => $expected) { + $this->classToTest->setName($input); + $result = $this->classToTest->getButtonIdent(); + $this->assertEquals($expected, $result); + } + } } diff --git a/Test/Unit/Block/Paypal/ExpressButtonV2Test.php b/Test/Unit/Block/Paypal/ExpressButtonV2Test.php new file mode 100644 index 00000000..60630b86 --- /dev/null +++ b/Test/Unit/Block/Paypal/ExpressButtonV2Test.php @@ -0,0 +1,142 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Block\Paypal; + +use Magento\Checkout\Model\Session; +use Magento\Framework\Locale\ResolverInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\UrlInterface; +use Magento\Framework\View\Element\Template\Context; +use Magento\Payment\Helper\Data; +use Magento\Quote\Model\Quote; +use Magento\Store\Api\Data\StoreInterface; +use Payone\Core\Block\Paypal\ExpressButtonV2 as ClassToTest; +use Payone\Core\Helper\Api; +use Payone\Core\Helper\Payment; +use Payone\Core\Model\Methods\PayoneMethod; +use Payone\Core\Model\PayoneConfig; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class ExpressButtonV2Test extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + /** + * @var ObjectManager|PayoneObjectManager + */ + private $objectManager; + + /** + * @var (Payment&\PHPUnit\Framework\MockObject\MockObject) + */ + private $paymentHelper; + + protected function setUp(): void + { + $this->objectManager = $this->getObjectManager(); + + $store = $this->getMockBuilder(StoreInterface::class)->disableOriginalConstructor()->getMock(); + $store->method('getCode')->willReturn('store4711code'); + + $quote = $this->getMockBuilder(Quote::class)->disableOriginalConstructor()->getMock(); + $quote->method('getId')->willReturn('test4711'); + $quote->method('getStore')->willReturn($store); + + $checkoutSession = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getQuote']) + ->getMock(); + $checkoutSession->method('getQuote')->willReturn($quote); + + $this->paymentHelper = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + + $apiHelper = $this->getMockBuilder(Api::class)->disableOriginalConstructor()->getMock(); + $apiHelper->method('getCurrencyFromQuote')->willReturn('EUR'); + + $methodInstance = $this->getMockBuilder(PayoneMethod::class)->disableOriginalConstructor()->getMock(); + $methodInstance->method('getOperationMode')->willReturn('live'); + $methodInstance->method('getCustomConfigParam')->willReturn('test4711'); + $methodInstance->method('getAuthorizationMode')->willReturn(PayoneConfig::REQUEST_TYPE_AUTHORIZATION); + + $dataHelper = $this->getMockBuilder(Data::class)->disableOriginalConstructor()->getMock(); + $dataHelper->method('getMethodInstance')->willReturn($methodInstance); + + $this->classToTest = $this->objectManager->getObject(ClassToTest::class, [ + 'checkoutSession' => $checkoutSession, + 'paymentHelper' => $this->paymentHelper, + 'apiHelper' => $apiHelper, + 'dataHelper' => $dataHelper, + ]); + } + + public function testGetMethodInstance() + { + $result = $this->classToTest->getMethodInstance(); + $this->assertInstanceOf(PayoneMethod::class, $result); + } + + public function testGetQuoteId() + { + $expected = "test4711"; + $result = $this->classToTest->getQuoteId(); + $this->assertEquals($expected, $result); + } + + public function testGetStoreCode() + { + $expected = "store4711code"; + $result = $this->classToTest->getStoreCode(); + $this->assertEquals($expected, $result); + } + + public function testGetButtonColor() + { + $expected = "test4711"; + $result = $this->classToTest->getButtonColor(); + $this->assertEquals($expected, $result); + } + + public function testGetButtonShape() + { + $expected = "test4711"; + $result = $this->classToTest->getButtonShape(); + $this->assertEquals($expected, $result); + } + + public function testGetJavascriptUrl() + { + $this->paymentHelper->method('getConfigParam')->willReturn(true); + + $result = $this->classToTest->getJavascriptUrl(); + $result = strpos($result, "enable-funding") !== false; + $this->assertTrue($result); + } +} diff --git a/Test/Unit/Helper/PaymentTest.php b/Test/Unit/Helper/PaymentTest.php index 00369bce..41e62c1f 100644 --- a/Test/Unit/Helper/PaymentTest.php +++ b/Test/Unit/Helper/PaymentTest.php @@ -166,11 +166,26 @@ public function testIsPayPalExpressActive() { $this->scopeConfig->expects($this->any()) ->method('getValue') - ->willReturnMap([['payone_payment/'.PayoneConfig::METHOD_PAYPAL.'/express_active', ScopeInterface::SCOPE_STORES, null, 1]]); + ->willReturnMap([ + ['payone_payment/'.PayoneConfig::METHOD_PAYPAL.'/express_active', ScopeInterface::SCOPE_STORES, null, 1], + ['payment/'.PayoneConfig::METHOD_PAYPAL.'/active', ScopeInterface::SCOPE_STORES, null, 1], + ]); $result = $this->payment->isPayPalExpressActive(); $this->assertTrue($result); } + public function testIsPayPalExpressV2Active() + { + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->willReturnMap([ + ['payone_payment/'.PayoneConfig::METHOD_PAYPALV2.'/express_active', ScopeInterface::SCOPE_STORES, null, 1], + ['payment/'.PayoneConfig::METHOD_PAYPALV2.'/active', ScopeInterface::SCOPE_STORES, null, 1], + ]); + $result = $this->payment->isPayPalExpressV2Active(); + $this->assertTrue($result); + } + public function testGetPaymentAbbreviation() { $result = $this->payment->getPaymentAbbreviation(PayoneConfig::METHOD_CREDITCARD); @@ -199,7 +214,7 @@ public function testGetKlarnaStoreIdsEmpty() { $this->scopeConfig->expects($this->any()) ->method('getValue') - ->willReturnMap([['payone_payment/'.PayoneConfig::METHOD_KLARNA.'/klarna_config', ScopeInterface::SCOPE_STORES, null, $this->toolkitHelper->serialize([])]]); + ->willReturnMap([['payone_payment/'.PayoneConfig::METHOD_KLARNA.'/klarna_config', ScopeInterface::SCOPE_STORES, null, null]]); $expected = []; $result = $this->payment->getKlarnaStoreIds(); @@ -252,4 +267,39 @@ public function testGetAvailableApplePayTypesEmpty() $result = $this->payment->getAvailableApplePayTypes(); $this->assertCount(0, $result); } + + public function testGetCustomConfigParamGlobal() + { + $expected = "test"; + + $method = PayoneConfig::METHOD_PAYPAL; + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->willReturnMap([ + ['payone_payment/'.$method.'/use_global', ScopeInterface::SCOPE_STORES, null, 1], + ['payone_general/global/mode', ScopeInterface::SCOPE_STORES, null, $expected], + ]); + + $result = $this->payment->getCustomConfigParam("mode", $method); + + $this->assertEquals($expected, $result); + } + + public function testGetCustomConfigParam() + { + $expected = "test"; + + $method = PayoneConfig::METHOD_PAYPAL; + $this->scopeConfig->expects($this->any()) + ->method('getValue') + ->willReturnMap([ + ['payone_payment/'.$method.'/use_global', ScopeInterface::SCOPE_STORES, null, 0], + ['payone_payment/'.$method.'/mode', ScopeInterface::SCOPE_STORES, null, $expected], + ['payone_general/global/mode', ScopeInterface::SCOPE_STORES, null, "live"], + ]); + + $result = $this->payment->getCustomConfigParam("mode", $method); + + $this->assertEquals($expected, $result); + } } diff --git a/Test/Unit/Model/Api/Request/Genericpayment/PayPalExpressTest.php b/Test/Unit/Model/Api/Request/Genericpayment/PayPalExpressTest.php index df82f8e2..e66efb6c 100644 --- a/Test/Unit/Model/Api/Request/Genericpayment/PayPalExpressTest.php +++ b/Test/Unit/Model/Api/Request/Genericpayment/PayPalExpressTest.php @@ -32,6 +32,7 @@ use Payone\Core\Helper\Api; use Payone\Core\Helper\Shop; use Payone\Core\Model\Methods\Paypal; +use Payone\Core\Model\Methods\PaypalV2; use Payone\Core\Test\Unit\BaseTestCase; use Payone\Core\Test\Unit\PayoneObjectManager; @@ -85,6 +86,7 @@ public function testSendRequest() $response = ['status' => 'APPROVED']; $this->apiHelper->method('sendApiRequest')->willReturn($response); $this->apiHelper->method('getQuoteAmount')->willReturn(100); + $this->apiHelper->method('isInvoiceDataNeeded')->willReturn(true); $result = $this->classToTest->sendRequest($quote, $payment, 100); $this->assertEquals($response, $result); @@ -99,7 +101,7 @@ public function testSendRequestNoWorkorderId() $quote->method('getGrandTotal')->willReturn(123); $quote->method('getQuoteCurrencyCode')->willReturn('EUR'); - $payment = $this->getMockBuilder(Paypal::class)->disableOriginalConstructor()->getMock(); + $payment = $this->getMockBuilder(PaypalV2::class)->disableOriginalConstructor()->getMock(); $payment->method('getOperationMode')->willReturn('test'); $payment->method('getSuccessUrl')->willReturn('http://testdomain.com'); $payment->method('getErrorUrl')->willReturn('http://testdomain.com'); diff --git a/Test/Unit/Model/Api/Request/Genericpayment/UpdateOrderTest.php b/Test/Unit/Model/Api/Request/Genericpayment/UpdateOrderTest.php new file mode 100644 index 00000000..e0f63e2c --- /dev/null +++ b/Test/Unit/Model/Api/Request/Genericpayment/UpdateOrderTest.php @@ -0,0 +1,97 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2017 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Model\Api\Request\Genericpayment; + +use Magento\Quote\Model\Quote; +use Payone\Core\Model\Api\Request\Genericpayment\UpdateOrder as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Payone\Core\Helper\Api; +use Payone\Core\Helper\Shop; +use Payone\Core\Model\Methods\Paypal; +use Payone\Core\Model\Methods\PaypalV2; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class UpdateOrderTest extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + /** + * @var Api|\PHPUnit_Framework_MockObject_MockObject + */ + private $apiHelper; + + /** + * @var Shop|\PHPUnit_Framework_MockObject_MockObject + */ + private $shopHelper; + + protected function setUp(): void + { + $objectManager = $this->getObjectManager(); + + $this->apiHelper = $this->getMockBuilder(Api::class)->disableOriginalConstructor()->getMock(); + $this->shopHelper = $this->getMockBuilder(Shop::class)->disableOriginalConstructor()->getMock(); + + $this->classToTest = $objectManager->getObject(ClassToTest::class, [ + 'shopHelper' => $this->shopHelper, + 'apiHelper' => $this->apiHelper + ]); + } + + public function testSendRequest() + { + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->setMethods(['getGrandTotal', 'getQuoteCurrencyCode']) + ->getMock(); + $quote->method('getGrandTotal')->willReturn(123); + $quote->method('getQuoteCurrencyCode')->willReturn('EUR'); + + $payment = $this->getMockBuilder(PaypalV2::class)->disableOriginalConstructor()->getMock(); + $payment->method('getOperationMode')->willReturn('test'); + $payment->method('getClearingtype')->willReturn('wlt'); + $payment->method('getWallettype')->willReturn('PAL'); + $payment->method('getAuthorizationMode')->willReturn('authorization'); + $payment->method('getSuccessUrl')->willReturn('http://testdomain.com'); + $payment->method('getErrorUrl')->willReturn('http://testdomain.com'); + $payment->method('getCancelUrl')->willReturn('http://testdomain.com'); + + $this->shopHelper->method('getConfigParam')->willReturn('12345'); + + $response = ['status' => 'APPROVED']; + $this->apiHelper->method('sendApiRequest')->willReturn($response); + $this->apiHelper->method('getQuoteAmount')->willReturn(100); + $this->apiHelper->method('getCurrencyFromQuote')->willReturn('EUR'); + + $result = $this->classToTest->sendRequest($quote, $payment, 100); + $this->assertEquals($response, $result); + } +} diff --git a/Test/Unit/Model/Methods/PaypalV2Test.php b/Test/Unit/Model/Methods/PaypalV2Test.php new file mode 100644 index 00000000..81164f61 --- /dev/null +++ b/Test/Unit/Model/Methods/PaypalV2Test.php @@ -0,0 +1,111 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Model\Methods; + +use Magento\Checkout\Model\Session; +use Payone\Core\Model\Methods\PaypalV2 as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Sales\Model\Order; +use Magento\Framework\Url; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class PaypalV2Test extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + /** + * @var ObjectManager|PayoneObjectManager + */ + private $objectManager; + + /** + * @var Session + */ + private $checkoutSession; + + protected function setUp(): void + { + $this->objectManager = $this->getObjectManager(); + + $this->checkoutSession = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods(['getPayoneWorkorderId', 'getIsPayonePayPalExpress']) + ->getMock(); + $this->checkoutSession->method('getPayoneWorkorderId')->willReturn('12345'); + + $url = $this->getMockBuilder(Url::class)->disableOriginalConstructor()->getMock(); + $url->method('getUrl')->willReturn('http://testdomain.org'); + + $this->classToTest = $this->objectManager->getObject(ClassToTest::class, [ + 'checkoutSession' => $this->checkoutSession, + 'url' => $url + ]); + } + + public function testGetPaymentSpecificParameters() + { + $order = $this->getMockBuilder(Order::class)->disableOriginalConstructor()->getMock(); + $this->checkoutSession->method('getIsPayonePayPalExpress')->willReturn(true); + + $result = $this->classToTest->getPaymentSpecificParameters($order); + $expected = ['wallettype' => 'PAL', 'workorderid' => '12345']; + $this->assertEquals($expected, $result); + } + + public function testGetSuccessUrl() + { + $this->checkoutSession->method('getIsPayonePayPalExpress')->willReturn(true); + $expected = 'http://testdomain.org'; + + $result = $this->classToTest->getSuccessUrl(); + $this->assertEquals($expected, $result); + } + + public function testGetSuccessUrlParent() + { + $this->checkoutSession->method('getIsPayonePayPalExpress')->willReturn(false); + $expected = 'http://testdomain.org?incrementId=12345'; + + $order = $this->getMockBuilder(Order::class)->disableOriginalConstructor()->getMock(); + $order->method('getIncrementId')->willReturn('12345'); + + $result = $this->classToTest->getSuccessUrl($order); + $this->assertEquals($expected, $result); + } + + public function testGetReturnedUrl() + { + $expected = 'http://testdomain.org'; + + $result = $this->classToTest->getCancelUrl(); + $this->assertEquals($expected, $result); + } +} diff --git a/Test/Unit/Model/Paypal/ReturnHandlerTest.php b/Test/Unit/Model/Paypal/ReturnHandlerTest.php index 147011ec..e8b7f157 100644 --- a/Test/Unit/Model/Paypal/ReturnHandlerTest.php +++ b/Test/Unit/Model/Paypal/ReturnHandlerTest.php @@ -26,6 +26,7 @@ namespace Payone\Core\Test\Unit\Model\Paypal; +use Payone\Core\Model\PayoneConfig; use Payone\Core\Model\Paypal\ReturnHandler as ClassToTest; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Checkout\Model\Session; @@ -38,6 +39,8 @@ use Magento\Quote\Model\Quote\Address; use Payone\Core\Test\Unit\BaseTestCase; use Payone\Core\Test\Unit\PayoneObjectManager; +use Payone\Core\Model\Methods\Paypal; +use Magento\Payment\Helper\Data; class ReturnHandlerTest extends BaseTestCase { @@ -51,11 +54,15 @@ class ReturnHandlerTest extends BaseTestCase */ private $objectManager; + + private $payment; + protected function setUp(): void { $this->objectManager = $this->getObjectManager(); - $payment = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + $this->payment = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + $address = $this->getMockBuilder(Address::class) ->disableOriginalConstructor() ->setMethods(['getEmail', 'setEmail', 'setShouldIgnoreValidation']) @@ -85,7 +92,7 @@ protected function setUp(): void ->getMock(); $quote->method('getId')->willReturn('12345'); $quote->method('setIsActive')->willReturn($quote); - $quote->method('getPayment')->willReturn($payment); + $quote->method('getPayment')->willReturn($this->payment); $quote->method('collectTotals')->willReturn($quote); $quote->method('setCustomerId')->willReturn($quote); $quote->method('setCustomerEmail')->willReturn($quote); @@ -117,17 +124,33 @@ protected function setUp(): void $checkoutHelper = $this->getMockBuilder(Checkout::class)->disableOriginalConstructor()->getMock(); $checkoutHelper->method('getCurrentCheckoutMethod')->willReturn(Onepage::METHOD_GUEST); + $paymentMethod = $this->getMockBuilder(Paypal::class)->disableOriginalConstructor()->getMock(); + + $dataHelper = $this->getMockBuilder(Data::class)->disableOriginalConstructor()->getMock(); + $dataHelper->method('getMethodInstance')->willReturn($paymentMethod); + $this->classToTest = $this->objectManager->getObject(ClassToTest::class, [ 'checkoutSession' => $checkoutSession, 'genericRequest' => $genericRequest, 'orderHelper' => $orderHelper, - 'checkoutHelper' => $checkoutHelper + 'checkoutHelper' => $checkoutHelper, + 'dataHelper' => $dataHelper, ]); } public function testHandlePayPalReturn() { + $this->payment->method('getMethod')->willReturn(PayoneConfig::METHOD_PAYPAL); + $result = $this->classToTest->handlePayPalReturn('12345'); $this->assertNull($result); } + + public function testHandlePayPalReturnException() + { + $this->payment->method('getMethod')->willReturn(PayoneConfig::METHOD_CREDITCARD); + + $this->expectException(\Exception::class); + $this->classToTest->handlePayPalReturn('12345'); + } } diff --git a/Test/Unit/Model/Source/PayPalButtonColorTest.php b/Test/Unit/Model/Source/PayPalButtonColorTest.php new file mode 100644 index 00000000..0cfc6ef8 --- /dev/null +++ b/Test/Unit/Model/Source/PayPalButtonColorTest.php @@ -0,0 +1,52 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Model\Source; + +use Payone\Core\Model\Source\PayPalButtonColor as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class PayPalButtonColorTest extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + protected function setUp(): void + { + $objectManager = $this->getObjectManager(); + $this->classToTest = $objectManager->getObject(ClassToTest::class); + } + + public function testToOptionArray() + { + $result = $this->classToTest->toOptionArray(); + $this->assertCount(5, $result); + } +} diff --git a/Test/Unit/Model/Source/PayPalButtonShapeTest.php b/Test/Unit/Model/Source/PayPalButtonShapeTest.php new file mode 100644 index 00000000..75ece1cc --- /dev/null +++ b/Test/Unit/Model/Source/PayPalButtonShapeTest.php @@ -0,0 +1,52 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Model\Source; + +use Payone\Core\Model\Source\PayPalButtonShape as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class PayPalButtonShapeTest extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + protected function setUp(): void + { + $objectManager = $this->getObjectManager(); + $this->classToTest = $objectManager->getObject(ClassToTest::class); + } + + public function testToOptionArray() + { + $result = $this->classToTest->toOptionArray(); + $this->assertCount(3, $result); + } +} diff --git a/Test/Unit/Observer/AddPaypalExpressButtonTest.php b/Test/Unit/Observer/AddPaypalExpressButtonTest.php index 956f64a0..a7bc98b9 100644 --- a/Test/Unit/Observer/AddPaypalExpressButtonTest.php +++ b/Test/Unit/Observer/AddPaypalExpressButtonTest.php @@ -68,6 +68,7 @@ protected function setUp(): void public function testExecutePaypalInactive() { $this->paymentHelper->method('isPayPalExpressActive')->willReturn(false); + $this->paymentHelper->method('isPayPalExpressV2Active')->willReturn(false); $observer = $this->getMockBuilder(Observer::class)->disableOriginalConstructor()->getMock(); $result = $this->classToTest->execute($observer); @@ -77,6 +78,7 @@ public function testExecutePaypalInactive() public function testExecutePaypalActive() { $this->paymentHelper->method('isPayPalExpressActive')->willReturn(true); + $this->paymentHelper->method('isPayPalExpressV2Active')->willReturn(true); $shortcut = $this->getMockBuilder(Shortcut::class)->disableOriginalConstructor()->getMock(); diff --git a/Test/Unit/Service/V1/Data/PayPalResponseTest.php b/Test/Unit/Service/V1/Data/PayPalResponseTest.php new file mode 100644 index 00000000..99fb64a2 --- /dev/null +++ b/Test/Unit/Service/V1/Data/PayPalResponseTest.php @@ -0,0 +1,84 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Service\V1\Data; + +use Payone\Core\Service\V1\Data\PayPalResponse as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Payone\Core\Test\Unit\BaseTestCase; +use Payone\Core\Test\Unit\PayoneObjectManager; + +class PayPalResponseTest extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + protected function setUp(): void + { + $objectManager = $this->getObjectManager(); + + $data = [ + 'success' => 'success', + 'errormessage' => 'errormessage', + 'workorderId' => 'workorderId', + 'orderId' => 'orderId', + ]; + + $this->classToTest = $objectManager->getObject(ClassToTest::class, [ + 'data' => $data + ]); + } + + public function testGetSuccess() + { + $result = $this->classToTest->getSuccess(); + $expected = 'success'; + $this->assertEquals($expected, $result); + } + + public function testGetErrormessage() + { + $result = $this->classToTest->getErrormessage(); + $expected = 'errormessage'; + $this->assertEquals($expected, $result); + } + + public function testGetWorkorderId() + { + $result = $this->classToTest->getWorkorderId(); + $expected = 'workorderId'; + $this->assertEquals($expected, $result); + } + + public function testGetOrderId() + { + $result = $this->classToTest->getOrderId(); + $expected = 'orderId'; + $this->assertEquals($expected, $result); + } +} diff --git a/Test/Unit/Service/V1/PayPalTest.php b/Test/Unit/Service/V1/PayPalTest.php new file mode 100644 index 00000000..0ea99836 --- /dev/null +++ b/Test/Unit/Service/V1/PayPalTest.php @@ -0,0 +1,143 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2018 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +namespace Payone\Core\Test\Unit\Service\V1\Data; + +use Magento\Quote\Model\Quote; +use Payone\Core\Helper\Checkout; +use Payone\Core\Model\Methods\PayoneMethod; +use Payone\Core\Model\PayoneConfig; +use Payone\Core\Service\V1\Data\PayPalResponse; +use Payone\Core\Service\V1\PayPal as ClassToTest; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Quote\Api\Data\AddressInterface; +use Magento\Customer\Model\ResourceModel\AddressRepository; +use Payone\Core\Test\Unit\BaseTestCase; +use Magento\Customer\Api\Data\AddressInterface as CustomerAddressInterface; +use Payone\Core\Api\Data\PayPalResponseInterfaceFactory; +use Magento\Checkout\Model\Session; +use Payone\Core\Model\Api\Request\Genericpayment\PayPalExpress; +use Magento\Quote\Model\Quote\Payment; +use Magento\Checkout\Model\Type\Onepage; +use Magento\Quote\Model\Quote\Address; +use Magento\Framework\App\ViewInterface; +use Magento\Framework\View\LayoutInterface; +use Magento\Framework\View\Element\BlockInterface; +use Magento\Payment\Helper\Data; + +class PayPalTest extends BaseTestCase +{ + /** + * @var ClassToTest + */ + private $classToTest; + + /** + * @var AmazonPayResponse|\PHPUnit_Framework_MockObject_MockObject + */ + private $response; + + private $paypalExpress; + + protected function setUp(): void + { + $objectManager = $this->getObjectManager(); + + $this->response = $objectManager->getObject(PayPalResponse::class); + + $responseFactory = $this->getMockBuilder(PayPalResponseInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $responseFactory->method('create')->willReturn($this->response); + + $payment = $this->getMockBuilder(Payment::class)->disableOriginalConstructor()->getMock(); + + $quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->setMethods([ + 'save', + 'getPayment', + 'setPayment', + ]) + ->getMock(); + $quote->method('getPayment')->willReturn($payment); + + $checkoutSession = $this->getMockBuilder(Session::class) + ->disableOriginalConstructor() + ->setMethods([ + 'getQuote', + 'setIsPayonePayPalExpress', + 'setPayoneWorkorderId', + 'setPayoneQuoteComparisonString', + ]) + ->getMock(); + $checkoutSession->method('getQuote')->willReturn($quote); + + $this->paypalExpress = $this->getMockBuilder(PayPalExpress::class)->disableOriginalConstructor()->getMock(); + + $checkoutHelper = $this->getMockBuilder(Checkout::class)->disableOriginalConstructor()->getMock(); + $checkoutHelper->method('getQuoteComparisonString')->willReturn('0815'); + + $methodInstance = $this->getMockBuilder(PayoneMethod::class)->disableOriginalConstructor()->getMock(); + + $dataHelper = $this->getMockBuilder(Data::class)->disableOriginalConstructor()->getMock(); + $dataHelper->method('getMethodInstance')->willReturn($methodInstance); + + $this->classToTest = $objectManager->getObject(ClassToTest::class, [ + 'responseFactory' => $responseFactory, + 'checkoutSession' => $checkoutSession, + 'paypalRequest' => $this->paypalExpress, + 'checkoutHelper' => $checkoutHelper, + 'dataHelper' => $dataHelper, + ]); + } + + public function testStartPayPalExpress() + { + $this->paypalExpress->method('sendRequest')->willReturn([ + 'status' => 'REDIRECT', + 'workorderid' => '4711', + 'add_paydata[orderId]' => '0815', + ]); + + $result = $this->classToTest->startPayPalExpress(4711); + $this->assertInstanceOf(PayPalResponse::class, $result); + $this->assertTrue($result->getSuccess()); + } + + public function testStartPayPalExpressError() + { + $this->paypalExpress->method('sendRequest')->willReturn([ + 'status' => 'ERROR', + 'customermessage' => 'error_message', + ]); + + $result = $this->classToTest->startPayPalExpress(4711); + $this->assertInstanceOf(PayPalResponse::class, $result); + $this->assertFalse($result->getSuccess()); + } +} diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 2dfe6f03..c2633cca 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -121,6 +121,11 @@ Payone\Core\Block\Adminhtml\Config\Form\Field\StatusMapping Payone\Core\Model\Config\Backend\SerializedOrJson + + + Payone\Core\Block\Adminhtml\Config\Form\Field\StatusMapping + Payone\Core\Model\Config\Backend\SerializedOrJson + Payone\Core\Block\Adminhtml\Config\Form\Field\StatusMapping @@ -307,6 +312,7 @@ + diff --git a/etc/adminhtml/system/payone_paypalv2.xml b/etc/adminhtml/system/payone_paypalv2.xml new file mode 100644 index 00000000..cf9bdafa --- /dev/null +++ b/etc/adminhtml/system/payone_paypalv2.xml @@ -0,0 +1,92 @@ + + + + + + + + Magento\Config\Model\Config\Source\Yesno + payment/payone_paypalv2/active + + + + Magento\Config\Model\Config\Source\Yesno + + + + Magento\Config\Model\Config\Source\Yesno + + + + payment/payone_paypalv2/title + + + + + + + + 1 + + Payone\Core\Model\Source\PayPalButtonColor + + + + + 1 + + Payone\Core\Model\Source\PayPalButtonShape + + + + Magento\Sales\Model\Config\Source\Order\Status\NewStatus + payment/payone_paypalv2/order_status + + + + payment/payone_paypalv2/instructions + + + + payment/payone_paypalv2/min_order_total + + + + payment/payone_paypalv2/max_order_total + + + + payment/payone_paypalv2/sort_order + + + + Transmit the billing address as delivery address if delivery address is missing. + Magento\Config\Model\Config\Source\Yesno + + + + diff --git a/etc/config.xml b/etc/config.xml index f2b7f235..2bb9e48d 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -64,6 +64,15 @@ 0 payone + + 1 + Authorization + Payone\Core\Model\Methods\PaypalV2 + pending + PAYONE PayPal V2 + 0 + payone + 1 Authorization @@ -382,6 +391,7 @@ {"_1343137391927_927":{"txaction":"appointed","state_status":"processing"}} {"_1338893616379_379":{"txaction":"appointed","state_status":"processing"}} {"_1343137411652_652":{"txaction":"appointed","state_status":"processing"}} + {"_payone_status_paypalv2":{"txaction":"appointed","state_status":"processing"}} {"_1338893625332_332":{"txaction":"appointed","state_status":"processing"}} {"_1338893611948_948":{"txaction":"appointed","state_status":"processing"}} {"_1338893618715_715":{"txaction":"appointed","state_status":"pending"},"_1458214328719_719":{"txaction":"paid","state_status":"processing"}} @@ -483,6 +493,13 @@ 1 0 + + 1 + 1 + 0 + gold + rect + 1 diff --git a/etc/di.xml b/etc/di.xml index 23a22313..8d32b7ba 100644 --- a/etc/di.xml +++ b/etc/di.xml @@ -38,6 +38,8 @@ + + payone_protocol_api diff --git a/etc/payment.xml b/etc/payment.xml index 29cd5fc8..fbcdef6e 100644 --- a/etc/payment.xml +++ b/etc/payment.xml @@ -43,6 +43,9 @@ 0 + + 0 + v 0 diff --git a/etc/webapi.xml b/etc/webapi.xml index 325413ba..f835f0eb 100644 --- a/etc/webapi.xml +++ b/etc/webapi.xml @@ -211,4 +211,21 @@ %order_id% + + + + + + + + + + + + + + + %cart_id% + + diff --git a/i18n/de_DE.csv b/i18n/de_DE.csv index 282abbff..89d5a579 100644 --- a/i18n/de_DE.csv +++ b/i18n/de_DE.csv @@ -1048,6 +1048,7 @@ "Desired guarantee time period (max. 15 running days) für a secured ore-order.","Gewünschter Garantiezeitraum (maximal 15 Kalendertage) für eine gesicherte Vorbestellung." "PayPal Express Enabled","PayPal Express aktiviert" +"Show Buy Now Pay Later Button","Später zahlen Button anzeigen" "An error occured during the PayPal Express transaction.","Während der PayPal Express Transaktion ist ein Fehler aufgetreten." "Please sign in to check out.","Bitte loggen Sie sich ein für den Einkauf." "Checkout with PayPal Express","Einkaufen mit PayPal Express" diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml index 39bdb08e..4a5f9d17 100644 --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -64,6 +64,9 @@ true + + true + true diff --git a/view/frontend/layout/default.xml b/view/frontend/layout/default.xml index 5308b4c6..e3d264cb 100644 --- a/view/frontend/layout/default.xml +++ b/view/frontend/layout/default.xml @@ -6,6 +6,9 @@ */ --> + + + diff --git a/view/frontend/templates/paypal/express_buttonv2.phtml b/view/frontend/templates/paypal/express_buttonv2.phtml new file mode 100644 index 00000000..e03b277b --- /dev/null +++ b/view/frontend/templates/paypal/express_buttonv2.phtml @@ -0,0 +1,110 @@ +. + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ + +/** @var \Payone\Core\Block\Paypal\ExpressButtonV2 $block */ +?> +
+ + diff --git a/view/frontend/web/css/payone.css b/view/frontend/web/css/payone.css index 68681141..90082526 100644 --- a/view/frontend/web/css/payone.css +++ b/view/frontend/web/css/payone.css @@ -40,3 +40,7 @@ .payoneBNPLselector { margin-bottom:0.7em; } + +#payone-paypal-button-minibasket { + margin-top: 1em; +} diff --git a/view/frontend/web/js/action/startpaypalexpress.js b/view/frontend/web/js/action/startpaypalexpress.js new file mode 100644 index 00000000..eeec1d94 --- /dev/null +++ b/view/frontend/web/js/action/startpaypalexpress.js @@ -0,0 +1,55 @@ +/** + * PAYONE Magento 2 Connector is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAYONE Magento 2 Connector is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with PAYONE Magento 2 Connector. If not, see . + * + * PHP version 8 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ +/*jshint browser:true jquery:true*/ +/*global alert*/ +define([ + 'jquery', + 'Magento_Checkout/js/model/url-builder', + 'mage/storage', + 'Magento_Checkout/js/model/full-screen-loader', + 'Magento_Customer/js/model/customer' +], function ($, urlBuilder, storage, fullScreenLoader, customer) { + 'use strict'; + return function (quoteId) { + var serviceUrl; + + var request = { + cartId: quoteId + }; + if (!customer.isLoggedIn()) { + serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/payone-startPayPalExpress', { + cartId: quoteId + }); + } else { + serviceUrl = urlBuilder.createUrl('/carts/mine/payone-startPayPalExpress', {}); + } + + fullScreenLoader.startLoader(); + + return storage.post( + serviceUrl, + JSON.stringify(request) + ); + }; +}); diff --git a/view/frontend/web/js/view/payment/method-renderer/paypalv2-method.js b/view/frontend/web/js/view/payment/method-renderer/paypalv2-method.js new file mode 100644 index 00000000..59115cad --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/paypalv2-method.js @@ -0,0 +1,41 @@ +/** + * PAYONE Magento 2 Connector is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * PAYONE Magento 2 Connector is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with PAYONE Magento 2 Connector. If not, see . + * + * PHP version 5 + * + * @category Payone + * @package Payone_Magento2_Plugin + * @author FATCHIP GmbH + * @copyright 2003 - 2024 Payone GmbH + * @license GNU Lesser General Public License + * @link http://www.payone.de + */ +define( + [ + 'Payone_Core/js/view/payment/method-renderer/base' + ], + function (Component) { + 'use strict'; + return Component.extend({ + defaults: { + template: 'Payone_Core/payment/paypalv2' + }, + + /** Returns payment method instructions */ + getInstructions: function () { + return window.checkoutConfig.payment.instructions[this.item.method]; + } + }); + } +); diff --git a/view/frontend/web/js/view/payment/payone-payments.js b/view/frontend/web/js/view/payment/payone-payments.js index 1d7c0217..dd90bfce 100644 --- a/view/frontend/web/js/view/payment/payone-payments.js +++ b/view/frontend/web/js/view/payment/payone-payments.js @@ -48,6 +48,10 @@ define( type: 'payone_paypal', component: 'Payone_Core/js/view/payment/method-renderer/paypal-method' }, + { + type: 'payone_paypalv2', + component: 'Payone_Core/js/view/payment/method-renderer/paypalv2-method' + }, { type: 'payone_advance_payment', component: 'Payone_Core/js/view/payment/method-renderer/advance_payment-method' diff --git a/view/frontend/web/template/payment/paypalv2.html b/view/frontend/web/template/payment/paypalv2.html new file mode 100644 index 00000000..3addc5aa --- /dev/null +++ b/view/frontend/web/template/payment/paypalv2.html @@ -0,0 +1,89 @@ + +
+
+ + +
+ +
+ + + +
+ + + +
+

+
+ + + +
+
+
+ + +
+ +
+ + +
+ + +
+ + +
+
+
+
+ +
+
+
+
From f752dddedf4777d0b00cec550f3d7b845be64e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 28 Oct 2024 16:40:28 +0100 Subject: [PATCH 2/3] MAG2-319 - Changed intent in javascript URL --- Block/Paypal/ExpressButtonV2.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Block/Paypal/ExpressButtonV2.php b/Block/Paypal/ExpressButtonV2.php index 10b1ae8f..0bfb029b 100644 --- a/Block/Paypal/ExpressButtonV2.php +++ b/Block/Paypal/ExpressButtonV2.php @@ -165,13 +165,7 @@ protected function showBNPLButton() */ protected function getIntent() { - $oMethodInstance = $this->getMethodInstance(); - - $sIntent = "authorize"; // authorize = preauthorize - if ($oMethodInstance && $oMethodInstance->getAuthorizationMode() == PayoneConfig::REQUEST_TYPE_AUTHORIZATION) { - $sIntent = "capture"; // capture = authorize - } - return $sIntent; + return "authorize"; // authorize = preauthorize // capture = authorize but Payone said to always use authorize } /** From d927656904d8099dd440a16f40870aee90280d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Mon, 28 Oct 2024 16:43:48 +0100 Subject: [PATCH 3/3] MAG2-319 - Removed debug output --- view/frontend/templates/paypal/express_buttonv2.phtml | 1 - 1 file changed, 1 deletion(-) diff --git a/view/frontend/templates/paypal/express_buttonv2.phtml b/view/frontend/templates/paypal/express_buttonv2.phtml index e03b277b..778d6bee 100644 --- a/view/frontend/templates/paypal/express_buttonv2.phtml +++ b/view/frontend/templates/paypal/express_buttonv2.phtml @@ -98,7 +98,6 @@ // add your actions on cancellation }, onError: function() { - alert("X"); console.log("An Error occurred as part of the PayPal JS SDK"); // add your actions if error occurs }