We will work on Apr 26th (Saturday) and will be off from Apr 30th (Wednesday) until May 2nd (Friday) for public holiday in our country

Commit ab1b5e67 authored by Tuan's avatar Tuan

First commit

parents
<?php
namespace MR\Zip\Api;
/**
* Payment method management interface for guest carts.
* @api
*/
interface GuestZipManagementInterface
{
/**
* Add a specified payment method to a specified shopping cart.
*
* @param string $cartId The cart ID.
* @param string $email
* @param \Magento\Quote\Api\Data\PaymentInterface $method The payment method.
* @param \Magento\Quote\Api\Data\AddressInterface $billingAddress
* @return string
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified cart does not exist.
* @throws \Magento\Framework\Exception\State\InvalidTransitionException The billing or shipping address
* is not set, or the specified payment method is not available.
*/
public function set($cartId, $email, \Magento\Quote\Api\Data\PaymentInterface $method, \Magento\Quote\Api\Data\AddressInterface $billingAddress = null);
}
<?php
namespace MR\Zip\Api;
interface ZipManagementInterface
{
/**
* Add a specified payment method to a specified shopping cart.
*
* @param string $cartId The cart ID.
* @param \Magento\Quote\Api\Data\PaymentInterface $method The payment method.
* @return string
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified cart does not exist.
* @throws \Magento\Framework\Exception\State\InvalidTransitionException The billing or shipping address
* is not set, or the specified payment method is not available.
*/
public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method, \Magento\Quote\Api\Data\AddressInterface $billingAddress = null);
}
<?php
namespace MR\Zip\Block;
use Magento\Framework\View\Element\Template\Context;
class Error extends \Magento\Framework\View\Element\Template
{
public function __construct(Context $context, array $data = [])
{
parent::__construct($context, $data);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
protected function _prepareLayout()
{
$this->setShowContinueButton(true);
$error = $this->getRequest()->getParam("error");
$this->_logger->info(__METHOD__ . " error:{$error}");
$this->setError($error);
return $this;
}
}
<?php
namespace MR\Zip\Block;
use Magento\Framework\View\Element\Template\Context;
class Info extends \Magento\Payment\Block\Info
{
/**
*
* @var string
*/
protected $_template = 'MR_Zip::info/default.phtml';
public function __construct(Context $context, array $data = [])
{
parent::__construct($context, $data);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
protected function _prepareSpecificInformation($transport = null)
{
$this->_logger->info(__METHOD__);
if (null !== $this->_paymentSpecificInformation) {
return $this->_paymentSpecificInformation;
}
$data = $this->getInfo()->getAdditionalInformation();
$decodedData = [];
foreach ($data as $key => $value) {
if (in_array($key, ['items', 'billing', 'shipping', 'merchant'])) {
continue;
}
if (strtotime($key)) {
$decodedValue = json_decode($value, true);
if (!$decodedValue) {
$decodedData[$key] = $this->getValueAsArray($value, true);
} else {
$decodedData[$key] = $decodedValue;
}
}
else {
$decodedData[$key] = $value;
}
}
$transport = parent::_prepareSpecificInformation($transport);
$this->_paymentSpecificInformation = $transport->setData(array_merge($decodedData, $transport->getData()));
return $this->_paymentSpecificInformation;
}
}
<?php
namespace MR\Zip\Block;
class Processed extends \Magento\Framework\View\Element\Template
{
}
<?php
namespace MR\Zip\Block\Widget;
use Magento\Framework\View\Element\Template\Context;
class Cart extends \Magento\Framework\View\Element\Template
{
/**
* @var $_paymentUtil \MR\Zip\Helper\PaymentUtil
*/
protected $_paymentUtil;
/**
* @var $_checkoutSession \Magento\Checkout\Model\Session
*/
protected $_checkoutSession;
public function __construct(
Context $context,
\Magento\Checkout\Model\Session $checkoutSession,
array $data = [])
{
parent::__construct($context, $data);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_paymentUtil = $objectManager->get("\MR\Zip\Helper\PaymentUtil");
$this->_checkoutSession = $checkoutSession;
$this->_logger->info(__METHOD__);
}
public function getCartWidgetHtml()
{
$quote = $this->_checkoutSession->getQuote();
return $this->_paymentUtil->getWidgetHtml($quote->getGrandTotal());
}
}
<?php
namespace MR\Zip\Block\Widget;
use Magento\Framework\View\Element\Template\Context;
class Product extends \Magento\Framework\View\Element\Template
{
/**
* @var $_paymentUtil \MR\Zip\Helper\PaymentUtil
*/
protected $_paymentUtil;
/**
* @var \Magento\Framework\Registry
*/
protected $_coreRegistry;
/**
* @var \Magento\Catalog\Api\ProductRepositoryInterface
*/
protected $_productRepository;
public function __construct(
Context $context,
\Magento\Framework\Registry $registry,
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
array $data = []
){
parent::__construct($context, $data);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_paymentUtil = $objectManager->get("\MR\Zip\Helper\PaymentUtil");
$this->_coreRegistry = $registry;
$this->_productRepository = $productRepository;
$this->_logger->info(__METHOD__);
}
public function getProductWidgetHtml(\Magento\Catalog\Model\Product $product = null)
{
if (!$product){
if (!($product = $this->_coreRegistry->registry('product'))) {
$productId = (int) $this->getRequest()->getParam('id');
$product = $this->_productRepository->getById($productId);
$this->_coreRegistry->register('product', $product);
}
}
return $this->_paymentUtil->getWidgetHtml($product->getFinalPrice());
}
}
<?php
namespace MR\Zip\Controller\Order;
use Magento\Framework\App\Action\Context;
// use Symfony\Component\Filesystem\LockHandler;
abstract class CommonAction extends \Magento\Framework\App\Action\Action
{
/**
*
* @var \Magento\Quote\Model\QuoteManagement
*/
private $_quoteManagement;
/**
*
* @var \Magento\Quote\Model\GuestCart\GuestCartManagement
*/
private $_guestCartManagement;
/**
*
* @var \Magento\Checkout\Model\Session
*/
private $_checkoutSession;
/**
*
* @var \MR\Zip\Helper\Communication
*/
private $_communication;
/**
*
* @var \MR\Zip\Helper\Configuration
*/
private $_configuration;
/**
*
* @var \Magento\Framework\Message\ManagerInterface
*/
private $_messageManager;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(Context $context)
{
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_communication = $this->_objectManager->get("\MR\Zip\Helper\Communication");
$this->_configuration = $this->_objectManager->get("\MR\Zip\Helper\Configuration");
$this->_quoteManagement = $this->_objectManager->get("\Magento\Quote\Model\QuoteManagement");
$this->_guestCartManagement = $this->_objectManager->get("\Magento\Quote\Model\GuestCart\GuestCartManagement");
$this->_checkoutSession = $this->_objectManager->get("\Magento\Checkout\Model\Session");
$this->_messageManager = $this->_objectManager->get("\Magento\Framework\Message\ManagerInterface");
$this->_logger->info(__METHOD__);
}
public function success()
{
$this->_logger->info(__METHOD__);
$this->_handlePaymentResponse(true);
}
public function fail()
{
$this->_logger->info(__METHOD__);
$this->_handlePaymentResponse(false);
return;
}
protected function _validateToken($zipId, $orderToken){
$requestTokenManager = $this->_objectManager->create("\MR\Zip\Model\RequestToken");
$requestToken = $requestTokenManager->load($zipId, "zip_id");
return $requestToken->getId() && $requestToken->getToken() == $orderToken;
}
private function _handlePaymentResponse($success)
{
$orderIncrementId = $this->getRequest()->getParam('mage_order_id');
$orderToken = $this->getRequest()->getParam('token');
$zipId = $this->getRequest()->getParam('orderId');
if(!$this->_validateToken($zipId, $orderToken)) {
$error = "The token and payment ID do not match at Zip side.";
$this->_logger->info($error);
$this->_redirectToCartPageWithError($error);
return;
}
$this->_logger->info(__METHOD__ . " order:{$orderIncrementId} token:{$orderToken} success:{$success}");
/**
* @var \Symfony\Component\Filesystem\LockHandler
*/
$lockHandler = null;
try {
// $lockHandler = new LockHandler($orderToken, BP . "/var/locks");
// if (!$lockHandler->lock(false)) {
// $action = $this->getRequest()->getActionName();
// $params = $this->getRequest()->getParams();
// $triedTime = 0;
// if (array_key_exists('TriedTime', $params)) {
// $triedTime = $params['TriedTime'];
// }
// if ($triedTime > 40) { // 40 seconds should be enough
// $this->_redirectToCartPageWithError("Failed to process the order, please contact support.");
// $this->_logger->critical(__METHOD__ . " lock timeout. order:{$orderIncrementId} token:{$orderToken} success:{$success} triedTime:{$triedTime}");
// return;
// }
// $params['TriedTime'] = $triedTime + 1;
// $this->_logger->info( __METHOD__ . " redirecting to self, wait for lock release. order:{$orderIncrementId} token:{$orderToken} success:{$success} triedTime:{$triedTime}");
// sleep(1); // wait for sometime about lock release
// return $this->_forward($action, null, null, $params);
// }
$this->_handlePaymentResponseWithoutLock($success, $orderIncrementId, $zipId);
// $lockHandler->release();
} catch (\Exception $e) {
// if (isset($lockHandler)) {
// $lockHandler->release();
// }
$this->_logger->critical(__METHOD__ . " " . "\n" . $e->getMessage() . $e->getTraceAsString());
$this->_redirectToCartPageWithError("Failed to process the order, please contact support.");
}
}
private function _handlePaymentResponseWithoutLock($success, $orderIncrementId, $zipId)
{
$this->_logger->info(__METHOD__ . " order:{$orderIncrementId} zipId:{$zipId} success:{$success}");
if (!$orderIncrementId) {
$error = "The Zip response does not contain an order ID. Order failed.";
$this->_logger->info($error);
$this->_redirectToCartPageWithError($error);
return;
}
$response = $this->_getTransactionStatus($zipId);
if (!$response) {
return;
}
/**
* @var \Magento\Quote\Model\Quote $quote
*/
$quote = $this->_loadQuote($orderIncrementId);
if ($quote == null) {
$error = "Failed to load quote from order: {$orderIncrementId}";
$this->_logger->critical($error);
$this->_redirectToCartPageWithError($error);
return;
}
// $this->_savePaymentResult($orderIncrementId, $orderToken, $quote, $response);
if (!$success || in_array($response['orderStatus'], ['Declined', 'Abandoned'])) {
$payment = $quote->getPayment();
$this->_savePaymentInfoForFailedPayment($payment);
$error = "Payment failed. Error: ";
$this->_logger->info($error);
$this->_redirectToCartPageWithError($error);
return;
}
return $this->_placeOrder($orderIncrementId, $quote, $response);
}
private function _loadQuote($orderIncrementId)
{
$this->_logger->info(__METHOD__ . " reserved_order_id:{$orderIncrementId}");
$quoteManager = $this->_objectManager->create("\Magento\Quote\Model\Quote");
/**
* @var \Magento\Quote\Model\Quote $quote
*/
$quote = $quoteManager->load($orderIncrementId, "reserved_order_id");
if (!$quote->getId()) {
$error = "Failed to load quote from order:{$orderIncrementId}";
$this->_logger->critical($error);
$this->_redirectToCartPageWithError($error);
return null;
}
return $quote;
}
private function _placeOrder($orderIncrementId, \Magento\Quote\Model\Quote $quote, $response)
{
$this->_logger->info(__METHOD__ . " orderIncrementId:{$orderIncrementId}");
$quoteId = $quote->getId();
$payment = $quote->getPayment();
if (!isset($response['orderStatus']) || $response['orderStatus'] != 'Approved') {
throw new \Magento\Framework\Exception\PaymentException(__('Payment failed. Order was not placed.'));
}
$info = $payment->getAdditionalInformation();
$this->_logger->info(__METHOD__ . " info:" . var_export($info, true));
$this->_savePaymentInfoForSuccessfulPayment($payment, $response);
$isRegisteredCustomer = !empty($quote->getCustomerId());
if ($isRegisteredCustomer) {
$quote->setPayment($payment); // looks like $payment is copy by reference. ensure the $payment data of order is exactly same with the quote.
$this->_logger->info(__METHOD__ . " placing order for logged in customer. quoteId:{$quoteId}");
// create order, and redirect to success page.
$orderId = $this->_quoteManagement->placeOrder($quoteId);
} else {
// Guest:
$cartId = $info["cartId"];
$this->_logger->info(__METHOD__ . " placing order for guest. quoteId:{$quoteId} cartId:{$cartId}");
$orderId = $this->_guestCartManagement->placeOrder($cartId);
}
$this->_checkoutSession->setLoadInactive(false);
$this->_checkoutSession->replaceQuote($this->_checkoutSession->getQuote()->save());
$this->_logger->info(__METHOD__ . " placing order done lastSuccessQuoteId:". $this->_checkoutSession->getLastSuccessQuoteId().
" lastQuoteId:".$this->_checkoutSession->getLastQuoteId().
" lastOrderId:".$this->_checkoutSession->getLastOrderId().
" lastRealOrderId:" . $this->_checkoutSession->getLastRealOrderId());
$this->_redirect("checkout/onepage/success", [
"_secure" => true
]);
return;
}
private function _savePaymentInfoForSuccessfulPayment($payment, $response)
{
$this->_logger->info(__METHOD__);
$info = $payment->getAdditionalInformation();
$info = $this->_clearPaymentParameters($info);
$info = array_merge($info, $response);
$payment->unsAdditionalInformation();
$payment->setAdditionalInformation($info);
$info = $payment->getAdditionalInformation();
$this->_logger->info(__METHOD__ . " info: ".var_export($info, true));
$payment->save();
}
private function _savePaymentInfoForFailedPayment($payment)
{
$this->_logger->info(__METHOD__);
$info = $payment->getAdditionalInformation();
$info = $this->_clearPaymentParameters($info);
$payment->unsAdditionalInformation();
$payment->setAdditionalInformation($info);
$payment->save();
}
private function _clearPaymentParameters($info)
{
$this->_logger->info(__METHOD__);
unset($info["cartId"]);
unset($info["guestEmail"]);
unset($info["method_title"]);
$this->_logger->info(__METHOD__ . " info: ".var_export($info, true));
return $info;
}
private function _getTransactionStatus($zipId)
{
try{
if(!$zipId){
throw new \Magento\Framework\Exception\NotFoundException(__('Can\'t find the initial Zip request ID.'));
}
$response = $this->_communication->getTransactionStatus($zipId);
if (!$response) { // defensive code. should never happen
throw new \Magento\Framework\Exception\NotFoundException(__('Transaction status checking response format is incorrect.'));
}
} catch (\Exception $ex) {
$this->_logger->critical(__METHOD__ . " zipId:{$zipId} response format is incorrect");
$this->_redirectToCartPageWithError("Failed to connect to Zip checking transaction status. Please try again later.");
return false;
}
return $response;
}
private function _redirectToCartPageWithError($error)
{
$this->_logger->info(__METHOD__ . " error:{$error}");
$this->_messageManager->addErrorMessage($error);
$this->_redirect("checkout/cart");
}
}
<?php
namespace MR\Zip\Controller\Order;
class Error extends \Magento\Framework\App\Action\Action
{
/**
*
* @var \Magento\Framework\View\Result\PageFactory
*/
private $resultPageFactory;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
)
{
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function execute()
{
$this->_logger->info(__METHOD__);
$resultPage = $this->resultPageFactory->create();
$resultPage->getLayout()->initMessages();
return $resultPage;
}
}
<?php
namespace MR\Zip\Controller\Order;
use \Magento\Framework\App\Action\Context;
class Fail extends CommonAction
{
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(Context $context)
{
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function execute()
{
$this->_logger->info(__METHOD__);
$this->fail();
}
}
<?php
namespace MR\Zip\Controller\Order;
class Processed extends \Magento\Framework\App\Action\Action
{
/**
*
* @var \Magento\Framework\View\Result\PageFactory
*/
private $resultPageFactory;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
)
{
$this->resultPageFactory = $resultPageFactory;
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function execute()
{
$this->_logger->info(__METHOD__);
$resultPage = $this->resultPageFactory->create();
$resultPage->getLayout()->initMessages();
return $resultPage;
}
}
<?php
// reference:
// https://www.ashsmith.io/2014/12/simple-magento2-controller-module/
// http://www.webmull.com/magento-2-create-simple-hello-world-module/
// http://www.clounce.com/magento/a-very-basic-magento-2-module
// http://www.clounce.com/magento/a-very-basic-magento-2-module-with-parameterized-template
// custom module: http://magento.stackexchange.com/questions/54609/custom-module-not-working-in-magento-2
// http://devdocs.magento.com/guides/v2.0/frontend-dev-guide/bk-frontend-dev-guide.html
// http://stackoverflow.com/questions/32356635/blank-page-in-a-custom-module-magento-2-beta-merchant-version-1-0-0
namespace MR\Zip\Controller\Order;
class Redirect extends \Magento\Framework\App\Action\Action
{
/**
*
* @var \Magento\Framework\View\Result\PageFactory
*/
private $_resultPageFactory;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
)
{
$this->_resultPageFactory = $resultPageFactory;
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function execute()
{
$this->_logger->info(__METHOD__);
$resultPage = $this->_resultPageFactory->create();
$resultPage->getLayout()->initMessages();
return $resultPage;
}
}
<?php
namespace MR\Zip\Controller\Order;
use Magento\Framework\App\Action\Context;
class Success extends CommonAction
{
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct(Context $context)
{
parent::__construct($context);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function execute()
{
$this->_logger->info(__METHOD__);
$this->success();
}
}
<?php
namespace MR\Zip\Cron;
class MerchantConfiguration
{
/**
*
* @var \Magento\Framework\App\ObjectManager
*/
protected $_objectManager;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $_storeManager;
/**
* @var $_paymentUtil \MR\Zip\Helper\PaymentUtil
*/
protected $_paymentUtil;
/**
* MerchantConfiguration Cron constructor.
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
*/
public function __construct(
\Magento\Store\Model\StoreManagerInterface $storeManager
) {
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_storeManager = $storeManager;
$this->_paymentUtil = $this->_objectManager->get("\MR\Zip\Helper\PaymentUtil");
}
public function execute()
{
$stores = $this->_storeManager->getStores();
foreach (array_keys($stores) as $storeId){
$merchantConfigurationManager = $this->_objectManager->create("\MR\Zip\Model\Configuration");
$configurationModel = $merchantConfigurationManager->load($storeId, "store_id");
$this->_paymentUtil->refreshMerchantConfiguration($configurationModel, $storeId);
}
}
}
<?php
namespace MR\Zip\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
class Communication extends AbstractHelper
{
private $_accessToken;
private $_date;
/**
*
* @var \MR\Zip\Helper\Configuration
*/
private $_configuration;
public function __construct(Context $context, \Magento\Framework\Stdlib\DateTime\DateTime $date)
{
parent::__construct($context);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_configuration = $objectManager->get("\MR\Zip\Helper\Configuration");
$this->_logger->info(__METHOD__);
$this->_accessToken = null;
$this->_date = $date;
}
public function getZipPage($requestData, $storeId = null)
{
$this->_logger->info(__METHOD__);
$orderIncrementId = $requestData['merchantReference'];
$requestData['merchant']['redirectConfirmUrl'] = $this->_getUrl('zip/order/success', ['_secure' => true, '_nosid' => true, 'mage_order_id' => $orderIncrementId]);
$requestData['merchant']['redirectCancelUrl'] = $this->_getUrl('zip/order/fail', ['_secure' => true, '_nosid' => true, 'mage_order_id' => $orderIncrementId]);
$requestData = json_encode($requestData);
$this->_logger->info(__METHOD__ . " request: ". $requestData);
$url = $this->_getApiUrl('order', $storeId);
$header = ['Content-Type: application/json', 'Authorization: Bearer ' . $this->_getAccessToken($storeId)];
$result = $this->_sendRequest($url, $header, [], \Magento\Framework\HTTP\ZendClient::POST, $requestData);
return json_decode($result['response'], true);
}
public function getTransactionStatus($zipId, $storeId = null)
{
$this->_logger->info(__METHOD__ . " zipId:{$zipId} storeId:{$storeId}");
$zipUrl = $this->_getApiUrl('/order/'. $zipId, $storeId);
$header = ['Authorization: Bearer ' . $this->_getAccessToken($storeId)];
$result = $this->_sendRequest($zipUrl, $header);
return json_decode($result['response'], true);
}
public function refund($orderIncrementId, $zipId, $amount, $storeId = null)
{
$this->_logger->info(__METHOD__ . "order:{$orderIncrementId} zipId:{$zipId} storeId:{$storeId}");
$requestData = json_encode([
'amount'=> $amount,
'merchantRefundReference' => $orderIncrementId.'-'.$amount.' '.$this->_date->date(),
]);
$this->_logger->info(__METHOD__ . " request: ". $requestData);
$zipUrl = $this->_getApiUrl('/order/' . $zipId . '/refund/', $storeId);
$header = ['Content-Type: application/json', 'Authorization: Bearer ' . $this->_getAccessToken($storeId)];
$result = $this->_sendRequest($zipUrl, $header, [],\Magento\Framework\HTTP\ZendClient::POST, $requestData);
return $result;
}
public function getMerchantConfiguration($storeId)
{
$this->_logger->info(__METHOD__ . "storeId:{$storeId}");
$zipUrl = $this->_getApiUrl('/configuration', $storeId);
$header = ['Content-Type: application/json', 'Authorization: Bearer ' . $this->_getAccessToken($storeId)];
$result = $this->_sendRequest($zipUrl, $header);
return json_decode($result['response'], true);
}
protected function _getAccessToken($storeId = null)
{
if (!$this->_accessToken) {
$accessTokenParam = [
'grant_type' => 'client_credentials',
'client_id' => $this->_configuration->getZipClientId($storeId),
'client_secret' => $this->_configuration->getZipClientSecret($storeId),
'audience' => $this->_configuration->getZipApiAudience($storeId),
];
$headers = [
'Content-Type: application/json'
];
$url = $this->_configuration->getZipAuthTokenEndpoint($storeId);
try {
$accessTokenResult = $this->_sendRequest($url, $headers, [], \Magento\Framework\HTTP\ZendClient::POST, json_encode($accessTokenParam));
$response = json_decode($accessTokenResult['response'], true);
} catch (\Exception $ex) {
$this->_logger->error($ex->getMessage());
return false;
}
if (!$response || !isset($response['access_token'])) {
$errorMessage = 'Can\'t get Zip AccessToken with the credential.';
throw new \Magento\Framework\Exception\PaymentException(__($errorMessage));
}
$this->_accessToken = $response['access_token'];
}
return $this->_accessToken;
}
protected function _getApiUrl($path, $storeId = null)
{
$baseUrl = $this->_configuration->getZipApiEndpoint($storeId);
$apiUrl = rtrim($baseUrl, '/') . '/' . trim($path, '/');
return $apiUrl;
}
private function _sendRequest($url, $header = [], $params = [], $method = \Magento\Framework\HTTP\ZendClient::GET, $postBody = null)
{
$this->_logger->info(__METHOD__ . " postUrl: {$url}");
$ch = curl_init();
switch ($method) {
case "POST":
curl_setopt($ch, CURLOPT_POST, 1);
if ($postBody)
curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
break;
case "PUT":
curl_setopt($ch, CURLOPT_PUT, 1);
break;
default:
if (!empty($params))
$url = sprintf("%s?%s", $url, http_build_query($params));
}
curl_setopt($ch, CURLOPT_URL, $url);
if (!empty($header)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($ch, CURLOPT_TIMEOUT, 180);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
$errorNo = curl_errno($ch);
$errorMessage = '';
if($errorNo){
$errorMessage = " Error:" . curl_error($ch) . " Error Code:" . curl_errno($ch);
$this->_logger->critical(__METHOD__ . $errorMessage);
}
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpcode && substr($httpcode, 0, 2) != "20") {
$errorMessage = " HTTP CODE: {$httpcode} for URL: {$url}";
$this->_logger->critical(__METHOD__ . $errorMessage);
}
$result = [
'httpcode' => $httpcode,
'response' => $response,
'errmsg' => $errorMessage,
];
curl_close($ch);
$this->_logger->info(__METHOD__ . " response from Zip - HttpCode:{$httpcode} Body:{$response}");
return $result;
}
}
<?php
namespace MR\Zip\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
class Configuration extends AbstractHelper
{
const ZIP_PATH = "payment/mr_zip/";
const MODULE_NAME = "MR_Zip";
/**
*
* @var \Magento\Framework\Module\ModuleListInterface
*/
private $_moduleList;
public function __construct(Context $context)
{
parent::__construct($context);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_moduleList = $objectManager->get("Magento\Framework\Module\ModuleListInterface");
$this->_logger = $objectManager->get("MR\Zip\Logger\ZipLogger");
}
public function getPaymentType($storeId = null)
{
return 'Purchase';
}
public function getModuleVersion()
{
if ($this->_moduleList == null)
return "M2-unknown";
return "M2-" . $this->_moduleList->getOne(self::MODULE_NAME)['setup_version'];
}
public function getZipClientId($storeId = null)
{
return $this->_getZipStoreConfig("client_id", $storeId);
}
public function getZipClientSecret($storeId = null)
{
return $this->_getZipStoreConfig("client_secret", $storeId, true);
}
public function getZipApiEndpoint($storeId = null)
{
return $this->_getZipStoreConfig("api_endpoint", $storeId);
}
public function getZipAuthTokenEndpoint($storeId = null)
{
return $this->_getZipStoreConfig("auth_token_endpoint", $storeId);
}
public function getZipApiAudience($storeId = null)
{
return $this->_getZipStoreConfig("api_audience", $storeId);
}
public function getEnabled($storeId = null)
{
return filter_var($this->_getZipStoreConfig("active", $storeId), FILTER_VALIDATE_BOOLEAN);
}
public function getDebugFlag($storeId = null)
{
return filter_var($this->_getZipStoreConfig("debug_flag", $storeId), FILTER_VALIDATE_BOOLEAN);
}
public function getMerchantName($storeId = null)
{
return $this->_getZipStoreConfig("merchant_name", $storeId);
}
private function _getZipStoreConfig($configName, $storeId = null, $isSensitiveData = false)
{
$this->_logger->info("Configuration::_getZipStoreConfig storeId argument:" . $storeId);
$value = $this->scopeConfig->getValue(self::ZIP_PATH . $configName, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $storeId);
if (!$isSensitiveData) {
$this->_logger->info(__METHOD__ . " configName:{$configName} storeId:{$storeId} value:{$value}");
} else {
$this->_logger->info(__METHOD__ . " configName:{$configName} storeId:{$storeId} value:*****");
}
return $value;
}
}
<?php
namespace MR\Zip\Helper;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
class PaymentUtil extends AbstractHelper
{
/**
*
* @var \Magento\Framework\App\ObjectManager
*/
private $_objectManager;
/**
* Asset service
*
* @var \Magento\Framework\View\Asset\Repository
*/
private $_assetRepo;
/**
* @var \MR\Zip\Helper\Communication
*/
protected $_communicationHelper;
/**
* @var $_storeManager \Magento\Store\Model\StoreManagerInterface
*/
protected $_storeManager;
/**
* @var $_configHelper \MR\Zip\Helper\Configuration
*/
protected $_configHelper;
public function __construct(
Context $context,
\Magento\Store\Model\StoreManagerInterface $storeManager
)
{
parent::__construct($context);
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_assetRepo = $this->_objectManager->get("\Magento\Framework\View\Asset\Repository");
$this->_communicationHelper = $this->_objectManager->get("\MR\Zip\Helper\Communication");
$this->_configHelper = $this->_objectManager->get("\MR\Zip\Helper\Configuration");
$this->_storeManager = $storeManager;
$this->_logger->info(__METHOD__);
}
public function buildRedirectUrl()
{
$this->_logger->info(__METHOD__);
$urlManager = $this->_objectManager->get('\Magento\Framework\Url');
$url = $urlManager->getUrl('zip/order/redirect', ['_secure' => true]);
$this->_logger->info(__METHOD__ . " url: {$url} ");
return $url;
}
public function saveInvalidRefundResponse($payment, $responseText)
{
$this->_logger->info(__METHOD__ . " responseText:{$responseText}");
$info = [
"Error" => $responseText,
];
$payment->setAdditionalInformation(date("Y-m-d H:i:s"), json_encode($info));
$payment->save();
return $info;
}
public function saveZipRefundResponse($payment, $responseBody)
{
$this->_logger->info(__METHOD__ . " responseBody:{$responseBody}");
$response = json_decode($responseBody, true);
if (isset($response['id'])) {
$payment->setTransactionId($response['id']);
}
$payment->setAdditionalInformation(date("Y-m-d H:i:s"), $responseBody);
$payment->save();
return $response;
}
public function loadOrderById($orderId)
{
$this->_logger->info(__METHOD__ . " orderId:{$orderId}");
$orderManager = $this->_objectManager->get('Magento\Sales\Model\Order');
$order = $orderManager->loadByAttribute("entity_id", $orderId);
$orderIncrementId = $order->getIncrementId();
$this->_logger->info(__METHOD__ . " orderIncrementId:{$orderIncrementId}");
if (!isset($orderIncrementId)) {
return null;
}
return $order;
}
public function loadCustomerInfo($order)
{
$customerId = $order->getCustomerId();
$this->_logger->info(__METHOD__ . " customerId:{$customerId}");
$customerInfo = $this->_objectManager->create("\Magento\Framework\DataObject");
$customerInfo->setId($customerId);
$customerInfo->setName($order->getCustomerName());
$customerInfo->setEmail($order->getCustomerEmail());
try {
$address = $order->getBillingAddress();
if ($address) {
$customerInfo->setPhoneNumber($address->getTelephone());
$streetFull = implode(" ", $address->getStreet()) . " " . $address->getCity() . ", " . $address->getRegion() . " " . $address->getPostcode() . " " . $address->getCountryId();
$customerInfo->setAddress($streetFull);
}
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->_logger->critical($e->_toString());
}
return $customerInfo;
}
public function findZipOrderForRefund($orderIncrementId, $info)
{
$this->_logger->info(__METHOD__);
$zipId = "";
if (isset($info["orderId"])) {
$zipId = $info["orderId"];
$this->_logger->info(__METHOD__ . "order:{$orderIncrementId} ZipID: {$zipId}");
return $zipId;
}
$this->_logger->info(__METHOD__ . " ZipID not found");
return $zipId;
}
public function getWidgetHtml($totalAmount)
{
$storeId = $this->_storeManager->getStore()->getId();
$merchantConfigurationManager = $this->_objectManager->create("\MR\Zip\Model\Configuration");
$configurationModel = $merchantConfigurationManager->load($storeId, "store_id");
if ($configurationModel && !$configurationModel->getId()) {
$configurationModel = $this->refreshMerchantConfiguration($configurationModel, $storeId);
}
if ($configurationModel->getMin() && $configurationModel->getMax()) {
$merchantName = $this->_configHelper->getMerchantName($storeId) ?: 'your-merchant-name';
$merchantName = urlencode(str_replace(' ', '-', $merchantName));
return '<script async src="https://widgets.partpay.co.nz/' . $merchantName . '/partpay-widget-0.1.1.js?type=calculator&min=' . $configurationModel->getMin() . '&max=' . $configurationModel->getMax() . '&amount=' . $totalAmount . '" type="application/javascript"></script>';
}
return false;
}
public function refreshMerchantConfiguration($merchantConfigurationModel, $storeId)
{
$apiData = $this->_communicationHelper->getMerchantConfiguration($storeId);
$merchantConfigurationModel->addData(
array(
"store_id" => $storeId,
"min" => $apiData['minimumAmount'] ? $apiData['minimumAmount'] : '',
"max" => $apiData['maximumAmount'] ? $apiData['maximumAmount'] : '',
));
$merchantConfigurationModel->save();
return $merchantConfigurationModel;
}
}
<?php
namespace MR\Zip\Helper\Zip;
class UrlCreator
{
/**
*
* @var \Magento\Framework\App\ObjectManager
*/
private $_objectManager;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
/**
*
* @var \MR\Zip\Helper\Configuration
*/
protected $_configuration;
/**
*
* @var \MR\Zip\Helper\Communication
*/
protected $_communication;
public function __construct()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_objectManager = $objectManager;
$this->_communication = $objectManager->get("\MR\Zip\Helper\Communication");
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_configuration = $objectManager->get("\MR\Zip\Helper\Configuration");
$this->_logger->info(__METHOD__);
}
public function CreateUrl(\Magento\Quote\Model\Quote $quote)
{
$this->_logger->info(__METHOD__);
$requestData = $this->_buildZipRequestData($quote);
try {
$response = $this->_communication->getZipPage($requestData);
}catch (\Exception $ex) {
$this->_logger->error($ex->getMessage());
return false;
}
if (!$response || empty($response['redirectUrl'])) {
$error = "Invalid response from Zip: " . $response;
$this->_logger->critical(__METHOD__ . " " . $error);
return false;
}
$requestTokenModel = $this->_objectManager->create("\MR\Zip\Model\RequestToken");
$requestTokenModel->setData(
array(
"token" => $response['token'],
"url" => $response['redirectUrl'],
"expire" => $response['expiryDateTime'],
"order_id" => $quote->getReservedOrderId(),
"zip_id" => $response['orderId'],
));
$requestTokenModel->save();
$session = $this->_objectManager->get('\Magento\Checkout\Model\Session');
$session->setZipQuoteId($session->getQuote()->getId());
return (string)$response['redirectUrl'];
}
private function _buildZipRequestData(\Magento\Quote\Model\Quote $quote)
{
$orderIncrementId = $quote->getReservedOrderId();
$this->_logger->info(__METHOD__ . " orderIncrementId:{$orderIncrementId}");
$customerInfo = $this->_loadCustomerInfo($quote);
//format order
$param = array();
$param['amount'] = $quote->getBaseGrandTotal();
$param['consumer']['phoneNumber'] = $customerInfo->getPhoneNumber();
$param['consumer']['surname'] = $customerInfo->getSurname();
$param['consumer']['email'] = $quote->getBillingAddress()->getEmail();
$param['billing']['addressLine1'] = $customerInfo->getBillingStreet1();
$param['billing']['addressLine2'] = $customerInfo->getBillingStreet2();
$param['billing']['suburb'] = '';
$param['billing']['city'] = $quote->getBillingAddress()->getCity();
$param['billing']['postcode'] = $quote->getBillingAddress()->getPostcode();
$param['billing']['state'] = $quote->getBillingAddress()->getRegion() ? $quote->getBillingAddress()->getRegion() : '';
$param['billing']['country'] = $quote->getBillingAddress()->getCountry();
$param['shipping']['addressLine1'] = $customerInfo->getShippingStreet1();
$param['shipping']['addressLine2'] = $customerInfo->getShippingStreet2();
$param['shipping']['suburb'] = '';
$param['shipping']['city'] = $quote->getShippingAddress()->getCity();
$param['shipping']['postcode'] = $quote->getShippingAddress()->getPostcode();
$param['shipping']['state'] = $quote->getShippingAddress()->getRegion();
$param['shipping']['country'] = $quote->getShippingAddress()->getCountry();
$param['description'] = '';
$productManager = $this->_objectManager->create("\Magento\Catalog\Model\Product");
//format all items in cart
foreach ( $quote->getAllVisibleItems() as $item){
/**
* @var \Magento\Catalog\Model\Product $product
*/
$product = $productManager->load($item->getProductId());
$param['items'][] = array(
'description' => $product->getDescription(),
'name' => $item->getName(),
'sku' => $item->getSku(),
'quantity' => $item->getQty(),
'price' => $item->getBaseRowTotalInclTax(),
);
}
$param['merchantReference'] = $orderIncrementId;
$param['taxAmount'] = $quote->getShippingAddress()->getBaseTaxAmount();
$param['shippingAmount'] = $quote->getShippingAddress()->getBaseShippingAmount();
$this->_logger->info(__METHOD__ . " param:" . var_export($param, true));
return $param;
}
private function _loadCustomerInfo(\Magento\Quote\Model\Quote $quote)
{
$customerId = $quote->getCustomerId();
$this->_logger->info(__METHOD__ . " customerId:{$customerId}");
$customerInfo = $this->_objectManager->create("\Magento\Framework\DataObject");
$customerInfo->setId($customerId);
$customerInfo->setSurname($this->_getCustomerSurname($quote));
$customerInfo->setEmail($quote->getCustomerEmail());
try {
$billingAddress = $quote->getBillingAddress();
if ($billingAddress) {
$customerInfo->setPhoneNumber($billingAddress->getTelephone());
$billingStreetData = $billingAddress->getStreet();
$streetFull = implode(" ", $billingStreetData) . " " . $billingAddress->getCity() . ", " .
$billingAddress->getRegion() . " " . $billingAddress->getPostcode() . " " . $billingAddress->getCountryId();
if (isset($billingStreetData[0])) {
$customerInfo->setBillingStreet1($billingStreetData[0]);
}
if (isset($billingStreetData[1])) {
$customerInfo->setBillingStreet2($billingStreetData[1]);
}
$customerInfo->setFullAddress($streetFull);
}
if ($shippingAddress = $quote->getShippingAddress()) {
$shippingStreetData = $shippingAddress->getStreet();
if (isset($shippingStreetData[0])) {
$customerInfo->setShippingStreet1($shippingStreetData[0]);
}
if (isset($shippingStreetData[1])) {
$customerInfo->setShippingStreet2($shippingStreetData[1]);
}
}
} catch (\Magento\Framework\Exception\NoSuchEntityException $e) {
$this->_logger->critical($e->_toString());
}
return $customerInfo;
}
/**
* Retrieve customer name
*
* @return string
*/
private function _getCustomerSurname(\Magento\Quote\Model\Quote $quote)
{
if ($quote->getCustomerLastname()) {
$customerName = $quote->getCustomerLastname();
} else {
$customerName = $quote->getBillingAddress()->getLastname();
}
$this->_logger->info(__METHOD__ . " customerSurname:{$customerName}");
return $customerName;
}
}
<?php
namespace MR\Zip\Logger\Handler;
use \Magento\Framework\Filesystem\DriverInterface;
use \Magento\Framework\Logger\Handler\Base;
use \Monolog\Logger;
class All extends Base
{
protected $level = Logger::DEBUG;
public function __construct(DriverInterface $filesystem, $filePath = null)
{
$now = new \DateTime('now');
$strToday = $now->format('Y-m-d');
$this->fileName = "/var/log/mr_zip_{$strToday}.log";
parent::__construct($filesystem, $filePath);
}
}
<?php
namespace MR\Zip\Logger;
// Refer to vendor\monolog\monolog\src\Monolog\Logger.php
// Log to separate file
class ZipLogger extends \Monolog\Logger
{
public function __construct($name, array $handlers = [], array $processors = [])
{
parent::__construct($name, $handlers, $processors);
try {
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$productMetadata = $objectManager->get('\Magento\Framework\App\ProductMetadataInterface');
$version = $productMetadata->getVersion();
$this->pushProcessor(function ($record) use ($version) {
$record['extra']['magentoVersion'] = $version;
return $record;
});
} catch (\Exception $e) {
// print 'Caught exception: ', $e->getMessage(), "\n";
}
}
}
<?php
namespace MR\Zip\Model\Api;
class ApiCommonHelper
{
// http://devdocs.magento.com/guides/v2.0/extension-dev-guide/service-contracts/service-to-web-service.html
/**
*
* @var /Magento\Quote\Model\QuoteIdMaskFactory
*/
private $_quoteIdMaskFactory;
/**
*
* @var \Magento\Quote\Model\QuoteRepository
*/
private $_quoteRepository;
/**
*
* @var \Magento\Quote\Model\PaymentMethodManagement
*/
private $_paymentMethodManagement;
/**
* @var \Magento\Quote\Model\QuoteValidator
*/
private $_quoteValidator;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_quoteIdMaskFactory = $objectManager->get("\Magento\Quote\Model\QuoteIdMaskFactory");
$this->_paymentMethodManagement = $objectManager->get("\Magento\Quote\Model\PaymentMethodManagement");
$this->_quoteRepository = $objectManager->get("\Magento\Quote\Model\QuoteRepository");
$this->_quoteValidator = $objectManager->get("\Magento\Quote\Model\QuoteValidator");
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function setPaymentForLoggedinCustomer($quoteId, \Magento\Quote\Api\Data\PaymentInterface $method)
{
$this->_logger->info(__METHOD__. " quoteId:{$quoteId}");
$this->_paymentMethodManagement->set($quoteId, $method);
$quote = $this->_quoteRepository->get($quoteId);
$this->_quoteValidator->validateBeforeSubmit($quote); // ensure all the data is correct
$quote->reserveOrderId();
$this->_quoteRepository->save($quote);
return $quote;
}
public function setPaymentForGuest($cartId, $email, \Magento\Quote\Api\Data\PaymentInterface $method)
{
$this->_logger->info(__METHOD__. " cartId:{$cartId}");
$quoteIdMask = $this->_quoteIdMaskFactory->create()->load($cartId, 'masked_id');
$quoteId = $quoteIdMask->getQuoteId();
$this->_logger->info(__METHOD__. " cartId:{$cartId} quoteId:{$quoteId}");
$this->_paymentMethodManagement->set($quoteId, $method);
$quote = $this->_quoteRepository->get($quoteId);
$quote->getBillingAddress()->setEmail($email);
$this->_quoteValidator->validateBeforeSubmit($quote); // ensure all the data is correct
$quote->setCustomerIsGuest(true);
$quote->reserveOrderId();
$this->_quoteRepository->save($quote);
$payment = $quote->getPayment();
$info = $payment->getAdditionalInformation();
if ($info["cartId"] != $cartId) {
// Maybe merchant do not use the default implementation of PaymentInterface, leads the $method->getData() not return the data from js?
$this->_logger->info(__METHOD__ . " Unexpected behavior! cartId set incorrectly. PaymentInterface.class:" . get_class($method) ." payment.info:" . var_export($info, true));
$info["cartId"] = $cartId;
$info["guestEmail"] = $email;
$payment->setAdditionalInformation($info);
$payment->save();
}
$info = $payment->getAdditionalInformation();
$this->_logger->info(__METHOD__ . " PaymentInterface.class:" . get_class($method) . " info: " . var_export($info, true));
return $quote;
}
}
<?php
namespace MR\Zip\Model\Api;
use \Magento\Framework\Exception\State\InvalidTransitionException;
class ApiZipHelper
{
// http://devdocs.magento.com/guides/v2.0/extension-dev-guide/service-contracts/service-to-web-service.html
/**
*
* @var \MR\Zip\Model\Api\ApiCommonHelper
*/
private $_apiCommonHelper;
/**
*
* @var \MR\Zip\Helper\Zip\UrlCreator
*/
private $_zipUrlCreator;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
public function __construct()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_zipUrlCreator = $objectManager->get("\MR\Zip\Helper\Zip\UrlCreator");
$this->_apiCommonHelper = $objectManager->get("\MR\Zip\Model\Api\ApiCommonHelper");
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function createUrlForCustomer($quoteId, \Magento\Quote\Api\Data\PaymentInterface $method)
{
$this->_logger->info(__METHOD__. " quoteId:{$quoteId}");
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $this->_apiCommonHelper->setPaymentForLoggedinCustomer($quoteId, $method);
return $this->_createUrl($quote);
}
public function createUrlForGuest($cartId, $email, \Magento\Quote\Api\Data\PaymentInterface $method)
{
$this->_logger->info(__METHOD__. " cartId:{$cartId}");
/** @var \Magento\Quote\Model\Quote $quote */
$quote = $this->_apiCommonHelper->setPaymentForGuest($cartId, $email, $method);
return $this->_createUrl($quote);
}
private function _createUrl(\Magento\Quote\Model\Quote $quote)
{
// Create zip redirect url.
$url = $this->_zipUrlCreator->CreateUrl($quote);
if (!isset($url) || empty($url)){
$quoteId = $quote->getId();
$this->_logger->critical(__METHOD__ . " Failed to create transaction quoteId:{$quoteId}");
throw new InvalidTransitionException(__('Failed to create transaction.'));
}
$this->_logger->info(__METHOD__. " redirectUrl:{$url}");
return $url;
}
}
<?php
namespace MR\Zip\Model\Api;
class GuestZipManagement implements \MR\Zip\Api\GuestZipManagementInterface
{
// http://devdocs.magento.com/guides/v2.0/extension-dev-guide/service-contracts/service-to-web-service.html
/**
*
* @var \MR\Zip\Model\Api\ApiZipHelper
*/
private $_apiHelper;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
/**
* @var \Magento\Quote\Api\CartRepositoryInterface
*/
private $_cartRepository;
/**
* @var \Magento\Quote\Model\QuoteIdMaskFactory
*/
private $_quoteIdMaskFactory;
/**
* @var \Magento\Quote\Api\GuestBillingAddressManagementInterface
*/
private $billingAddressManagement;
public function __construct(
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
\Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory,
\Magento\Quote\Api\GuestBillingAddressManagementInterface $billingAddressManagement
) {
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_apiHelper = $objectManager->get("\MR\Zip\Model\Api\ApiZipHelper");
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
$this->_cartRepository = $quoteRepository;
$this->_quoteIdMaskFactory = $quoteIdMaskFactory;
$this->billingAddressManagement = $billingAddressManagement;
}
/**
* {@inheritDoc}
*/
public function set(
$cartId,
$email,
\Magento\Quote\Api\Data\PaymentInterface $method,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
$this->_logger->info(__METHOD__. " cartId:{$cartId} guestEmail:{$email}");
// Create zip redirect url.
if ($billingAddress) {
$this->_logger->info(__METHOD__. " assigning billing address.");
$billingAddress->setEmail($email);
$this->billingAddressManagement->assign($cartId, $billingAddress);
} else {
$quoteIdMask = $this->_quoteIdMaskFactory->create()->load($cartId, 'masked_id');
$quoteId = $quoteIdMask->getQuoteId();
$this->_cartRepository->getActive($quoteId)->getBillingAddress()->setEmail($email);
}
$url = $this->_apiHelper->createUrlForGuest($cartId, $email, $method);
$this->_logger->info(__METHOD__. " redirectUrl:{$url}");
return $url;
}
}
<?php
namespace MR\Zip\Model\Api;
class ZipManagement implements \MR\Zip\Api\ZipManagementInterface
{
// http://devdocs.magento.com/guides/v2.0/extension-dev-guide/service-contracts/service-to-web-service.html
/**
*
* @var \MR\Zip\Model\Api\ApiZipHelper
*/
private $_apiHelper;
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
/**
*
* @var \Magento\Quote\Api\BillingAddressManagementInterface
*/
private $_billingAddressManagement;
public function __construct(\Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement)
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_billingAddressManagement = $billingAddressManagement;
$this->_apiHelper = $objectManager->get("\MR\Zip\Model\Api\ApiZipHelper");
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
/**
* {@inheritDoc}
*/
public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method, \Magento\Quote\Api\Data\AddressInterface $billingAddress = null)
{
$this->_logger->info(__METHOD__. " cartId:{$cartId}");
if ($billingAddress) {
$this->_logger->info(__METHOD__. " assigning billing address");
$this->_billingAddressManagement->assign($cartId, $billingAddress);
}
$url = $this->_apiHelper->createUrlForCustomer($cartId, $method);
$this->_logger->info(__METHOD__. " redirectUrl:{$url}");
return $url;
}
}
<?php
// http://www.mage-world.com/blog/how-to-use-model-and-collection-in-magento-2.html
// http://stackoverflow.com/questions/31983546/in-magento-2-what-is-the-correct-way-for-getmodel/31984198
// http://stackoverflow.com/questions/31920769/how-to-save-data-using-model-in-magento2
namespace MR\Zip\Model;
use \Magento\Framework\Model\AbstractModel;
class Configuration extends AbstractModel
{
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
)
{
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
parent::__construct($context, $registry, $resource, $resourceCollection, $data);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
protected function _construct()
{
$this->_logger->info(__METHOD__);
$this->_init('MR\Zip\Model\ResourceModel\Configuration');
}
}
<?php
// Magento\Framework\DataObject implements the magic call function
// Create payment module http://www.josephmcdermott.co.uk/basics-creating-magento2-payment-method
// https://github.com/magento/magento2-samples/tree/master/sample-module-payment-provider
namespace MR\Zip\Model;
class Payment extends \Magento\Payment\Model\Method\AbstractMethod
{
/**
*
* @var \Magento\Framework\App\ObjectManager
*/
private $_objectManager;
protected $_code;
protected $_infoBlockType = 'MR\Zip\Block\Info';
protected $_isGateway = true;
protected $_canCapture = true;
protected $_canUseInternal = false;
protected $_canUseCheckout = true;
protected $_canUseForMultishipping = false;
protected $_canRefund = true;
protected $_canCapturePartial = true;
protected $_canRefundInvoicePartial = true;
/**
*
* @var \MR\Zip\Model\PaymentHelper
*/
private $_paymentHelper;
const MR_ZIP_CODE = "mr_zip";
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
\Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
\Magento\Payment\Helper\Data $paymentData,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Payment\Model\Method\Logger $logger,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
)
{
parent::__construct(
$context,
$registry,
$extensionFactory,
$customAttributeFactory,
$paymentData,
$scopeConfig,
$logger,
$resource,
$resourceCollection,
$data
);
$this->_code = self::MR_ZIP_CODE;
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
/** @var \MR\Zip\Helper\Configuration $configuration*/
$configuration = $this->_objectManager->get("\MR\Zip\Helper\Configuration");
/** @var \MR\Zip\Helper\Communication $communication*/
$communication = $this->_objectManager->get("\MR\Zip\Helper\Communication");
$this->_paymentHelper = $this->_objectManager->create("\MR\Zip\Model\PaymentHelper");
$this->_paymentHelper->init($configuration, $communication);
$this->_logger->info(__METHOD__);
}
// invoked by Magento\Quote\Model\PaymentMethodManagement::set
public function assignData(\Magento\Framework\DataObject $data)
{
$this->_logger->info(__METHOD__ . " data:" . var_export($data, true));
$infoInstance = $this->getInfoInstance();
$source = $data;
if (isset($data['additional_data'])){
$source = $this->_objectManager->create("\Magento\Framework\DataObject");
$source->setData($data['additional_data']);
}
$info = [];
$info["cartId"] = $source->getData("cartId");
$info["guestEmail"] = $source->getData("guestEmail");
$infoInstance->setAdditionalInformation($info);
$infoInstance->save();
$this->_logger->info(__METHOD__ . " info:" . var_export($info, true));
return $this;
}
public function getConfigPaymentAction()
{
return $this->_paymentHelper->getConfigPaymentAction($this->getStore());
}
// Invoked by Mage_Sales_Model_Order_Payment::capture
public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
{
$this->_logger->info(__METHOD__ . " payment amount:" . $amount);
$this->_paymentHelper->capture($payment, $amount, $this->getStore());
return $this;
}
// Mage_Sales_Model_Order_Payment::refund
// use getInfoInstance to get object of Mage_Payment_Model_Info (Mage_Payment_Model_Info::getMethodInstance Mage_Sales_Model_Order_Payment is sub class of Mage_Payment_Model_Info)
public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
{
$this->_logger->info(__METHOD__);
$this->_paymentHelper->refund($payment, $amount, $this->getStore());
return $this;
}
public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
{
$this->_logger->info(__METHOD__);
return $this->_paymentHelper->isAvailable($quote);
}
}
<?php
// Magento\Framework\DataObject implements the magic call function
// Create payment module http://www.josephmcdermott.co.uk/basics-creating-magento2-payment-method
// https://github.com/magento/magento2-samples/tree/master/sample-module-payment-provider
namespace MR\Zip\Model;
class PaymentHelper
{
/**
*
* @var \MR\Zip\Helper\PaymentUtil
*/
protected $_paymentUtil;
/**
*
* @var \MR\Zip\Helper\Configuration
*/
protected $_configuration;
/**
*
* @var \MR\Zip\Helper\Communication
*/
protected $_communication;
public function __construct()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$this->_logger = $objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_paymentUtil = $objectManager->get("\MR\Zip\Helper\PaymentUtil");
$this->_communication = $objectManager->get("\MR\Zip\Helper\Communication");
$this->_logger->info(__METHOD__);
}
public function init($configuration, $communication)
{
$this->_logger->info(__METHOD__);
$this->_configuration = $configuration;
$this->_communication = $communication;
}
public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
{
$this->_logger->info(__METHOD__);
if ($quote != null){
$enabled = $this->_configuration->getEnabled($quote->getStoreId());
}
else {
$enabled = $this->_configuration->getEnabled();
}
$this->_logger->info(__METHOD__ . " enabled:" . $enabled);
return $enabled;
}
public function getConfigPaymentAction($storeId)
{
// invoked by Magento\Sales\Model\Order\Payment::place
$this->_logger->info(__METHOD__);
$paymentAction = \Magento\Payment\Model\Method\AbstractMethod::ACTION_AUTHORIZE_CAPTURE;
$this->_logger->info(__METHOD__ . " paymentAction: {$paymentAction}");
return $paymentAction;
}
public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount, $storeId)
{
// refer to Magento\Sales\Model\Order\Payment\Transaction\Builder::build for which fields should be set.
$this->_logger->info(__METHOD__);
$orderId = "unknown";
$order = $payment->getOrder();
if ($order) {
$orderId = $order->getIncrementId();
}
if (!$payment->hasAdditionalInformation()) {
$this->_logger->info(__METHOD__ . " orderId:{$orderId} additional_information is empty");
}
$info = $payment->getAdditionalInformation();
$transactionId = $info["orderId"]; // ensure it is unique
$payment->setTransactionId($transactionId);
$payment->setIsTransactionClosed(1);
unset($info['items']);
unset($info['billing']);
unset($info['shipping']);
unset($info['merchant']);
$payment->setTransactionAdditionalInfo(\Magento\Sales\Model\Order\Payment\Transaction::RAW_DETAILS, $info);
}
// Mage_Sales_Model_Order_Payment::refund
// use getInfoInstance to get object of Mage_Payment_Model_Info (Mage_Payment_Model_Info::getMethodInstance Mage_Sales_Model_Order_Payment is sub class of Mage_Payment_Model_Info)
public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount, $storeId)
{
$this->_logger->info(__METHOD__);
$info = $payment->getAdditionalInformation();
$orderIncrementId = $payment->getOrder()->getIncrementId();
$zipId = $this->_paymentUtil->findZipOrderForRefund($orderIncrementId, $info);
$apiResult = $this->_communication->refund($orderIncrementId, $zipId, $amount, $storeId);
$orderId = "unknown";
$order = $payment->getOrder();
if ($order) {
$orderId = $order->getIncrementId();
}
$this->_logger->info(__METHOD__ . " orderId:{$orderId}");
$response = $apiResult['response'];
if ($apiResult['errmsg']) {
$errorMessage = " Failed to refund order:{$orderId}, {$apiResult['errmsg']}, response from Zip: " . $response;
$this->_paymentUtil->saveInvalidRefundResponse($payment, $errorMessage);
$this->_logger->critical(__METHOD__ . $errorMessage);
throw new \Magento\Framework\Exception\PaymentException(__($errorMessage));
}
$this->_paymentUtil->saveZipRefundResponse($payment, $response);
}
}
<?php
// http://www.mage-world.com/blog/how-to-use-model-and-collection-in-magento-2.html
// http://stackoverflow.com/questions/31983546/in-magento-2-what-is-the-correct-way-for-getmodel/31984198
// http://stackoverflow.com/questions/31920769/how-to-save-data-using-model-in-magento2
namespace MR\Zip\Model;
use \Magento\Framework\Model\AbstractModel;
class RequestToken extends AbstractModel
{
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
)
{
$this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
parent::__construct($context, $registry, $resource, $resourceCollection, $data);
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
protected function _construct()
{
$this->_logger->info(__METHOD__);
$this->_init('MR\Zip\Model\ResourceModel\RequestToken');
}
}
<?php
namespace MR\Zip\Model\ResourceModel;
use \Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class Configuration extends AbstractDb
{
protected function _construct()
{
$this->_init('mr_zip_configuration', 'id');
}
}
<?php
namespace MR\Zip\Model\ResourceModel\Configuration;
use \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
protected function _construct()
{
$this->_init('MR\Zip\Model\Configuration', 'MR\Zip\Model\ResourceModel\Configuration');
}
}
<?php
namespace MR\Zip\Model\ResourceModel;
use \Magento\Framework\Model\ResourceModel\Db\AbstractDb;
class RequestToken extends AbstractDb
{
protected function _construct()
{
$this->_init('mr_zip', 'id');
}
}
<?php
namespace MR\Zip\Model\ResourceModel\RequestToken;
use \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection;
class Collection extends AbstractCollection
{
protected function _construct()
{
$this->_init('MR\Zip\Model\RequestToken', 'MR\Zip\Model\ResourceModel\RequestToken');
}
}
<?php
namespace MR\Zip\Model;
use \Magento\Checkout\Model\ConfigProviderInterface;
// Invoked by Magento\Checkout\Block\Onepage::getCheckoutConfig
class ZipConfigProvider implements ConfigProviderInterface
{
/**
*
* @var \MR\Zip\Logger\ZipLogger
*/
private $_logger;
/**
*
* @var \Magento\Framework\App\ObjectManager
*/
private $_objectManager;
/**
*
* @var \MR\Zip\Helper\Configuration
*/
private $_configuration;
public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager)
{
$this->_objectManager = $objectManager;
$this->_configuration = $this->_objectManager->get("\MR\Zip\Helper\Configuration");
$this->_logger = $this->_objectManager->get("\MR\Zip\Logger\ZipLogger");
$this->_logger->info(__METHOD__);
}
public function getConfig()
{
$this->_logger->info(__METHOD__);
$session = $this->_objectManager->get('\Magento\Checkout\Model\Session');
$quote = $session->getQuote();
$quoteId = $quote->getId();
// $customerSession = $this->_objectManager->get("\Magento\Customer\Model\Session");
$paymentUtil = $this->_objectManager->get("\MR\Zip\Helper\PaymentUtil");
return [
'payment' => [
'zip' => [
'redirectUrl' => $paymentUtil->buildRedirectUrl($quoteId),
'method' => \MR\Zip\Model\Payment::MR_ZIP_CODE
]
]
];
}
}
<?php
namespace MR\Zip\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\DB\Adapter\AdapterInterface;
class InstallSchema implements InstallSchemaInterface
{
/**
* @param SchemaSetupInterface $setup
* @param ModuleContextInterface $context
* @throws \Zend_Db_Exception
*/
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$installer->startSetup();
$mrZipTableName = $installer->getTable('mr_zip');
// if exists, then this module should be installed before, just skip it. Use upgrade command to updata the table.
if ($installer->getConnection()->isTableExists($mrZipTableName) != true) {
$mrZipTable = $installer->getConnection()
->newTable($mrZipTableName)
->addColumn(
'id',
Table::TYPE_INTEGER,
11,
[
'identity' => true,
'unsigned' => true,
'nullable' => false,
'primary' => true
],
'ID'
)
->addColumn(
'token',
Table::TYPE_TEXT,
255,
[],
'Token'
)
->addColumn(
'url',
Table::TYPE_TEXT,
255,
[],
'URL'
)
->addColumn(
'expire',
Table::TYPE_TEXT,
255,
[],
'Expire'
)
->addColumn(
'order_id',
Table::TYPE_TEXT,
255,
[],
'Order ID'
)
->addColumn(
'zip_id',
Table::TYPE_TEXT,
255,
[],
'Zip ID'
)
->addIndex('token', 'token')
->addIndex('order_id', 'order_id')
->addIndex('zip_id', 'zip_id')
->setComment('Zip Orders Token Info etc.');
$installer->getConnection()->createTable($mrZipTable);
}
$configurationTableName = $installer->getTable('mr_zip_configuration');
// if exists, then this module should be installed before, just skip it. Use upgrade command to updata the table.
if ($installer->getConnection()->isTableExists($configurationTableName) != true) {
$configurationTable = $installer->getConnection()
->newTable($configurationTableName)
->addColumn(
'id',
Table::TYPE_INTEGER,
11,
[
'identity' => true,
'unsigned' => true,
'nullable' => false,
'primary' => true
],
'ID'
)
->addColumn(
'store_id',
Table::TYPE_INTEGER,
11,
[],
'Store ID'
)
->addColumn(
'min',
Table::TYPE_TEXT,
255,
[],
'Min'
)
->addColumn(
'max',
Table::TYPE_TEXT,
255,
[],
'Max'
)
->setComment('Zip Configuration Table');
$installer->getConnection()->createTable($configurationTable);
}
$installer->endSetup();
}
}
{
"name": "mr/zip",
"description": "Zip",
"require": {
"php": "~5.6.0|7.0.2|~7.0.6",
"magento/module-store": "0.74.0-beta4",
"magento/module-theme": "0.74.0-beta4",
"magento/module-widget": "0.74.0-beta4",
"magento/module-backend": "0.74.0-beta4",
"magento/module-catalog": "0.74.0-beta4",
"magento/module-email": "0.74.0-beta4",
"magento/module-ui": "0.74.0-beta4",
"magento/module-variable": "0.74.0-beta4",
"magento/module-media-storage": "0.74.0-beta4",
"magento/framework": "0.74.0-beta4",
"magento/magento-composer-installer": "*"
},
"type": "magento2-module",
"version": "0.74.0-beta4",
"license": [
"OSL-3.0",
"AFL-3.0"
],
"extra": {
"map": [
[
"*",
"MR/Zip"
]
]
}
}
\ No newline at end of file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="payment">
<group id="mr_zip" translate="label" type="text"
sortOrder="120" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Zip</label>
<field id="active" translate="label" type="select" sortOrder="100"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enabled</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="client_id" translate="label" type="text"
sortOrder="200" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Client ID</label>
</field>
<field id="client_secret" translate="label" type="password"
sortOrder="300" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Client Secret</label>
</field>
<field id="api_endpoint" translate="label" type="text" sortOrder="400"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>API Endpoint</label>
</field>
<field id="auth_token_endpoint" translate="label" type="text" sortOrder="500"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Auth Token Endpoint</label>
</field>
<field id="api_audience" translate="label" type="text"
sortOrder="600" showInDefault="1" showInWebsite="1" showInStore="1">
<label>API Audience</label>
</field>
<field id="debug_flag" translate="label" type="select" sortOrder="700"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Debug Mode</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
<field id="merchant_name" translate="label" type="text"
sortOrder="800" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Merchant Name</label>
</field>
</group>
</section>
</system>
</config>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
<default>
<payment>
<mr_zip>
<model>MR\Zip\Model\Payment</model>
<active>1</active>
<payment_action>order</payment_action>
<order_status>pending_zip</order_status>
<title>Zip</title>
<allowspecific>0</allowspecific>
<api_endpoint>https://zip.co/nz/api</api_endpoint>
<auth_token_endpoint>login.nz.zip.co/oauth/token</auth_token_endpoint>
<api_audience>https://auth.nz.zip.co</api_audience>
<min>10</min>
<max>1000</max>
<debug_flag>1</debug_flag>
<sort_order>200</sort_order>
</mr_zip>
</payment>
</default>
</config>
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="mr_zip_update_merchant_configuration" instance="MR\Zip\Cron\MerchantConfiguration" method="execute">
<schedule>0 0 * * *</schedule>
</job>
</group>
</config>
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="MR\Zip\Logger\ZipLogger">
<arguments>
<argument name="name" xsi:type="string">Zip</argument>
<argument name="handlers" xsi:type="array">
<item name="system" xsi:type="object">MR\Zip\Logger\Handler\All</item>
</argument>
</arguments>
</type>
<preference for="MR\Zip\Api\ZipManagementInterface" type="MR\Zip\Model\Api\ZipManagement" />
<preference for="MR\Zip\Api\GuestZipManagementInterface" type="MR\Zip\Model\Api\GuestZipManagement" />
</config>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Checkout\Model\CompositeConfigProvider">
<arguments>
<argument name="configProviders" xsi:type="array"><item name="mr_zip_config_provider" xsi:type="object">MR\Zip\Model\ZipConfigProvider</item>
</argument>
</arguments>
</type>
</config>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd">
<router id="standard">
<route id="zip" frontName="zip">
<module name="MR_Zip" />
</route>
</router>
</config>
\ No newline at end of file
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
<module name="MR_Zip" setup_version="1.0.0"></module>
<sequence>
<module name="Magento_Store" />
<module name="Magento_Backend"/>
<module name="Magento_Sales"/>
<module name="Magento_Quote"/>
<module name="Magento_Checkout"/>
</sequence>
</config>
<?xml version="1.0"?>
<payment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../Magento/Payment/etc/payment.xsd">
<methods>
<method name="mr_zip">
<allow_multiple_address>1</allow_multiple_address>
</method>
</methods>
</payment>
<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<!-- Managing Guest Cart Payment -->
<route url="/V1/guest-carts/:cartId/zip/selected-payment-method" method="PUT">
<service class="MR\Zip\Api\GuestZipManagementInterface" method="set"/>
<resources>
<resource ref="anonymous" />
</resources>
</route>
<!-- Managing my Cart Payment -->
<route url="/V1/carts/mine/zip/selected-payment-method" method="PUT">
<service class="MR\Zip\Api\ZipManagementInterface" method="set"/>
<resources>
<resource ref="self" />
</resources>
<data>
<parameter name="cartId" force="true">%cart_id%</parameter>
</data>
</route>
</routes>
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'MR_Zip',
__DIR__
);
\ No newline at end of file
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<head>
<title>Backend Page Title</title>
<!--
demo
<css src="MR_Zip::css/css.css"/>
<script src="MR_Zip::js/js.js"/>
<css src="jquery/fileUploader/css/jquery.fileupload-ui.css"/>
<script src="path/file.js" defer="defer"/>
<link src="http://url.com" src_type="url"/>
<remove src="path/remove/file.css"/>
-->
</head>
<body>
<referenceContainer name="content">
<block class="MR\Zip\Block\Adminhtml\Index\Index" name="zip_block_adminhtml_index_index" template="MR_Zip::zip_index_index.phtml" />
</referenceContainer>
</body>
</page>
\ No newline at end of file
<?php echo $block->escapeHtml($block->getMethod()->getTitle())?>
<?php if ($_specificInfo = $block->getSpecificInformation()):?>
<table>
<?php foreach ($_specificInfo as $_label => $_value):?>
<?php if(strtotime($_label)):?>
<tr>
<td colspan="3"><?php echo $block->escapeHtml($_label)?>:</td>
</tr>
<?php foreach ($_value as $_subKey => $_subValue):?>
<tr>
<td></td>
<td><?php echo $block->escapeHtml($_subKey)?>:</td>
<td><?php echo nl2br(implode($block->getValueAsArray($_subValue, true), "\n"))?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td><?php echo $block->escapeHtml($_label)?>:</td>
<td colspan="2"><?php echo nl2br(implode($block->getValueAsArray($_value, true), "\n"))?></td>
</tr>
<?php endif;?>
<?php endforeach; ?>
</table>
<?php endif;?>
<?php echo $block->getChildHtml()?>
Demo Backend Page Content
\ No newline at end of file
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="product.info.main">
<block name="mrzip.widget.product" before="alert.urls" class="MR\Zip\Block\Widget\Product" template="MR_Zip::widget/product.phtml"/>
</referenceContainer>
</body>
</page>
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="checkout.cart.items">
<block name="mrzip.widget.cart" after="checkout.cart.container" class="MR\Zip\Block\Widget\Cart" template="MR_Zip::widget/cart.phtml"/>
</referenceContainer>
</body>
</page>
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<head>
<css src="MR_Zip::css/zipCheckout.css" />
</head>
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="steps" xsi:type="array">
<item name="children" xsi:type="array">
<item name="billing-step" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="children" xsi:type="array">
<item name="payment" xsi:type="array">
<item name="children" xsi:type="array">
<item name="renders" xsi:type="array">
<!-- merge payment method renders here -->
<item name="children" xsi:type="array">
<item name="mr_zip_methods"
xsi:type="array">
<item name="component" xsi:type="string">MR_Zip/js/view/payment/method-renderer</item>
<item name="methods" xsi:type="array">
<item name="mr_zip" xsi:type="array">
<item name="isBillingAddressRequired" xsi:type="boolean">true</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="MR\Zip\Block\Error" name="error"
template="error.phtml" cacheable="false" />
</referenceContainer>
</body>
</page>
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="MR\Zip\Block\Processed" name="processed"
template="processed.phtml" cacheable="false" />
</referenceContainer>
</body>
</page>
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column"
xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="MR\Zip\Block\Redirect" name="redirect"
template="redirect.phtml" cacheable="false" />
</referenceContainer>
</body>
</page>
<?php /** @var $block \MR\Zip\Block\Error */ ?>
<p>Error: <?php echo htmlentities($block->getError()) ?> </p>
<?php if($block->getShowContinueButton()) :?>
<div class="actions-toolbar">
<div class="primary">
<a class="action primary continue"
href="<?php /* @escapeNotVerified */ echo $block->getUrl() ?>"><span><?php /* @escapeNotVerified */ echo __('Continue Shopping') ?></span></a>
</div>
</div>
<?php endif;?>
<?php
/**
* @see MR_Zip_Block_Zip_Info
*/
?>
<?php echo $block->escapeHtml($block->getMethod()->getTitle())?>
<?php $_displayKeys = array("CardName");
$_nameMapping = [
"CardName" => "Payment Type"
];
?>
<?php if ($_specificInfo = $block->getSpecificInformation()):?>
<table>
<?php foreach ($_specificInfo as $_label => $_value):?>
<?php if(strtotime($_label)):?>
<tr>
<td colspan="3"><?php echo $block->escapeHtml($_label)?>:</td>
</tr>
<?php foreach ($_value as $_subKey => $_subValue):?>
<?php if(!in_array($_subKey, $_displayKeys)):?>
<?php continue;?>
<?php endif;?>
<tr>
<td></td>
<td><?php echo $block->escapeHtml($_nameMapping[$_subKey])?>:</td>
<td><?php echo nl2br(implode($block->getValueAsArray($_subValue, true), "\n"))?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<?php if(!in_array($_label, $_displayKeys)):?>
<?php continue;?>
<?php endif;?>
<tr>
<td><?php echo $block->escapeHtml($_nameMapping[$_label])?>:</td>
<td colspan="2"><?php echo nl2br(implode($block->getValueAsArray($_value, true), "\n"))?></td>
</tr>
<?php endif;?>
<?php endforeach; ?>
</table>
<?php endif;?>
<?php echo $block->getChildHtml()?>
<?php
// @codingStandardsIgnoreFile
?>
<?php echo $block->getChildHtml()?>
<?php /** @var $block \MR\Zip\Block\Processed */ ?>
<div class="checkout-success">
<p>The order is processed</p>
<div class="actions-toolbar">
<div class="primary">
<a class="action primary continue"
href="<?php /* @escapeNotVerified */ echo $block->getUrl() ?>"><span><?php /* @escapeNotVerified */ echo __('Continue Shopping') ?></span></a>
</div>
</div>
</div>
<?php /** @var $block \MR\Zip\Block\Redirect */ ?>
<?php if($block->getSuccess()) :?>
<p>You will be redirected to the Zip website in a few seconds</p>
<form action="<?php echo $block->getRedirectUrl() ?>" method="get"
id="zip_redirect_form">
<input id="zip_redirect" type="submit"
value="Click here if you are not redirected within 10 seconds..." />
</form>
<script type="text/javascript">
document.getElementById("zip_redirect_form").submit();
</script>
<?php else: ?>
<p><?php echo htmlentities($block->getError()) ?> </p>
<?php if($block->getShowContinueButton()) :?>
<div class="actions-toolbar">
<div class="primary">
<a class="action primary continue"
href="<?php /* @escapeNotVerified */ echo $block->getUrl() ?>"><span><?php /* @escapeNotVerified */ echo __('Continue Shopping') ?></span></a>
</div>
</div>
<?php endif;?>
<?php endif;?>
<?php
/**
* @see \MR\Zip\Block\Widget\Cart
*/
?>
<?php echo $block->getCartWidgetHtml()?>
<?php
/**
* @see \MR\Zip\Block\Widget\Product
*/
?>
<?php echo $block->getProductWidgetHtml()?>
.cvv{
width:200px;
}
.clear{
clear: both;
}
define([ 'jquery',
'Magento_Checkout/js/model/quote',
'Magento_Checkout/js/model/url-builder',
'mage/storage',
'Magento_Checkout/js/model/error-processor',
'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/full-screen-loader',
'Magento_Customer/js/customer-data',
'Magento_Ui/js/modal/modal'],
function($, quote, urlBuilder, storage, errorProcessor, customer, fullScreenLoader, customerData, modal){
'use strict';
return function(messageContainer, module, paymentData, successAction, successActionParameters){
var serviceUrl, payload;
/**
* Checkout for guest and registered customer.
*/
if (!customer.isLoggedIn()) {
serviceUrl = urlBuilder.createUrl('/guest-carts/:cartId/:module/selected-payment-method', {
cartId : quote.getQuoteId(),
module : module
});
payload = {
cartId : quote.getQuoteId(),
email: quote.guestEmail,
method : paymentData,
billingAddress: quote.billingAddress()
};
} else {
serviceUrl = urlBuilder.createUrl('/carts/mine/:module/selected-payment-method', {module : module});
payload = {
cartId : quote.getQuoteId(),
method : paymentData,
billingAddress: quote.billingAddress()
};
}
fullScreenLoader.startLoader();
console.log("payload:" + JSON.stringify(payload));
return storage.put(serviceUrl, JSON.stringify(payload)).done(
function(response){
console.log("response from server:" + response);
successActionParameters.sessionId = response;
successAction(successActionParameters);
}).fail(
function(response){
console.log("response from server:" + response);
fullScreenLoader.stopLoader();
try {
errorProcessor.process(response, messageContainer);
}
catch (e) {
var errorResponse = { status: 500, responseText: JSON.stringify({ message: "Internal server error" }) };
errorProcessor.process(errorResponse, messageContainer);
var options = {
type: 'popup',
responsive: true,
innerScroll: true,
title: 'Internal server error.',
buttons: [{
text: $.mage.__('Continue'),
class: '',
click: function () {
this.closeModal();
}
}]
};
$('<div></div>').html('Please contact support.').modal(options).modal('openModal');
}
}).always(
function () {
customerData.invalidate(['cart']);
}
);
};
});
define(
[
'uiComponent',
'Magento_Checkout/js/model/payment/renderer-list'
],
function (
Component,
rendererList
) {
'use strict';
rendererList.push(
{
type: 'mr_zip',
component: 'MR_Zip/js/view/payment/method-renderer/zip-payment'
}
);
return Component.extend({});
}
);
/*browser:true*/
/*global define*/
define(
[
'jquery',
'ko',
'Magento_Checkout/js/view/payment/default',
'MR_Zip/js/action/set-payment',
'Magento_Checkout/js/model/payment/additional-validators',
'Magento_Customer/js/model/customer',
'Magento_Checkout/js/model/quote',
],
function ($, ko, Component, setPaymentMethodAction, additionalValidators, customer, quote) {
var zipConfig = window.checkoutConfig.payment.zip;
return Component.extend(
{
redirectToZip: function (parameters) {
window.location.replace(parameters.sessionId);
},
defaults: {
template: 'MR_Zip/payment/zip-payment'
},
getPaymentData: function () {
var additionalData = {};
if (!customer.isLoggedIn()){
additionalData["cartId"] = quote.getQuoteId();
additionalData["guestEmail"] = quote.guestEmail;
}
var data = {
'method': zipConfig.method,
'additional_data' : additionalData
};
return data;
},
continueToZip: function() {
var isValid = jQuery('#co-payment-form').validate({
errorClass: 'mage-error',
errorElement: 'div',
meta: 'validate',
errorPlacement: function (error, element) {
var errorPlacement = element;
if (element.is(':checkbox') || element.is(':radio')) {
errorPlacement = element.siblings('label').last();
}
errorPlacement.after(error);
}
}).form();
if (isValid && additionalValidators.validate()) {
setPaymentMethodAction(this.messageContainer, "zip", this.getPaymentData(), this.redirectToZip, {});
}
},
}
);
}
);
<div class="payment-method"
data-bind="css: {'_active': (getCode() == isChecked())}">
<div class="payment-method-title field choice">
<input type="radio" name="payment[method]" class="radio"
data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()" />
<label data-bind="attr: {'for': getCode()}" class="label">
<!-- zipMoney Logo -->
<img style="height:26px" src="https://static.zipmoney.com.au/logo/25px/zip.png" alt="zipMoney Acceptance Mark"
class="payment-icon"/>
<!-- zipMoney Logo -->
<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>
<div class="checkout-agreements-block">
<!-- ko foreach: $parent.getRegion('before-place-order') -->
<!-- ko template: getTemplate() -->
<!-- /ko -->
<!--/ko-->
</div>
<div class="form-alt" style="padding-top: 2em;">Zip – Own it now</div>
<!-- PaymentInformationManagement::savePaymentInformationAndPlaceOrder -->
<!-- QuoteManagement::placeOrder -->
<!-- OrderService::place -->
<div class="actions-toolbar">
<div class="primary">
<button class="action primary checkout" type="submit"
data-bind="
click: continueToZip,
attr: {title: $t('Continue to Zip')},
enable: (getCode() == isChecked())
"
disabled>
<span data-bind="i18n: 'Continue to Zip'"></span>
</button>
</div>
</div>
</div>
</div>
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