We will be off from 27/1 (Monday) to 31/1 (Friday) (GMT +7) for our Tet Holiday (Lunar New Year) in our country

Commit 482b60ba authored by rikterbeek's avatar rikterbeek

implmented HPP integration with new settings and notification handler improvements

parent 9acc8eb5
<?php
namespace Adyen\Payment\Block;
use Symfony\Component\Config\Definition\Exception\Exception;
class Redirect extends \Magento\Payment\Block\Form
{
protected $_orderFactory;
/**
* @var \Magento\Checkout\Model\Session
*/
protected $_checkoutSession;
protected $_order;
/**
* Constructor
*
* @param \\Magento\Framework\View\Element\Template\Context $context
* @param array $data
*/
public function __construct(
\Magento\Framework\View\Element\Template\Context $context,
array $data = [],
\Magento\Sales\Model\OrderFactory $orderFactory,
\Magento\Checkout\Model\Session $checkoutSession
)
{
$this->_orderFactory = $orderFactory;
$this->_checkoutSession = $checkoutSession;
parent::__construct($context, $data);
$this->_getOrder();
}
public function _prepareLayout()
{
return parent::_prepareLayout();
}
public function getFormUrl()
{
$result = "";
try {
$order = $this->_order;
if($order->getPayment())
{
$result = $this->_order->getPayment()->getMethodInstance()->getFormUrl();
}
} catch(Exception $e) {
// do nothing for now
}
return $result;
}
public function test() {
$orderId = $this->_checkoutSession->getId();
$orderId = $this->_checkoutSession->getLastOrderId();
return "incrementIdd: " . $orderId;
// return "sdf";
}
public function getFormFields()
{
$result = array();
try {
if($this->_order->getPayment())
{
$result = $this->_order->getPayment()->getMethodInstance()->getFormFields();
}
} catch(Exception $e) {
// do nothing for now
}
return $result;
}
/**
* Get order object
*
* @return \Magento\Sales\Model\Order
*/
protected function _getOrder()
{
if (!$this->_order) {
$incrementId = $this->_getCheckout()->getLastRealOrderId();
$this->_order = $this->_orderFactory->create()->loadByIncrementId($incrementId);
}
return $this->_order;
}
/**
* Get frontend checkout session object
*
* @return \Magento\Checkout\Model\Session
*/
protected function _getCheckout()
{
return $this->_checkoutSession;
}
}
\ No newline at end of file
......@@ -12,8 +12,6 @@ use Symfony\Component\Config\Definition\Exception\Exception;
*/
class Json extends \Magento\Framework\App\Action\Action
{
/**
* @var \Magento\Framework\ObjectManagerInterface
*/
......@@ -24,15 +22,21 @@ class Json extends \Magento\Framework\App\Action\Action
*/
protected $_resultFactory;
/**
* @var \Adyen\Payment\Helper\Data
*/
protected $_adyenHelper;
/**
* @param \Magento\Framework\App\Action\Context $context
*/
public function __construct(
\Magento\Framework\App\Action\Context $context
\Magento\Framework\App\Action\Context $context,
\Adyen\Payment\Helper\Data $adyenHelper
) {
parent::__construct($context);
$this->_objectManager = $context->getObjectManager();
$this->_resultFactory = $context->getResultFactory();
$this->_adyenHelper = $adyenHelper;
}
/**
......@@ -46,9 +50,8 @@ class Json extends \Magento\Framework\App\Action\Action
// check duplicates
try {
// $notificationItems = json_decode(file_get_contents('php://input'), true);
$notificationItems = json_decode('{"live":"false","notificationItems":[{"NotificationRequestItem":{"additionalData":{"expiryDate":"12\/2012"," NAME1 ":"VALUE1","authCode":"1234","cardSummary":"7777","totalFraudScore":"10","hmacSignature":"yGnVWLP+UcpqjHTJbO5IUkG4ZdIk3uHCu62QAJvbbyg=","NAME2":" VALUE2 ","fraudCheck-6-ShopperIpUsage":"10"},"amount":{"currency":"EUR","value":10500},"eventCode":"AUTHORISATION","eventDate":"2015-09-11T13:53:21+02:00","merchantAccountCode":"MagentoMerchantByteShop1","merchantReference":"000000023","operations":["CANCEL","CAPTURE","REFUND"],"paymentMethod":"visa","pspReference":"test_AUTHORISATION_1","reason":"1234:7777:12\/2012","success":"true"}}]}', true);
$notificationItems = json_decode(file_get_contents('php://input'), true);
// $notificationItems = json_decode('{"live":"false","notificationItems":[{"NotificationRequestItem":{"additionalData":{"expiryDate":"12\/2012"," NAME1 ":"VALUE1","authCode":"1234","cardSummary":"7777","totalFraudScore":"10","hmacSignature":"yGnVWLP+UcpqjHTJbO5IUkG4ZdIk3uHCu62QAJvbbyg=","NAME2":" VALUE2 ","fraudCheck-6-ShopperIpUsage":"10"},"amount":{"currency":"EUR","value":10500},"eventCode":"AUTHORISATION","eventDate":"2015-09-11T13:53:21+02:00","merchantAccountCode":"MagentoMerchantByteShop1","merchantReference":"000000023","operations":["CANCEL","CAPTURE","REFUND"],"paymentMethod":"visa","pspReference":"test_AUTHORISATION_1","reason":"1234:7777:12\/2012","success":"true"}}]}', true);
$notificationMode = isset($notificationItems['live']) ? $notificationItems['live'] : "";
......@@ -89,13 +92,12 @@ class Json extends \Magento\Framework\App\Action\Action
*/
protected function _validateNotificationMode($notificationMode)
{
// $mode = $this->_getConfigData('demoMode');
// if ($mode=='Y' && $notificationMode == "false" || $mode=='N' && $notificationMode == 'true') {
// return true;
// }
// return false;
$mode = $this->_adyenHelper->getAdyenAbstractConfigData('demo_mode');
if ($mode=='Y' && $notificationMode == "false" || $mode=='N' && $notificationMode == 'true') {
return true;
}
return false;
}
/**
......@@ -104,6 +106,10 @@ class Json extends \Magento\Framework\App\Action\Action
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _processNotification($response)
{
// validate the notification
if($this->authorised($response))
{
try {
......@@ -145,6 +151,76 @@ class Json extends \Magento\Framework\App\Action\Action
}
}
}
/**
* @desc HTTP Authentication of the notification
* @param $response
*/
protected function authorised($response)
{
// Add CGI support
$this->_fixCgiHttpAuthentication();
$internalMerchantAccount = $this->_adyenHelper->getAdyenAbstractConfigData('merchantAccount');
$username = $this->_adyenHelper->getAdyenAbstractConfigData('notification_username');
$password = $this->_adyenHelper->getNotificationPassword();
$submitedMerchantAccount = $response['merchantAccountCode'];
if (empty($submitedMerchantAccount) && empty($internalMerchantAccount)) {
if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
echo 'merchantAccountCode is empty in magento settings'; exit();
}
return false;
}
// validate username and password
if ((!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']))) {
if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
echo 'Authentication failed: PHP_AUTH_USER and PHP_AUTH_PW are empty. See Adyen Magento manual CGI mode'; exit();
}
return false;
}
$accountCmp = !$this->_adyenHelper->getAdyenAbstractConfigDataFlag('multiple_merchants')
? strcmp($submitedMerchantAccount, $internalMerchantAccount)
: 0;
$usernameCmp = strcmp($_SERVER['PHP_AUTH_USER'], $username);
$passwordCmp = strcmp($_SERVER['PHP_AUTH_PW'], $password);
if ($accountCmp === 0 && $usernameCmp === 0 && $passwordCmp === 0) {
return true;
}
// If notification is test check if fields are correct if not return error
if(strtolower(substr($response['pspReference'],0,17)) == "testnotification_" || strtolower(substr($response['pspReference'],0,5)) == "test_") {
if($accountCmp != 0) {
echo 'MerchantAccount in notification is not the same as in Magento settings'; exit();
} elseif($usernameCmp != 0 || $passwordCmp != 0) {
echo 'username (PHP_AUTH_USER) and\or password (PHP_AUTH_PW) are not the same as Magento settings'; exit();
}
}
return false;
}
/**
* Fix these global variables for the CGI
*/
protected function _fixCgiHttpAuthentication() { // unsupported is $_SERVER['REMOTE_AUTHORIZATION']: as stated in manual :p
if (isset($_SERVER['REDIRECT_REMOTE_AUTHORIZATION']) && $_SERVER['REDIRECT_REMOTE_AUTHORIZATION'] != '') { //pcd note: no idea who sets this
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode($_SERVER['REDIRECT_REMOTE_AUTHORIZATION']));
} elseif(!empty($_SERVER['HTTP_AUTHORIZATION'])){ //pcd note: standard in magento?
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
} elseif (!empty($_SERVER['REMOTE_USER'])) { //pcd note: when cgi and .htaccess modrewrite patch is executed
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REMOTE_USER'], 6)));
} elseif (!empty($_SERVER['REDIRECT_REMOTE_USER'])) { //pcd note: no idea who sets this
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REDIRECT_REMOTE_USER'], 6)));
}
}
/**
*
*/
......
......@@ -31,6 +31,14 @@ class Redirect extends \Magento\Framework\App\Action\Action
*/
protected $_customerSession;
protected $_order;
/**
* @var \Magento\Sales\Model\OrderFactory
*/
protected $_orderFactory;
/**
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Customer\Model\Session $customerSession
......@@ -56,14 +64,62 @@ class Redirect extends \Magento\Framework\App\Action\Action
public function execute()
{
$this->_getQuote();
echo 'hier;';die();
$this->_quote->collectTotals();
echo 'hier';die();
$url = "http://www.google.com";
$this->getResponse()->setRedirect($url);
return;
// $session->clearQuote();
$this->_view->loadLayout();
$this->_view->getLayout()->initMessages();
$this->_view->renderLayout();
// \Magento\Quote\Model\QuoteManagement $quoteManagement
//$this->_checkout->place($this->_initToken());
// $order = $this->quoteManagement->submit($this->_quote);
// $orderId = $this->_getCheckout()->getLastOrderId();
//
// $order = $this->_getOrder();
//
// $payment = $order->getPayment()->getMethodInstance();
//
// echo $payment->getCode();die();
//
//
//echo $order->getId();
// die();
//
// $quote->collectTotals();
//
//// print_r($quote->getPayment());die();
//
// //$this->_quote->collectTotals();
//// $order = $this->quoteManagement->submit($this->_quote);
////\Magento\Quote\Model\QuoteManagement $quoteManagement
//
//// $this->_getQuoteManagement()->submit($quote);
//
//
////echo 'test';
//// print_r($this->_getQuote()->getBillingAddress()->getFirstname());die();
//
//// echo $quote->getBillingAddress()->getFirstname();
////// echo $quote->getShippingAddress()->getFirstname();
//// die();
//
// $this->_getQuoteManagement()->placeOrder($quote->getId());
//
// // $this->cartManagement->placeOrder($this->_getCheckout()->getQuote()->getId());
//
//
//// $this->getOrder();
//
//// echo $quote->getId();
//// echo 'hier;';die();
//// $this->_quote->collectTotals();
////
////echo 'hier';die();
// $url = "http://www.google.com";
// $this->getResponse()->setRedirect($url);
// return;
......@@ -74,15 +130,36 @@ echo 'hier';die();
}
/**
* Return checkout quote object
* Get order object
*
* @return \Magento\Quote\Model\Quote
* @return \Magento\Sales\Model\Order
*/
protected function _getOrder()
{
if (!$this->_order) {
$incrementId = $this->_getCheckout()->getLastRealOrderId();
$this->_orderFactory = $this->_objectManager->get('Magento\Sales\Model\OrderFactory');
$this->_order = $this->_orderFactory->create()->loadByIncrementId($incrementId);
}
return $this->_order;
}
/**
* @return \Magento\Checkout\Model\Session
*/
protected function _getCheckout()
{
return $this->_objectManager->get('Magento\Checkout\Model\Session');
}
protected function _getQuote()
{
if (!$this->_quote) {
$this->_quote = $this->_getCheckoutSession()->getQuote();
return $this->_objectManager->get('Magento\Quote\Model\Quote');
}
return $this->_quote;
protected function _getQuoteManagement()
{
return $this->_objectManager->get('\Magento\Quote\Model\QuoteManagement');
}
}
\ No newline at end of file
<?php
namespace Adyen\Payment\Controller\Process;
use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
class Result extends \Magento\Framework\App\Action\Action
{
protected $_adyenHelper;
protected $_orderFactory;
protected $_order;
/**
* @var \Magento\Sales\Model\Order\Status\HistoryFactory
*/
protected $_orderHistoryFactory;
protected $_session;
/**
* @param \Magento\Framework\App\Action\Context $context
* @param \Magento\Customer\Model\Session $customerSession
* @param CustomerRepositoryInterface $customerRepository
* @param AccountManagementInterface $accountManagement
*/
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Sales\Model\OrderFactory $orderFactory,
\Magento\Sales\Model\Order\Status\HistoryFactory $orderHistoryFactory,
\Magento\Checkout\Model\Session $session
) {
$this->_adyenHelper = $adyenHelper;
$this->_orderFactory = $orderFactory;
$this->_orderHistoryFactory = $orderHistoryFactory;
$this->_session = $session;
parent::__construct($context);
}
public function execute()
{
$response = $this->getRequest()->getParams();
$result = $this->validateResponse($response);
if ($result) {
$session = $this->_session;
$session->getQuote()->setIsActive(false)->save();
$this->_redirect('checkout/onepage/success');
} else {
$this->_cancel($response);
$this->_redirect('checkout/cart');
}
}
protected function _cancel($response)
{
$session = $this->_session;
// restore the quote
$session->restoreQuote();
$order = $this->_order;
$orderStatus = $this->_adyenHelper->getAdyenAbstractConfigData('payment_cancelled');
$order->setActionFlag($orderStatus, true);
switch ($orderStatus) {
case \Magento\Sales\Model\Order::STATE_HOLDED:
if ($order->canHold()) {
$order->hold()->save();
}
break;
default:
if($order->canCancel()) {
$order->cancel()->save();
}
break;
}
if(isset($response['authResult']) && $response['authResult'] == \Adyen\Payment\Model\Notification::CANCELLED) {
$this->messageManager->addError(__('You have cancelled the order. Please try again'));
} else {
$this->messageManager->addError(__('Your payment failed, Please try again later'));
}
}
protected function validateResponse($response)
{
$result = true;
$this->_debugData['Step1'] = 'Processing ResultUrl';
$storeId = null;
if (empty($response)) {
$this->_debugData['error'] = 'Response is empty, please check your webserver that the result url accepts parameters';
throw new \Magento\Framework\Exception\LocalizedException(__('Response is empty, please check your webserver that the result url accepts parameters'));
}
// Log the results in log file and adyen_debug table
$this->_debugData['response'] = $response;
// authenticate result url
$authStatus = $this->_authenticate($response);
if (!$authStatus) {
throw new \Magento\Framework\Exception\LocalizedException(__('ResultUrl authentification failure'));
}
$incrementId = $response['merchantReference'];
if($incrementId) {
$order = $this->_getOrder($incrementId);
if ($order->getId()) {
$this->_eventManager->dispatch('adyen_payment_process_resulturl_before', [
'order' => $order,
'adyen_response' => $response
]);
if (isset($response['handled'])) {
return;
}
// set StoreId for retrieving debug log setting
$storeId = $order->getStoreId();
// update the order
$result = $this->_validateUpdateOrder($order, $response);
$this->_eventManager->dispatch('adyen_payment_process_resulturl_after', [
'order' => $order,
'adyen_response' => $response
]);
} else {
throw new \Magento\Framework\Exception\LocalizedException(__('Order does not exists with increment_id: %s1', $incrementId));
}
} else {
Mage::throwException(
Mage::helper('adyen')->__('Empty merchantReference')
);
}
return $result;
}
/**
* @param $order
* @param $params
*/
protected function _validateUpdateOrder($order, $response)
{
$result = false;
$this->_debugData['Step2'] = 'Updating the order';
$authResult = $response['authResult'];
$paymentMethod = isset($response['paymentMethod']) ? trim($response['paymentMethod']) : '';
$pspReference = isset($response['pspReference']) ? trim($response['pspReference']) : '';
$type = 'Adyen Result URL Notification(s):';
$comment = __('%1 <br /> authResult: %2 <br /> pspReference: %3 <br /> paymentMethod: %4', $type, $authResult, $pspReference, $paymentMethod);
$history = $this->_orderHistoryFactory->create()
//->setStatus($status)
->setComment($comment)
->setEntityName('order')
->setOrder($order)
;
$history->save();
switch ($authResult) {
case \Adyen\Payment\Model\Notification::AUTHORISED:
case \Adyen\Payment\Model\Notification::PENDING:
// do nothing wait for the notification
$result = true;
$this->_debugData['Step4'] = 'Do nothing wait for the notification';
break;
case \Adyen\Payment\Model\Notification::CANCELLED:
$this->_debugData['Step4'] = 'Cancel or Hold the order';
$result = false;
break;
case \Adyen\Payment\Model\Notification::REFUSED:
// if refused there will be a AUTHORIZATION : FALSE notification send only exception is ideal
$this->_debugData['Step4'] = 'Cancel or Hold the order';
$result = false;
break;
case \Adyen\Payment\Model\Notification::ERROR:
//attempt to hold/cancel
$this->_debugData['Step4'] = 'Cancel or Hold the order';
$result = false;
break;
default:
$this->_debugData['error'] = 'This event is not supported: ' . $authResult;
$result = false;
break;
}
return $result;
}
/**
* @desc Authenticate using sha1 Merchant signature
* @see success Action during checkout
* @param Varien_Object $response
*/
protected function _authenticate($response) {
$hmacKey = $this->_adyenHelper->getHmac();
// do not include the merchantSig in the merchantSig calculation
$merchantSigNotification = $response['merchantSig'];
unset($response['merchantSig']);
// Sort the array by key using SORT_STRING order
ksort($response, SORT_STRING);
// Generate the signing data string
$signData = implode(":",array_map(array($this, 'escapeString'),array_merge(array_keys($response), array_values($response))));
$merchantSig = base64_encode(hash_hmac('sha256',$signData,pack("H*" , $hmacKey),true));
if (strcmp($merchantSig, $merchantSigNotification) === 0) {
return true;
}
return false;
}
/*
* @desc The character escape function is called from the array_map function in _signRequestParams
* $param $val
* return string
*/
protected function escapeString($val)
{
return str_replace(':','\\:',str_replace('\\','\\\\',$val));
}
protected function _getOrder($incrementId)
{
if (!$this->_order) {
$this->_order = $this->_orderFactory->create()->loadByIncrementId($incrementId);
}
return $this->_order;
}
}
\ No newline at end of file
......@@ -20,17 +20,21 @@ class Data extends AbstractHelper
*/
protected $_scopeConfig;
protected $_encryptor;
/**
* @param Context $context
*/
public function __construct(
\Magento\Framework\App\Helper\Context $context,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Encryption\EncryptorInterface $encryptor
)
{
parent::__construct($context);
$this->_scopeConfig = $scopeConfig;
$this->_encryptor = $encryptor;
}
......@@ -57,6 +61,13 @@ class Data extends AbstractHelper
];
}
public function getPaymentRoutines() {
return [
'single' => 'Single Page Payment Routine',
'multi' => 'Multi-page Payment Routine'
];
}
/**
* Return the formatted currency. Adyen accepts the currency in multiple formats.
* @param $amount
......@@ -173,6 +184,30 @@ class Data extends AbstractHelper
return $this->getConfigData($field, 'adyen_hpp', $storeId, true);
}
public function getHmac()
{
switch ($this->isDemoMode()) {
case true:
$secretWord = $this->_encryptor->decrypt(trim($this->getAdyenHppConfigData('hmac_test')));
break;
default:
$secretWord = $this->_encryptor->decrypt(trim($this->getAdyenHppConfigData('hmac_live')));
break;
}
return $secretWord;
}
public function isDemoMode()
{
return $this->getAdyenAbstractConfigDataFlag('demo_mode');
}
public function getNotificationPassword()
{
return $this->_encryptor->decrypt(trim($this->getAdyenAbstractConfigData('notification_password')));
}
/**
* Retrieve information from payment configuration
*
......
<?php
namespace Adyen\Payment\Model\Config\Source;
/**
* Order Statuses source model
*/
class Complete extends \Magento\Sales\Model\Config\Source\Order\Status
{
/**
* @var string[]
*/
protected $_stateStatuses = [
\Magento\Sales\Model\Order::STATE_COMPLETE
];
}
<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
/**
* Order Statuses source model
*/
namespace Adyen\Payment\Model\Config\Source;
class PaymentRoutine implements \Magento\Framework\Option\ArrayInterface
{
/**
* @var \Magento\Sales\Model\Order\Config
*/
protected $_orderConfig;
protected $_adyenHelper;
/**
* @param \Magento\Sales\Model\Order\Config $orderConfig
*/
public function __construct(
\Magento\Sales\Model\Order\Config $orderConfig,
\Adyen\Payment\Helper\Data $adyenHelper
)
{
$this->_orderConfig = $orderConfig;
$this->_adyenHelper = $adyenHelper;
}
/**
* @return array
*/
public function toOptionArray()
{
$recurringTypes = $this->_adyenHelper->getPaymentRoutines();
foreach ($recurringTypes as $code => $label) {
$options[] = ['value' => $code, 'label' => $label];
}
return $options;
}
}
......@@ -275,9 +275,15 @@ class Cron
$this->_fraudManualReview = false;
}
// modification.action is it for JSON
$modificationActionJson = isset($additionalData['modification.action']) ? $additionalData['modification.action'] : null;
if($modificationActionJson != "") {
$this->_modificationResult = $modificationActionJson;
}
$modification = isset($additionalData['modification']) ? $additionalData['modification'] : null;
if($modification && is_array($modification)) {
$this->_modificationResult = isset($valueArray['action']) ? trim($modification['action']) : "";
$this->_modificationResult = isset($modification['action']) ? trim($modification['action']) : "";
}
$additionalData2 = isset($additionalData['additionalData']) ? $additionalData['additionalData'] : null;
if($additionalData2 && is_array($additionalData2)) {
......
......@@ -23,6 +23,11 @@ class Hpp extends \Magento\Payment\Model\Method\AbstractMethod implements Gatewa
*/
protected $_code = self::METHOD_CODE;
/**
* @var GUEST_ID , used when order is placed by guests
*/
const GUEST_ID = 'customer_';
/**
* Payment Method feature
......@@ -33,6 +38,15 @@ class Hpp extends \Magento\Payment\Model\Method\AbstractMethod implements Gatewa
protected $_canAuthorize = true;
protected $_isInitializeNeeded = true;
protected $_adyenHelper;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
......@@ -48,6 +62,8 @@ class Hpp extends \Magento\Payment\Model\Method\AbstractMethod implements Gatewa
*/
public function __construct(
\Magento\Framework\UrlInterface $urlBuilder,
\Adyen\Payment\Helper\Data $adyenHelper,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
......@@ -72,6 +88,8 @@ class Hpp extends \Magento\Payment\Model\Method\AbstractMethod implements Gatewa
$data
);
$this->_urlBuilder = $urlBuilder;
$this->_adyenHelper = $adyenHelper;
$this->storeManager = $storeManager;
}
public function isAvailable($quote = null)
......@@ -153,4 +171,148 @@ class Hpp extends \Magento\Payment\Model\Method\AbstractMethod implements Gatewa
$this->_logger->critical("postRequest");
// TODO: Implement postRequest() method.
}
/**
* @desc Get url of Adyen payment
* @return string
* @todo add brandCode here
*/
public function getFormUrl()
{
// $brandCode = $this->getInfoInstance()->getCcType();
$paymentRoutine = $this->getConfigData('payment_routine');
switch ($this->_adyenHelper->isDemoMode()) {
case true:
if ($paymentRoutine == 'single' && $this->getPaymentMethodSelectionOnAdyen()) {
$url = 'https://test.adyen.com/hpp/pay.shtml';
} else {
$url = ($this->getPaymentMethodSelectionOnAdyen())
? 'https://test.adyen.com/hpp/select.shtml'
: "https://test.adyen.com/hpp/details.shtml";
}
break;
default:
if ($paymentRoutine == 'single' && $this->getPaymentMethodSelectionOnAdyen()) {
$url = 'https://live.adyen.com/hpp/pay.shtml';
} else {
$url = ($this->getPaymentMethodSelectionOnAdyen())
? 'https://live.adyen.com/hpp/select.shtml'
: "https://live.adyen.com/hpp/details.shtml";
}
break;
}
//IDEAL
// $idealBankUrl = false;
// $bankData = $this->getInfoInstance()->getPoNumber();
// if ($brandCode == 'ideal' && !empty($bankData)) {
// $idealBankUrl = ($isConfigDemoMode == true)
// ? 'https://test.adyen.com/hpp/redirectIdeal.shtml'
// : 'https://live.adyen.com/hpp/redirectIdeal.shtml';
// }
// return (!empty($idealBankUrl)) ? $idealBankUrl : $url;
return $url;
}
public function getFormFields()
{
$paymentInfo = $this->getInfoInstance();
$order = $paymentInfo->getOrder();
$realOrderId = $order->getRealOrderId();
$orderCurrencyCode = $order->getOrderCurrencyCode();
$skinCode = trim($this->getConfigData('skin_code'));
$amount = $this->_adyenHelper->formatAmount($order->getGrandTotal(), $orderCurrencyCode);
$merchantAccount = trim($this->_adyenHelper->getAdyenAbstractConfigData('merchant_account'));
$shopperEmail = $order->getCustomerEmail();
$customerId = $order->getCustomerId();
$shopperIP = $order->getRemoteIp();
$browserInfo = $_SERVER['HTTP_USER_AGENT'];
$deliveryDays = 5;
// $shopperLocale = trim($this->_getConfigData('shopperlocale'));
// $shopperLocale = (!empty($shopperLocale)) ? $shopperLocale : Mage::app()->getLocale()->getLocaleCode();
// $countryCode = trim($this->_getConfigData('countryCode'));
// $countryCode = (!empty($countryCode)) ? $countryCode : false;
$countryCode = false;
// if directory lookup is enabled use the billingadress as countrycode
if ($countryCode == false) {
if ($order->getBillingAddress() && $order->getBillingAddress()->getCountryId() != "") {
$countryCode = $order->getBillingAddress()->getCountryId();
}
}
$formFields = array();
$formFields['merchantAccount'] = $merchantAccount;
$formFields['merchantReference'] = $realOrderId;
$formFields['paymentAmount'] = (int)$amount;
$formFields['currencyCode'] = $orderCurrencyCode;
$formFields['shipBeforeDate'] = date(
"Y-m-d",
mktime(date("H"), date("i"), date("s"), date("m"), date("j") + $deliveryDays, date("Y"))
);
$formFields['skinCode'] = $skinCode;
// $formFields['shopperLocale'] = $shopperLocale;
$formFields['countryCode'] = $countryCode;
$formFields['shopperIP'] = $shopperIP;
$formFields['browserInfo'] = $browserInfo;
$formFields['sessionValidity'] = date(
DATE_ATOM,
mktime(date("H") + 1, date("i"), date("s"), date("m"), date("j"), date("Y"))
);
$formFields['shopperEmail'] = $shopperEmail;
// recurring
$recurringType = trim($this->_adyenHelper->getAdyenAbstractConfigData('recurring_type'));
$formFields['recurringContract'] = $recurringType;
$formFields['shopperReference'] = (!empty($customerId)) ? $customerId : self::GUEST_ID . $realOrderId;
//blocked methods
$formFields['blockedMethods'] = "";
$baseUrl = $this->storeManager->getStore($this->getStore())
->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_LINK);
$formFields['resURL'] = $baseUrl . 'adyen/process/result';
// echo $adyFields['resURL'];die();
// $password = Mage::helper('core')->decrypt($this->_getConfigData('notification_password'));
$hmacKey = $this->_adyenHelper->getHmac();
$brandCode = $this->getInfoInstance()->getCcType();
if($brandCode) {
$formFields['brandCode'] = $brandCode;
}
// Sort the array by key using SORT_STRING order
ksort($formFields, SORT_STRING);
// Generate the signing data string
$signData = implode(":",array_map(array($this, 'escapeString'),array_merge(array_keys($formFields), array_values($formFields))));
$merchantSig = base64_encode(hash_hmac('sha256',$signData,pack("H*" , $hmacKey),true));
$formFields['merchantSig'] = $merchantSig;
return $formFields;
}
/*
* @desc The character escape function is called from the array_map function in _signRequestParams
* $param $val
* return string
*/
protected function escapeString($val)
{
return str_replace(':','\\:',str_replace('\\','\\\\',$val));
}
public function getPaymentMethodSelectionOnAdyen() {
return $this->getConfigData('payment_selection_on_adyen');
}
}
\ No newline at end of file
......@@ -16,6 +16,9 @@
<include path="Adyen_Payment::system/adyen_getting_started.xml"/>
<include path="Adyen_Payment::system/adyen_required_settings.xml"/>
<include path="Adyen_Payment::system/adyen_advanced_order_processing.xml"/>
<include path="Adyen_Payment::system/adyen_advanced_notifications.xml"/>
<include path="Adyen_Payment::system/adyen_billing_agreements.xml"/>
<include path="Adyen_Payment::system/adyen_cc.xml"/>
<include path="Adyen_Payment::system/adyen_hpp.xml"/>
......
<?xml version="1.0"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../Magento/Config/etc/system_include.xsd">
<group id="adyen_advanced_notifications" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label><![CDATA[Advanced: Adyen Payment Notifications]]></label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
<field id="ignore_refund_notification" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Ignore refund notification</label>
<tooltip>If the refund is done on the Adyen Platform it will send a refund notification to Magento which automatically creates a credit memo. If you set this setting to 'Yes', this will not happen because it will not process any of the REFUND notification that is received.</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/ignore_refund_notification</config_path>
</field>
<field id="multiple_merchants" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Allow multiple merchants</label>
<tooltip><![CDATA[Allow notifications sent from other Adyen merchant accounts. Keep in mind that the Notification user name and password should be the same for all the merchant accounts]]></tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/multiple_merchants</config_path>
</field>
</group>
</include>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../Magento/Config/etc/system_include.xsd">
<group id="adyen_advanced_order_processing" translate="label" type="text" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label><![CDATA[Advanced: Magento Order Processing]]></label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
<field id="paypal_capture_mode" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Use manual capture for PayPal</label>
<tooltip>Should be on 'No' by default. If you have requested with Adyen Support for your PayPal integration to be on manual capture, set this to 'Yes'.</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/paypal_capture_mode</config_path>
</field>
<field id="auto_capture_openinvoice" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Use auto-capture for OpenInvoice payments</label>
<tooltip>Applicable for Klarna and AfterPay only. By default OpenInvoice is set to manual capture. If you want auto capture you need to contact magento@adyen.com. After approval has been given, then you can set this option to 'Yes'.</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/auto_capture_openinvoice</config_path>
</field>
<field id="payment_authorized_virtual" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Order status: payment capture (virtual products)</label>
<tooltip>(optional) Select only status assigned to state complete. Leave empty to use the same as normal products</tooltip>
<source_model>Adyen\Payment\Model\Config\Source\Complete</source_model>
<config_path>payment/adyen_abstract/payment_authorized_virtual</config_path>
</field>
<field id="pending_status" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Order status: pending Bank Transfer/SEPA orders</label>
<tooltip>By default, Adyen does not inform your Magento store about pending payments. If you want these notifications to be received, Go to Adyen Customer Area => Server Communication and add BankTransfer Pending Notification and Direct-Debit Pending Notification.</tooltip>
<source_model>Magento\Sales\Model\Config\Source\Order\Status\NewStatus</source_model>
<config_path>payment/adyen_abstract/pending_status</config_path>
</field>
<field id="send_email_bank_sepa_on_pending" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Send order confirmation email for Bank Transfer/SEPA</label>
<tooltip>Send a confirmation mail after Bank Tranfer/SEPA is placed (not yet paid). If you want these notifications to be received, Go to Adyen Customer Area => Server Communication and add BankTransfer Pending Notification and Direct-Debit Pending Notification.</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_abstract/send_email_bank_sepa_on_pending</config_path>
</field>
</group>
</include>
\ No newline at end of file
<?xml version="1.0"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<include xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../Magento/Config/etc/system_include.xsd">
<group id="adyen_billing_agreements" translate="label" type="text" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label><![CDATA[Advanced: Billing Agreements]]></label>
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>
<comment>
<![CDATA[
<p>
<strong>ONECLICK</strong>: The shopper opts in to storing their card details for future use.
The shopper is present for the subsequent transaction, for cards the security code (CVC/CVV) is required.
</p>
<p>
<strong>RECURRING*</strong>: Payment details are stored for future use. For cards, the security
code (CVC/CVV) is not required for subsequent payments.
</p>
<p>
<strong>ONECLICK, RECURRING*</strong>: Payment details are stored for future use. This allows the use of
the stored payment details regardless of whether the shopper is on your site or not.
</p>
<p>* keep in mind you need the recurring permission enabled. You can contact magento@adyen.com to enable this for your account.
]]>
</comment>
<field id="recurring_type" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Agreement Type</label>
<tooltip>When enabled, users can save their Credit Cards and their SEPA authorizations. ONECLICK will require the input of the CVC for subsequent payments, while RECURRING does not.</tooltip>
<source_model>Adyen\Payment\Model\Config\Source\RecurringType</source_model>
<config_path>payment/adyen_abstract/recurring_type</config_path>
</field>
</group>
</include>
\ No newline at end of file
......@@ -29,6 +29,40 @@
<frontend_class>validate-number</frontend_class>
<config_path>payment/adyen_hpp/sort_order</config_path>
</field>
<field id="skin_code" translate="label" type="text" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Skin Code</label>
<tooltip>Copy and paste the skin code of the skin you want to use from Test Customer Area => Skins.</tooltip>
<config_path>payment/adyen_hpp/skin_code</config_path>
</field>
<field id="hmac_test" translate="label" type="obscure" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
<label>HMAC Key for Test</label>
<tooltip>Copy and paste the HMAC key of the skin you want to use from Test Customer Area => Skins. => click on [skin code] => Edit => HMAC for Test platform. Currently, only the older SHA-1 HMAC calculation method is supported in this plugin.</tooltip>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>payment/adyen_hpp/hmac_test</config_path>
</field>
<field id="hmac_live" translate="label" type="obscure" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="1">
<label>HMAC Key for Live</label>
<tooltip>Copy and paste the HMAC key of the skin you want to use from Test Customer Area => Skins. => click on [skin code] => Edit => HMAC for Live platform. Currently, only the older SHA-1 HMAC calculation method is supported in this plugin.</tooltip>
<backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model>
<config_path>payment/adyen_hpp/hmac_live</config_path>
</field>
<field id="payment_selection_on_adyen" translate="label" type="select" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0">
<label>Payment method selection in Adyen</label>
<tooltip>If you set this to 'Yes', payment methods in the checkout won't be displayed and you will be redirected to the Adyen HPP to make the selection.</tooltip>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
<config_path>payment/adyen_hpp/payment_selection_on_adyen</config_path>
</field>
<field id="payment_routine" translate="label" type="select" sortOrder="80" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Payment Flow Selection</label>
<tooltip>Adyen provides you with 2 types of payment routines. The Single-Page flow is dynamic and contains card validation and animations powered by JavaScript. The Multi-Page flow is static, but performs better on older browsers.</tooltip>
<source_model>Adyen\Payment\Model\Config\Source\PaymentRoutine</source_model>
<depends><field id="payment_selection_on_adyen">1</field></depends>
<config_path>payment/adyen_hpp/payment_routine</config_path>
</field>
<group id="adyen_cc_country_specific" translate="label" showInDefault="1" showInWebsite="1" sortOrder="210">
<label>Country Specific Settings</label>
......
......@@ -31,6 +31,8 @@
<model>Adyen\Payment\Model\Method\Hpp</model>
<order_status>pending</order_status>
<title>Adyen HPP</title>
<payment_selection_on_adyen>1</payment_selection_on_adyen>
<payment_routine>single</payment_routine>
<recurring_type>ONECLICK</recurring_type>
<allowspecific>0</allowspecific>
<sort_order>10</sort_order>
......
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/layout_generic.xsd">
<container name="root">
<block class="Adyen\Payment\Block\Redirect" name="adyen-form" template="form.phtml" cacheable="false"/>
</container>
</layout>
\ No newline at end of file
<?php
?>
<html>
<head>
</head>
<body>
<form id="adyen_form" method="POST" action="<?php echo $block->getFormUrl()?>">
<?php
foreach($block->getFormFields() as $field => $value) {
echo '<input type="hidden" name="' .htmlspecialchars($field, ENT_COMPAT | ENT_HTML401 ,'UTF-8').
'" value="' .htmlspecialchars($value, ENT_COMPAT | ENT_HTML401 ,'UTF-8') . '" />';
}
?>
</form>
<script>
document.getElementById('adyen_form').submit();
</script>
</body>
</html>
......@@ -14,30 +14,68 @@ define(
function ($, quote, urlBuilder, storage, errorProcessor, customer) {
'use strict';
//return function () {
// var serviceUrl,
// payload,
// paymentData = quote.paymentMethod();
//
// /**
// * Checkout for guest and registered customer.
// */
// if (!customer.isLoggedIn()) {
// serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/selected-payment-method', {
// cartId: quote.getQuoteId()
// });
// payload = {
// cartId: quote.getQuoteId(),
// method: paymentData
// };
// } else {
// serviceUrl = urlBuilder.createUrl('/carts/mine/selected-payment-method', {});
// payload = {
// cartId: quote.getQuoteId(),
// method: paymentData
// };
// }
// return storage.put(
// serviceUrl, JSON.stringify(payload)
// ).done(
// function () {
// $.mage.redirect(window.checkoutConfig.payment.adyenHpp.redirectUrl[quote.paymentMethod().method]);
// }
// ).fail(
// function (response) {
// errorProcessor.process(response);
// }
// );
//};
return function () {
var serviceUrl,
payload,
paymentData = quote.paymentMethod();
/**
* Checkout for guest and registered customer.
*/
/** Checkout for guest and registered customer. */
if (!customer.isLoggedIn()) {
serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/selected-payment-method', {
cartId: quote.getQuoteId()
serviceUrl = urlBuilder.createUrl('/guest-carts/:quoteId/payment-information', {
quoteId: quote.getQuoteId()
});
payload = {
cartId: quote.getQuoteId(),
method: paymentData
email: quote.guestEmail,
paymentMethod: paymentData,
billingAddress: quote.billingAddress()
};
} else {
serviceUrl = urlBuilder.createUrl('/carts/mine/selected-payment-method', {});
serviceUrl = urlBuilder.createUrl('/carts/mine/payment-information', {});
payload = {
cartId: quote.getQuoteId(),
method: paymentData
paymentMethod: paymentData,
billingAddress: quote.billingAddress()
};
}
return storage.put(
return storage.post(
serviceUrl, JSON.stringify(payload)
).done(
function () {
......
......@@ -13,6 +13,11 @@
<label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
</div>
<div class="payment-method-content">
<div class="payment-method-billing-address">
<!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
<!-- ko template: getTemplate() --><!-- /ko -->
<!--/ko-->
</div>
<fieldset class="fieldset" data-bind='attr: {id: "payment_form_" + getCode()}'>
<div class="payment-method-note">
<!-- ko text: $t('You will be redirected to the Adyen website.') --><!-- /ko -->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment