diff --git a/CHANGELOG.md b/CHANGELOG.md index c26b6b1b775..f770ec37a8e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,20 @@ ## Versioning This project does not follow a versioning standard. Versions are crafted after the dates; for example, the version 17.7.25 was released on July, 25th in 2017 + +## 20.2.24 +### Added +- Refund to iDeal payment method. +- Add column `heidelpay TxnId` to `sales_order_grid` to enable better mapping between magento order and hIP transactions. +- Enable push notifications to create an order if it does not exist already for an successful reservation or payment. +- Add PHP 7.3 support. + +### Fixed +- Made sure the reserved value matches the gross value of the order to avoid problems finalizing. + +### Remove +- PHP 5.6 support. + ## 19.10.17 ### Added - Hash validation to push requests. diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 573884be9b2..9702c8ead5b 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -2,17 +2,37 @@ namespace Heidelpay\Gateway\Controller\Index; +use Heidelpay\Gateway\Controller\HgwAbstract; +use Heidelpay\Gateway\Helper\Order as orderHelper; +use Heidelpay\Gateway\Helper\Payment as PaymentHelper; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; +use Heidelpay\PhpPaymentApi\Exceptions\XmlResponseParserException; +use Heidelpay\PhpPaymentApi\Push as heidelpayPush; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Model\Session as CustomerSession; +use Magento\Customer\Model\Url; use Heidelpay\Gateway\Helper\Response as ResponseHelper; use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Request\Http; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\Controller\ResultInterface; +use Magento\Framework\Encryption\Encryptor; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Url\Helper\Data; +use Magento\Framework\View\Result\PageFactory; +use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\QuoteRepository; +use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; use Magento\Sales\Model\Order\Email\Sender\OrderCommentSender; use Magento\Sales\Model\Order\Email\Sender\OrderSender; -use Magento\Sales\Model\Order\Payment\Transaction; use Magento\Sales\Model\Order\Invoice; +use Magento\Sales\Model\Order\Payment\Transaction; +use Magento\Sales\Model\OrderFactory; use Magento\Sales\Model\OrderRepository; -use Magento\Sales\Model\Order; -use Magento\Sales\Model\ResourceModel\Order\Collection; -use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; +use Psr\Log\LoggerInterface; /** * heidelpay Push Controller @@ -27,59 +47,65 @@ * * @package heidelpay\magento2\controllers */ -class Push extends \Heidelpay\Gateway\Controller\HgwAbstract +class Push extends HgwAbstract { /** @var OrderRepository $orderRepository */ private $orderRepository; - /** @var \Heidelpay\PhpPaymentApi\Push */ + /** @var heidelpayPush */ private $heidelpayPush; - /** @var SearchCriteriaBuilder */ - private $searchCriteriaBuilder; + /** @var QuoteRepository */ + private $quoteRepository; + /** @var orderHelper */ + private $orderHelper; /** @var ResponseHelper */ private $repsonseHelper; /** - * @param \Magento\Framework\App\Action\Context $context - * @param \Magento\Customer\Model\Session $customerSession - * @param \Magento\Checkout\Model\Session $checkoutSession - * @param \Magento\Sales\Model\OrderFactory $orderFactory - * @param \Magento\Framework\Url\Helper\Data $urlHelper - * @param \Psr\Log\LoggerInterface $logger - * @param \Magento\Quote\Api\CartManagementInterface $cartManagement - * @param \Magento\Quote\Api\CartRepositoryInterface $quoteObject - * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory - * @param \Heidelpay\Gateway\Helper\Payment $paymentHelper + * @param Context $context + * @param CustomerSession $customerSession + * @param CheckoutSession $checkoutSession + * @param OrderFactory $orderFactory + * @param Data $urlHelper + * @param LoggerInterface $logger + * @param CartManagementInterface $cartManagement + * @param CartRepositoryInterface $quoteObject + * @param PageFactory $resultPageFactory + * @param PaymentHelper $paymentHelper * @param OrderSender $orderSender * @param InvoiceSender $invoiceSender * @param OrderCommentSender $orderCommentSender - * @param \Magento\Framework\Encryption\Encryptor $encryptor - * @param \Magento\Customer\Model\Url $customerUrl + * @param Encryptor $encryptor + * @param Url $customerUrl * @param OrderRepository $orderRepository - * @param \Heidelpay\PhpPaymentApi\Push $heidelpayPush + * @param heidelpayPush $heidelpayPush * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param QuoteRepository $quoteRepository + * @param orderHelper $orderHelper * @param ResponseHelper $repsonseHelper */ public function __construct( - \Magento\Framework\App\Action\Context $context, - \Magento\Customer\Model\Session $customerSession, - \Magento\Checkout\Model\Session $checkoutSession, - \Magento\Sales\Model\OrderFactory $orderFactory, - \Magento\Framework\Url\Helper\Data $urlHelper, - \Psr\Log\LoggerInterface $logger, - \Magento\Quote\Api\CartManagementInterface $cartManagement, - \Magento\Quote\Api\CartRepositoryInterface $quoteObject, - \Magento\Framework\View\Result\PageFactory $resultPageFactory, - \Heidelpay\Gateway\Helper\Payment $paymentHelper, + Context $context, + CustomerSession $customerSession, + CheckoutSession $checkoutSession, + OrderFactory $orderFactory, + Data $urlHelper, + LoggerInterface $logger, + CartManagementInterface $cartManagement, + CartRepositoryInterface $quoteObject, + PageFactory $resultPageFactory, + PaymentHelper $paymentHelper, OrderSender $orderSender, InvoiceSender $invoiceSender, OrderCommentSender $orderCommentSender, - \Magento\Framework\Encryption\Encryptor $encryptor, - \Magento\Customer\Model\Url $customerUrl, + Encryptor $encryptor, + Url $customerUrl, OrderRepository $orderRepository, - \Heidelpay\PhpPaymentApi\Push $heidelpayPush, + heidelpayPush $heidelpayPush, + QuoteRepository $quoteRepository, + orderHelper $orderHelper, SearchCriteriaBuilder $searchCriteriaBuilder, ResponseHelper $repsonseHelper ) { @@ -103,17 +129,20 @@ public function __construct( $this->orderRepository = $orderRepository; $this->heidelpayPush = $heidelpayPush; + $this->quoteRepository = $quoteRepository; + $this->orderHelper = $orderHelper; $this->searchCriteriaBuilder = $searchCriteriaBuilder; $this->repsonseHelper = $repsonseHelper; } /** - * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface|void - * @throws \Heidelpay\PhpPaymentApi\Exceptions\XmlResponseParserException + * @return ResponseInterface|ResultInterface|void + * @throws XmlResponseParserException + * @throws NoSuchEntityException */ public function execute() { - /** @var \Magento\Framework\App\Request\Http $request */ + /** @var Http $request */ $request = $this->getRequest(); if (!$request->isPost()) { @@ -121,7 +150,7 @@ public function execute() return; } - if ($request->getHeader('Content-Type') != 'application/xml') { + if ($request->getHeader('Content-Type') !== 'application/xml') { $this->_logger->debug('Heidelpay - Push: Content-Type is not "application/xml"'); } @@ -153,80 +182,107 @@ public function execute() $pushResponse->getPayment()->getCode() ); - // in case of receipts, we process the push message for receipts. - if ($this->_paymentHelper->isReceiptAble($paymentMethod, $paymentType) && $pushResponse->isSuccess()) { - // load the referenced order to receive the order information. - $criteria = $this->searchCriteriaBuilder - ->addFilter( - 'quote_id', - $pushResponse->getIdentification()->getTransactionId() - )->create(); - - /** @var Collection $orderList */ - $orderList = $this->orderRepository->getList($criteria); - - /** @var Order $order */ - $order = $orderList->getFirstItem(); - $payment = $order->getPayment(); - - /** @var HeidelpayAbstractPaymentMethod $methodInstance */ - $methodInstance = $payment->getMethodInstance(); - $transactionID = $pushResponse->getPaymentReferenceId(); - - /** @var bool $transactionExists Flag to identify new Transaction*/ - $transactionExists = $methodInstance->heidelpayTransactionExists($transactionID); - - // If Transaction already exists, push wont be processed. - if ($transactionExists) { - $this->_logger->debug('heidelpay - Push Response: ' . $transactionID . ' already exists'); - return; - } + // Only process transactions that might potentially create new order, this includes receipts. + if ( + $pushResponse->isSuccess() && + !$pushResponse->isPending() && + $this->_paymentHelper->isNewOrderType($paymentType) + ) { + $transactionId = $pushResponse->getIdentification()->getTransactionId(); + $order = $this->orderHelper->fetchOrder($transactionId); + $quote = $this->quoteRepository->get($transactionId); - $paidAmount = (float)$pushResponse->getPresentation()->getAmount(); - $dueLeft = $order->getTotalDue() - $paidAmount; + // create order if it doesn't exists already. + if ($order === null || $order->isEmpty()) { + $transactionData = $this->_paymentHelper->getDataFromResponse($pushResponse); + $this->_paymentHelper->saveHeidelpayTransaction($pushResponse, $transactionData, 'PUSH'); + $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' + . $transactionId); - $state = Order::STATE_PROCESSING; - $comment = 'heidelpay - Purchase Complete'; + try { + $order = $this->_paymentHelper->createOrderFromQuote($quote); + if ($order === null || $order->isEmpty()) + { + $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); + return; + } + } catch (Exception $e) { + $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); + return; + } - // if payment is not complete - if ($dueLeft > 0.00) { - $state = Order::STATE_PAYMENT_REVIEW; - $comment = 'heidelpay - Partly Paid (' - . $this->_paymentHelper->format( - $pushResponse->getPresentation()->getAmount() - ) - . ' ' . $pushResponse->getPresentation()->getCurrency() . ')'; + $this->_paymentHelper->mapStatus($transactionData, $order); + $this->_logger->debug('order status: ' . $order->getStatus()); + $this->orderHelper->handleOrderMail($order); + $this->orderHelper->handleInvoiceMails($order); + $this->orderRepository->save($order); } + $this->_paymentHelper->handleAdditionalPaymentInformation($quote); + + + if ($this->_paymentHelper->isReceiptAble($paymentMethod, $paymentType)) { + // load the referenced order to receive the order information. + $payment = $order->getPayment(); + + /** @var HeidelpayAbstractPaymentMethod $methodInstance */ + $methodInstance = $payment->getMethodInstance(); + $uniqueId = $pushResponse->getPaymentReferenceId(); - // set the invoice states to 'paid', if no due is left. - if ($dueLeft <= 0.00) { - /** @var \Magento\Sales\Model\Order\Invoice $invoice */ - foreach ($order->getInvoiceCollection() as $invoice) { - $invoice->setState(Invoice::STATE_PAID)->save(); + /** @var bool $transactionExists Flag to identify new Transaction */ + $transactionExists = $methodInstance->heidelpayTransactionExists($uniqueId); + + // If Transaction already exists, push wont be processed. + if ($transactionExists) { + $this->_logger->debug('heidelpay - Push Response: ' . $uniqueId . ' already exists'); + return; } - } - $order->setTotalPaid($order->getTotalPaid() + $paidAmount) - ->setBaseTotalPaid($order->getBaseTotalPaid() + $paidAmount) - ->setState($state) - ->addStatusHistoryComment($comment, $state); - - // create a heidelpay Transaction. - $methodInstance->saveHeidelpayTransaction( - $pushResponse, - $paymentMethod, - $paymentType, - 'PUSH', - [] - ); + $paidAmount = (float)$pushResponse->getPresentation()->getAmount(); + $dueLeft = $order->getTotalDue() - $paidAmount; - // create a child transaction. - $payment->setTransactionId($transactionID) - ->setParentTransactionId($pushResponse->getIdentification()->getReferenceId()) - ->setIsTransactionClosed(true) - ->addTransaction(Transaction::TYPE_CAPTURE, null, true); + $state = Order::STATE_PROCESSING; + $comment = 'heidelpay - Purchase Complete'; - $this->orderRepository->save($order); + // if payment is not complete + if ($dueLeft > 0.00) { + $state = Order::STATE_PAYMENT_REVIEW; + $comment = 'heidelpay - Partly Paid (' + . $this->_paymentHelper->format( + $pushResponse->getPresentation()->getAmount() + ) + . ' ' . $pushResponse->getPresentation()->getCurrency() . ')'; + } + + // set the invoice states to 'paid', if no due is left. + if ($dueLeft <= 0.00) { + /** @var Invoice $invoice */ + foreach ($order->getInvoiceCollection() as $invoice) { + $invoice->setState(Invoice::STATE_PAID)->save(); + } + } + + $order->setTotalPaid($order->getTotalPaid() + $paidAmount) + ->setBaseTotalPaid($order->getBaseTotalPaid() + $paidAmount) + ->setState($state) + ->addStatusHistoryComment($comment, $state); + + // create a heidelpay Transaction. + $methodInstance->saveHeidelpayTransaction( + $pushResponse, + $paymentMethod, + $paymentType, + 'PUSH', + [] + ); + + // create a child transaction. + $payment->setTransactionId($uniqueId) + ->setParentTransactionId($pushResponse->getIdentification()->getReferenceId()) + ->setIsTransactionClosed(true) + ->addTransaction(Transaction::TYPE_CAPTURE, null, true); + + $this->orderRepository->save($order); + } } } } diff --git a/Controller/Index/Response.php b/Controller/Index/Response.php index ee96a66c1f5..9ae53495397 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -270,7 +270,7 @@ public function execute() $this->orderRepository->save($order); } - $this->handleAdditionalPaymentInformation($quote); + $this->_paymentHelper->handleAdditionalPaymentInformation($quote); $this->_logger->debug('Heidelpay - Response: redirectUrl is ' . $redirectUrl); // return the heidelpay response url as raw response instead of echoing it out. @@ -281,12 +281,13 @@ public function execute() /** * Send order confirmation to the customer - * @param $order + * @param Order $order */ protected function handleOrderMail($order) { try { if ($order && $order->getId()) { + $this->_logger->debug('heidelpay Response - sending mail for order ' . $order->getIncrementId()); $this->_orderSender->send($order); } } catch (Exception $e) { diff --git a/Gateway/Config/HgwMainConfigInterface.php b/Gateway/Config/HgwMainConfigInterface.php index 95083d0a017..5df5e580df0 100755 --- a/Gateway/Config/HgwMainConfigInterface.php +++ b/Gateway/Config/HgwMainConfigInterface.php @@ -3,7 +3,7 @@ * This class provides the interface to the HgwMainConfiguration getters. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/Helper/BasketHelper.php b/Helper/BasketHelper.php index f30d3dacaae..34006160813 100755 --- a/Helper/BasketHelper.php +++ b/Helper/BasketHelper.php @@ -4,13 +4,14 @@ use Heidelpay\Gateway\Gateway\Config\HgwMainConfigInterface; use Heidelpay\Gateway\Wrapper\ItemWrapper; use Heidelpay\Gateway\Wrapper\QuoteWrapper; +use Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException; use Heidelpay\PhpBasketApi\Object\BasketItem; use Heidelpay\PhpBasketApi\Request; use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; use Magento\Framework\App\ObjectManager; -use Magento\Framework\HTTP\ZendClientFactory; use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Item; /** * Heidelpay basket helper @@ -18,7 +19,7 @@ * The payment helper is a collection of function to prepare an send * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @link https://dev.heidelpay.de/magento * @@ -54,7 +55,7 @@ public function __construct( * @param Quote $quote * * @return Request|null - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws InvalidBasketitemPositionException */ public function convertQuoteToBasket(Quote $quote) { @@ -70,13 +71,16 @@ public function convertQuoteToBasket(Quote $quote) $basketRequest = new Request(); $basketReferenceId = $basketTotals->getBasketReferenceId(); $basket = $basketRequest->getBasket(); + + $amountGrandTotal = $basketTotals->normalizeValue($quote->getGrandTotal()); + $amountTotalNet = $basketTotals->getSubtotalWithDiscountAndShipping(); + $basket->setCurrencyCode($basketTotals->getCurrencyCode()) - ->setAmountTotalNet($basketTotals->getSubtotalWithDiscountAndShipping()) - ->setAmountTotalVat($basketTotals->getActualTaxAmount()) - ->setAmountTotalDiscount($basketTotals->getTotalDiscountAmount()) + ->setAmountTotalNet($amountTotalNet) + ->setAmountTotalVat($amountGrandTotal - $amountTotalNet) ->setBasketReferenceId($basketReferenceId); - /** @var \Magento\Quote\Model\Quote\Item $item */ + /** @var Item $item */ foreach ($quote->getAllVisibleItems() as $item) { $basketItem = ObjectManager::getInstance()->create(BasketItem::class); @@ -131,7 +135,7 @@ public function convertQuoteToBasket(Quote $quote) * @param Quote|null $quote * * @return null|string - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws InvalidBasketitemPositionException */ public function submitQuoteToBasketApi(Quote $quote = null) { diff --git a/Helper/Order.php b/Helper/Order.php new file mode 100644 index 00000000000..a3966665f3d --- /dev/null +++ b/Helper/Order.php @@ -0,0 +1,132 @@ +salesHelper = $salesHelper; + $this->invoiceSender = $invoiceSender; + $this->orderSender = $orderSender; + $this->searchCriteriaBuilder = $criteriaBuilder; + $this->orderRepository = $orderRepository; + } + + /** + * Send invoice mails to the customer. + * @param MagentoOrder $order + */ + public function handleInvoiceMails($order) + { + $debugArray = [ + 'canInvoice' => $order->canInvoice(), + 'canSendNewInvoiceEmail' => $this->salesHelper->canSendNewInvoiceEmail($order->getStore()->getId()) + ]; + $this->_logger->debug('heidelpay - handling invoices' . print_r($debugArray, 1) + ); + + if (!$order->canInvoice() && $this->salesHelper->canSendNewInvoiceEmail($order->getStore()->getId())) { + $invoices = $order->getInvoiceCollection(); + + $this->_logger->debug('sending invoices...'); + foreach ($invoices as $invoice) { + $this->invoiceSender->send($invoice); + } + } + } + + /** + * Send order confirmation to the customer. + * @param MagentoOrder $order + */ + public function handleOrderMail($order) + { + try { + if ($order && $order->getId() && !$order->getEmailSent()) { + $this->orderSender->send($order); + } + } catch (\Exception $e) { + $this->_logger->error('heidelpay - Response: Cannot send order confirmation E-Mail. ' . $e->getMessage()); + } + } + + /** + * @param $transactionId + * @return MagentoOrder + */ + public function fetchOrder($transactionId) + { + $criteria = $this->searchCriteriaBuilder->addFilter('quote_id', $transactionId)->create(); + + /** @var Collection $orderList */ + $orderList = $this->orderRepository->getList($criteria); + + return $orderList->getFirstItem(); + } +} \ No newline at end of file diff --git a/Helper/Payment.php b/Helper/Payment.php index 5ab3199c0ef..d2c11e37c66 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -4,10 +4,10 @@ use Exception; use Heidelpay\MessageCodeMapper\Exceptions\MissingLocaleFileException; use Heidelpay\MessageCodeMapper\MessageCodeMapper; +use Heidelpay\PhpPaymentApi\Constants\TransactionType; use Heidelpay\PhpPaymentApi\Constants\PaymentMethod; use Heidelpay\PhpPaymentApi\Constants\ProcessingResult; use Heidelpay\PhpPaymentApi\Constants\StatusCode; -use Heidelpay\PhpPaymentApi\Constants\TransactionType; use Heidelpay\PhpPaymentApi\Response; use Magento\Customer\Model\Group; use Magento\Framework\App\Helper\AbstractHelper; @@ -24,11 +24,14 @@ use Magento\Sales\Model\Order\Invoice; use Heidelpay\Gateway\Model\Transaction; use Heidelpay\Gateway\Model\TransactionFactory as HgwTransactionFactory; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; +use Heidelpay\Gateway\Model\ResourceModel\PaymentInformation\CollectionFactory as PaymentInformationCollectionFactory; + /** * Heidelpay payment helper * - * The payment helper is a collection of function to prepare an send + * The payment helper is a collection of function to prepare an send payment requests * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. @@ -61,6 +64,16 @@ class Payment extends AbstractHelper /** @var HgwTransactionFactory */ private $heidelpayTransactionFactory; + const NEW_ORDER_TRANSACTION_TYPE_ARRAY = [ + TransactionType::RECEIPT, + TransactionType::DEBIT, + TransactionType::RESERVATION + ]; + /** + * @var PaymentInformationCollectionFactory + */ + private $paymentInformationCollectionFactory; + /** * @param Context $context * @param ZendClientFactory $httpClientFactory @@ -75,6 +88,7 @@ public function __construct( TransactionFactory $transactionFactory, Resolver $localeResolver, QuoteManagement $cartManagement, + PaymentInformationCollectionFactory $paymentInformationCollectionFactory, HgwTransactionFactory $heidelpayTransactionFactory ) { $this->httpClientFactory = $httpClientFactory; @@ -84,6 +98,7 @@ public function __construct( parent::__construct($context); $this->_cartManagement = $cartManagement; $this->heidelpayTransactionFactory = $heidelpayTransactionFactory; + $this->paymentInformationCollectionFactory = $paymentInformationCollectionFactory; } /** @@ -117,13 +132,14 @@ public function mapStatus($data, $order, $message = false) return; } - $payment = $order->getPayment(); + /** @var HeidelpayAbstractPaymentMethod $paymentMethod */ + $paymentMethod = $order->getPayment()->getMethodInstance(); if ($data['PROCESSING_RESULT'] === ProcessingResult::NOK) { - $payment->getMethodInstance()->cancelledTransactionProcessing($order, $message); + $paymentMethod->cancelledTransactionProcessing($order, $message); } elseif ($this->isProcessing($paymentCode[1], $data)) { - $payment->getMethodInstance()->processingTransactionProcessing($data, $order); + $paymentMethod->processingTransactionProcessing($data, $order); } else { - $payment->getMethodInstance()->pendingTransactionProcessing($data, $order, $message); + $paymentMethod->pendingTransactionProcessing($data, $order, $message); } } @@ -139,6 +155,17 @@ public function format($number) return number_format($number, 2, '.', ''); } + public function getDataFromResponse(Response $response) + { + $data = []; + + foreach ($response->toArray() as $parameterKey => $value) { + $data[str_replace('.', '_', $parameterKey)] = $value; + } + + return $data; + } + /** * helper to generate customer payment error messages * @@ -153,6 +180,20 @@ public function handleError($errorCode = null) return $messageCodeMapper->getMessage($errorCode); } + public function handleInvoiceCreation($order, $paymentCode, $uniqueId) + { + $data['PAYMENT_CODE'] = $paymentCode; + if ($order->canInvoice() && !$this->isPreAuthorization($data)) { + $invoice = $order->prepareInvoice(); + + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE); + $invoice->setTransactionId($uniqueId); + $invoice->register()->pay(); + + $this->saveTransaction($invoice); + } + } + /** * Checks if the currency in the data set matches the currency in the order. * @@ -352,4 +393,40 @@ public function getPaymentMethodAndType(Response $response) { return $this->splitPaymentCode($response->getPayment()->getCode()); } + + /** + * Provide information whether a transaction type is able to create an order or not + * @param $paymentType + * @return bool + */ + public function isNewOrderType($paymentType) + { + return in_array($paymentType, self::NEW_ORDER_TRANSACTION_TYPE_ARRAY, true); + } + + /** + * If the customer is a guest, we'll delete the additional payment information, which + * is only used for customer recognition. + * @param Quote $quote + * @throws \Exception + */ + public function handleAdditionalPaymentInformation($quote) + { + if ($quote !== null && $quote->getCustomerIsGuest()) { + // create a new instance for the payment information collection. + $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); + + // load the payment information and delete it. + /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( + $quote->getStoreId(), + $quote->getBillingAddress()->getEmail(), + $quote->getPayment()->getMethod() + ); + + if (!$paymentInfo->isEmpty()) { + $paymentInfo->delete(); + } + } + } } diff --git a/Helper/Response.php b/Helper/Response.php index 2f7c439ca3b..7841ec4a4c1 100644 --- a/Helper/Response.php +++ b/Helper/Response.php @@ -14,7 +14,7 @@ /** * Heidelpay response helper * - * The response helper is a collection of function to prepare an send + * The response helper is a collection of functions to handle payment responses * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. diff --git a/Model/ResourceModel/Order/Grid/Collection.php b/Model/ResourceModel/Order/Grid/Collection.php new file mode 100644 index 00000000000..38a51ba594a --- /dev/null +++ b/Model/ResourceModel/Order/Grid/Collection.php @@ -0,0 +1,37 @@ +getSelect()->joinLeft(['t' => $subQuery], 'main_table.entity_id = t.entity_id', array('quote_id')); + + return $this; + } +} diff --git a/PaymentMethods/HeidelpayIDealPaymentMethod.php b/PaymentMethods/HeidelpayIDealPaymentMethod.php index 86365b353a6..f204eb5afa6 100644 --- a/PaymentMethods/HeidelpayIDealPaymentMethod.php +++ b/PaymentMethods/HeidelpayIDealPaymentMethod.php @@ -34,6 +34,8 @@ protected function setup() { parent::setup(); $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; } /** diff --git a/README.md b/README.md index d8911fbbee7..1c8e5b9fb75 100755 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ [![Latest Version on Packagist](https://img.shields.io/packagist/v/heidelpay/magento2.svg?style=flat-square)](https://packagist.org/packages/heidelpay/magento2) [![Codacy Badge](https://api.codacy.com/project/badge/grade/fb5b516ad21f44a591a58761a8c3ef42)](https://www.codacy.com/app/heidelpay/magento2/dashboard) -[![PHP 5.6](https://img.shields.io/badge/php-5.6-blue.svg)](http://www.php.net) [![PHP 7.0](https://img.shields.io/badge/php-7.0-blue.svg)](http://www.php.net) [![PHP 7.1](https://img.shields.io/badge/php-7.1-blue.svg)](http://www.php.net) [![PHP 7.2](https://img.shields.io/badge/php-7.2-blue.svg)](http://www.php.net) +[![PHP 7.3](https://img.shields.io/badge/php-7.3-blue.svg)](http://www.php.net) ![Logo](http://dev.heidelpay.com/devHeidelpay_400_180.jpg) @@ -29,7 +29,7 @@ For more information please visit -http://dev.heidelpay.com/magento2/ ## SYSTEM REQUIREMENTS -This extension requires PHP 5.6, PHP 7.0, PHP 7.1 or PHP 7.2. +This extension requires PHP 7.0, PHP 7.1, PHP 7.2 or PHP 7.3. It also depends on the Heidelpay php-payment-api library, which will be installed along with the plugin. ## LICENSE diff --git a/Test/Integration/BasketApiTest.php b/Test/Integration/BasketApiTest.php index 400d930d976..9c4748a5b7e 100755 --- a/Test/Integration/BasketApiTest.php +++ b/Test/Integration/BasketApiTest.php @@ -3,7 +3,7 @@ * This test class provides tests of the modules integration with the basket-api. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * @@ -14,6 +14,7 @@ use Heidelpay\Gateway\Helper\BasketHelper; use Heidelpay\Gateway\Helper\Payment; use Heidelpay\Gateway\Wrapper\QuoteWrapper; +use Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException; use Heidelpay\PhpBasketApi\Object\Basket; use Heidelpay\PhpBasketApi\Object\BasketItem; use Magento\Catalog\Model\Product\Attribute\Source\Status; @@ -21,9 +22,11 @@ use Magento\Catalog\Model\Product\Visibility; use Magento\Catalog\Model\Product; use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Customer\Api\Data\CustomerInterfaceFactory; use Magento\Customer\Model\Customer; use Magento\Customer\Model\Group; +use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\ObjectManagerInterface; use Magento\Quote\Api\CartItemRepositoryInterface; use Magento\Quote\Api\CartManagementInterface; @@ -38,6 +41,8 @@ use Magento\SalesRule\Model\Rule; use \Magento\Quote\Model\Quote; use Magento\OfflineShippingSampleData\Model\Tablerate; +use Magento\Customer\Model\CustomerFactory; +use Magento\Customer\Model\AddressFactory; class BasketApiTest extends AbstractController { @@ -108,19 +113,7 @@ public function setUp() $this->paymentHelper = $this->getObject(Payment::class); } - /** - * @return array - */ - public function verifyBasketHasSameValueAsApiCallDP() - { - return [ - 'No coupon' => [null], - 'fixed cart 20 EUR coupon' => ['COUPON_FIXED_CART_20_EUR'], - '20 percent coupon /wo shipping' => ['COUPON_20_PERC_WO_SHIPPING'] - // Test deaktiviert, weil Magento bei Rabatt auf Shipping die MwSt nicht richtig berechnet. - // '20 percent coupon /w shipping' => ['COUPON_20_PERC_W_SHIPPING'] - ]; - } + // /** * @dataProvider verifyBasketHasSameValueAsApiCallDP @@ -134,7 +127,10 @@ public function verifyBasketHasSameValueAsApiCallDP() * * @test * @param $couponCode - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws InvalidBasketitemPositionException + * @throws NoSuchEntityException */ public function verifyBasketHasSameValueAsApiCall($couponCode) { @@ -154,7 +150,10 @@ public function verifyBasketHasSameValueAsApiCall($couponCode) * * @test * @param $couponCode - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws InvalidBasketitemPositionException + * @throws NoSuchEntityException */ public function verifyBasketHasSameValueAsApiCallPlusTaxes($couponCode) { @@ -175,7 +174,10 @@ public function verifyBasketHasSameValueAsApiCallPlusTaxes($couponCode) * * @test * @param $couponCode - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws InvalidBasketitemPositionException + * @throws NoSuchEntityException */ public function verifyBasketHasSameValueAsApiCallPlusTaxesPlusShippingTax($couponCode) { @@ -185,7 +187,10 @@ public function verifyBasketHasSameValueAsApiCallPlusTaxesPlusShippingTax($coupo /** * @param $couponCode * @return array - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws NoSuchEntityException */ private function performCheckout($couponCode) { @@ -235,6 +240,8 @@ private function performCheckout($couponCode) return array($quote, $basket); } + // + // /** @@ -272,16 +279,16 @@ private function getObjectManager() private function generateCustomerFixture() { - /** @var \Magento\Tax\Model\ClassModel $customerTaxClass */ + /** @var ClassModel $customerTaxClass */ $customerTaxClass = $this->createObject(ClassModel::class); $customerTaxClass->load('Retail Customer', 'class_name'); - /** @var \Magento\Customer\Model\Group $customerGroup */ + /** @var Group $customerGroup */ $customerGroup = $this->createObject(Group::class) ->load('custom_group', 'customer_group_code'); $customerGroup->setTaxClassId($customerTaxClass->getId())->save(); - $customerFactory = $this->getObject('\Magento\Customer\Model\CustomerFactory'); + $customerFactory = $this->getObject(CustomerFactory::class); /** @var CustomerInterface $customer */ $customer = $customerFactory->create() ->setEmail('l.h@mail.com') @@ -291,7 +298,7 @@ private function generateCustomerFixture() ->setGroupId($customerGroup->getId()) ->save(); - $addressFactory = $this->getObject('\Magento\Customer\Model\AddressFactory'); + $addressFactory = $this->getObject(AddressFactory::class); $addressFactory->create() ->setCustomerId($customer->getId()) ->setFirstname('Linda') @@ -330,8 +337,8 @@ private function generateProductFixtures($number) ->setName('Simple Product ' . $idx) ->setSku('simple' . $idx) ->setPrice($price) - ->setData('news_from_date', null) - ->setData('news_to_date', null) + ->setData('news_from_date') + ->setData('news_to_date') ->setVisibility(Visibility::VISIBILITY_BOTH) ->setStatus(Status::STATUS_ENABLED) ->setStockData( @@ -401,7 +408,7 @@ private function printItemsAndSums($basket) echo "\nProducts in Basket:"; /** @var BasketItem $basketItem */ foreach ($basket->getBasketItems() as $key => $basketItem) { - if ('Discount' !== $basketItem->getTitle()) { + if ($basketItem->getTitle() !== 'Discount') { echo "\nProduct #" . $key . ': ' . $basketItem->getTitle() . "\t" . $basketItem->getQuantity() . "x \t" . @@ -427,7 +434,10 @@ private function printBasketValues($quote) /** * @param $couponCode - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws InvalidBasketitemPositionException + * @throws NoSuchEntityException */ private function assertResult($couponCode) { @@ -449,4 +459,20 @@ private function assertResult($couponCode) } // + + // + /** + * @return array + */ + public function verifyBasketHasSameValueAsApiCallDP() + { + return [ + 'No coupon' => [null], + 'fixed cart 20 EUR coupon' => ['COUPON_FIXED_CART_20_EUR'], + '20 percent coupon /wo shipping' => ['COUPON_20_PERC_WO_SHIPPING'] + // Test deaktiviert, weil Magento bei Rabatt auf Shipping die MwSt nicht richtig berechnet. + // '20 percent coupon /w shipping' => ['COUPON_20_PERC_W_SHIPPING'] + ]; + } + // } diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php new file mode 100644 index 00000000000..5903964ff71 --- /dev/null +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -0,0 +1,345 @@ + + * + * @package heidelpay/magento2 + */ + +namespace Heidelpay\Gateway\Test\Integration\Controller\Index; + + +use Heidelpay\Gateway\Helper\Response as ResponseHelper; +use Heidelpay\Gateway\Model\ResourceModel\Transaction\Collection; +use Heidelpay\Gateway\Model\Transaction; +use Heidelpay\Gateway\Test\Integration\data\provider\PushResponse; +use Heidelpay\Gateway\Test\Integration\IntegrationTestAbstract; +use Heidelpay\Gateway\Test\Mocks\Helper\Response as ResponseHelperMock; +use Heidelpay\PhpPaymentApi\Constants\TransactionType; +use Magento\Customer\Api\CustomerManagementInterface; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Model\Customer; +use Magento\Framework\App\Request\Http; +use Magento\Framework\Exception\CouldNotSaveException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Payment; +use Magento\Sales\Model\Order; +use SimpleXMLElement; +use Zend\Http\Headers; + + +/** + * @inheritDoc + * + * @property Http $_request + * + * @method Http getResponse() + * + */ +class PushHandlingTest extends IntegrationTestAbstract +{ + const CONTROLLER_PATH = 'hgw/index/push'; + + public $loggerMock; + + public function setUp() + { + parent::setUp(); + + /** @var Http $request */ + $request = $this->getRequest(); + + /** Set Request type */ + $request->setMethod($request::METHOD_POST); + $request->setHeaders(Headers::fromString('content-type: application/xml')); + } + + public static function loadFixture() + { + include __DIR__ . '/../../_files/products.php'; + include __DIR__ . '/../../_files/categories.php'; + include __DIR__ . '/../../_files/coupons.php'; + include __DIR__ . '/../../_files/customer.php'; + } + + /** + * @test + * + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function EmptyRequest() + { + $request = $this->getRequest(); + $request->setMethod($request::METHOD_GET); + + $this->dispatch(self::CONTROLLER_PATH); + $this->getResponse(); + $response = $this->getResponse()->getBody(); + $this->assertEmpty($response, $response); + } + + /** + * Test creation of new order via push if no order exists already. + * + * @test + * + * @dataProvider dataProviderPushCreatesNewTransactionDP + * @magentoDbIsolation enabled + * + * @magentoDataFixture loadFixture + * @magentoConfigFixture default/currency/options/default EUR + * @magentoConfigFixture default/currency/options/base EUR + * @magentoConfigFixture default_store currency/options/allow EUR + * @param string $paymentCode + * @param $paymentMethod + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function PushCreatesNewTransaction($paymentCode, $paymentMethod) + { + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->assertQuoteHasNoOrder($quote); + $this->dispatch(self::CONTROLLER_PATH); // Call push controller. + + /** Evaluate end results. Quote, Order, Transaction */ + $this->assertQuoteActive($quote->getId(), false); + + /** @var Order $order */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertFalse($fetchedOrder->isEmpty(), 'Order creation failed: Order is empty'); + + $uniqueId = $xml->Transaction->Identification->UniqueID; + $this->assertMagentoTransactionExists($uniqueId); + + // Check Amounts + $this->assertEquals( + $xml->Transaction->Payment->Clearing->Amount, + $fetchedOrder->getGrandTotal(), + 'Grand total amount doesn\'t match'); + + + $shouldBeMarkedAsPaid = TransactionType::RESERVATION !== $this->paymentHelper->splitPaymentCode($paymentCode)[1]; + if ($shouldBeMarkedAsPaid) { + $this->assertEquals( + (float)$xml->Transaction->Payment->Clearing->Amount, + (float)$fetchedOrder->getTotalPaid(), + 'Order state: ' .$fetchedOrder->getStatus() .'. Total paid amount doesn\'t match'); + + $this->assertEquals('processing', $fetchedOrder->getState()); + } + + } + + /** Data provider for transaction types that should create new order. + * @return array + */ + public function dataProviderPushCreatesNewTransactionDP() + { + return [ + 'Create order from invoice receipt ' => ['IV.RC', 'hgwivs'], + 'Create order from credit card debit' => ['CC.DB', 'hgwcc'], + 'Create order from sofort receipt' => ['OT.RC', 'hgwsue'], + 'Create order from sofort reservation' => ['OT.PA', 'hgwsue'], + 'Create order from prepayment receipt' => ['PP.RC', 'hgwpp'], + ]; + } + + /** Data provider for transaction types that should NOT create new order. + * @return array + */ + public function CreateNoOrderFromInvalidTransactionTypesDP() + { + return [ + 'Create no order from invoice reversal' => ['IV.RV', 'hgwivs'], + 'Create no order from credit card refund' => ['CC.RF', 'hgwcc'], + 'Create no order from invoice init' => ['IV.IN', 'hgwivs'], + 'Create no order from invoice finalize' => ['IV.FI', 'hgwivs'], + ]; + } + + /** + * No order should be created for transaction types other then defined. + * + * @test + * @dataProvider CreateNoOrderFromInvalidTransactionTypesDP + * @magentoDbIsolation enabled + * + * @magentoDataFixture loadFixture + * @magentoConfigFixture default/currency/options/default EUR + * @magentoConfigFixture default/currency/options/base EUR + * @magentoConfigFixture default_store currency/options/allow EUR + * @param string $paymentCode + * @param $paymentMethod + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + public function CreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) + { + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->assertQuoteHasNoOrder($quote); + $this->dispatch(self::CONTROLLER_PATH); + + /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + $this->assertQuoteActive($quote->getId(), true); + + /** @var Order $order */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($fetchedOrder->isEmpty(), 'No Order should be created here'); + + // Check Transaction + /** @var Collection $collection */ + $collection = $this->transactionFactory->create(); + + /** @var Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); + $this->assertNotNull($heidelpayTransaction); + $this->assertTrue($heidelpayTransaction->isEmpty()); + } + + /** + * @param $paymentMethod + * @return array + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + protected function generateQuote($paymentMethod) + { + $quoteId = $this->cartManagement->createEmptyCart(); + /** @var CustomerManagementInterface $customerRepository */ + $customerRepository = $this->createObject(CustomerRepositoryInterface::class); + + /** @var Customer|CustomerInterface $customer */ + $customer = $customerRepository->get('l.h@mail.com'); + + /** Create a cart | Sometimes also create an order for that cart.*/ + /** @var Quote $quote */ + $quote = $this->quoteRepository->get($quoteId); + + $product = $this->productRepository->getById('1'); + $quote->addProduct($product); + + $product = $this->productRepository->getById('2'); + $quote->assignCustomer($customer); + $quote->addProduct($product); + + /** @var Payment $payment */ + $quote->getPayment()->setMethod($paymentMethod); + //$quote->getBillingAddress()->addData($addressData); + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setCustomerId($customer->getId()) + ->collectShippingRates() + ->setFreeShipping(true) + ->setShippingMethod('flatrate_flatrate') + ->setPaymentMethod('hgwcc'); + + $quote->collectTotals()->save(); + return array($customer, $quote); + } + + /** + * @param $paymentCode + * @param Quote $quote + * @param Customer $customer + * @return SimpleXMLElement + */ + protected function preparePushNotification($paymentCode, Quote $quote, $customer) + { + /** @var PushResponse $pushProvider */ + $pushProvider = $this->createObject(PushResponse::class); + + $pushSpecification = [ + 'TransactionID' => $quote->getId(), + 'Amount' => $quote->getGrandTotal(), + 'ShopperID' => $customer->getId() + ]; + + /** @var SimpleXMLElement $xml */ + $xml = new SimpleXMLElement($pushProvider->providePushXml($pushSpecification)); + $xml->Transaction->Payment->addAttribute('code', $paymentCode); + return $xml; + } + + /** + * @param $paymentCode + * @param $paymentMethod + * @return array + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException + */ + protected function prepareRequest($paymentCode, $paymentMethod) + { + /** Disable hash validation */ + $this->getObjectManager()->configure( + ['preferences' => [ResponseHelper::class => ResponseHelperMock::class]] + ); + + /** Prepare data. Quote, Customer, XML */ + list($customer, $quote) = $this->generateQuote($paymentMethod); + + /** @var PushResponse $pushProvider */ + $xml = $this->preparePushNotification($paymentCode, $quote, $customer); + + /** Perform the actual test request on controller */ + $this->getRequest()->setContent($xml->saveXML()); + return array($quote, $xml); + } + + /** Assert that magento transaction with given unique id exists. + * @param $uniqueId + */ + private function assertMagentoTransactionExists($uniqueId) + { + $collection = $this->transactionFactory->create(); + /** @var Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($uniqueId); + $this->assertNotNull($heidelpayTransaction); + $this->assertFalse($heidelpayTransaction->isEmpty()); + } + + /** Assertions that Quote should exists but order doesn't. + * @param $quote + * @return void + */ + private function assertQuoteHasNoOrder(Quote $quote) + { + /** @var Order $fetchedOrder */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($fetchedOrder->isEmpty()); + $this->assertNotNull($quote); + } + + /** Assertion whether quote should be active or not. + * @param $quoteId + * @param bool $expectIsActive + * @throws NoSuchEntityException + */ + private function assertQuoteActive($quoteId, $expectIsActive) + { + $fetchedQuote = $this->quoteRepository->get($quoteId); + $this->assertNotNull($fetchedQuote); + + $message = 'New order was created - Quote should NOT be active anymore!'; + if ($expectIsActive === true) { + $message = 'No order was created - Quote should still be active!'; + } + + $isActive = $fetchedQuote->getIsActive() === '1'; + + $this->assertEquals( + $expectIsActive, + $isActive, + $message); + } +} diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php new file mode 100644 index 00000000000..81f9814b89f --- /dev/null +++ b/Test/Integration/IntegrationTestAbstract.php @@ -0,0 +1,285 @@ + + * + * @package heidelpay/magento2 + */ +namespace Heidelpay\Gateway\Test\Integration; + +use Heidelpay\Gateway\Helper\BasketHelper; +use Heidelpay\Gateway\Helper\Order as OrderHelper; +use Heidelpay\Gateway\Helper\Payment; +use Heidelpay\PhpBasketApi\Object\Basket; +use Heidelpay\PhpBasketApi\Object\BasketItem; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Type; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\Product; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Customer\Api\Data\CustomerInterfaceFactory; +use Magento\Customer\Model\Customer; +use Magento\Customer\Model\Group; +use Magento\Framework\ObjectManagerInterface; +use Magento\Quote\Api\CartItemRepositoryInterface; +use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Api\CouponManagementInterface; +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Quote\Api\Data\CartItemInterface; +use Magento\Tax\Model\ClassModel; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\AbstractController; +use \Magento\Quote\Model\Quote; +use Magento\OfflineShippingSampleData\Model\Tablerate; +use Heidelpay\Gateway\Model\ResourceModel\Transaction\CollectionFactory as HeidelpayTransactionCollectionFactory; + + +class IntegrationTestAbstract extends AbstractController +{ + const ENABLE_DEBUG_OUTPUT = false; + + const NUMBER_OF_PRODUCTS = 3; + + /** + * @var Customer $customerFixture + */ + protected $customerFixture; + + /** + * @var array $productFixture + */ + protected $productFixtures = []; + + /** + * @var CouponManagementInterface $couponManagement + */ + protected $couponManagement; + + /** + * @var CartManagementInterface $cartManagement + */ + protected $cartManagement; + + /** + * @var CartItemRepositoryInterface $cartItemRepository + */ + protected $cartItemRepository; + + /** + * @var CartRepositoryInterface $quoteRepo + */ + protected $quoteRepository; + + /** + * @var Payment $paymentHelper + */ + protected $paymentHelper; + + /** + * @var BasketHelper $basketHelper + */ + protected $basketHelper; + protected $productRepository; + /** @var OrderHelper $orderHelper */ + protected $orderHelper; + /** @var HeidelpayTransactionCollectionFactory\ */ + protected $transactionFactory; + + /** + * {@inheritDoc} + */ + public function setUp() + { + parent::setUp(); + echo self::ENABLE_DEBUG_OUTPUT ? "\n\n\n" : ''; + + $this->transactionFactory = $this->createObject(HeidelpayTransactionCollectionFactory::class); + $this->orderHelper = $this->createObject(OrderHelper::class); + $this->productRepository = $this->createObject(ProductRepositoryInterface::class); + $this->couponManagement = $this->createObject(CouponManagementInterface::class); + $this->cartManagement = $this->createObject(CartManagementInterface::class); + $this->cartItemRepository = $this->createObject(CartItemRepositoryInterface::class); + $this->quoteRepository = $this->getObject(CartRepositoryInterface::class); + $this->basketHelper = $this->getObject(BasketHelper::class); + $this->paymentHelper = $this->getObject(Payment::class); + } + + /** + * @return ObjectManagerInterface + */ + protected function getObjectManager() + { + if (!($this->_objectManager instanceof ObjectManagerInterface)) { + $this->_objectManager = Bootstrap::getObjectManager(); + } + return $this->_objectManager; + } + + /** + * @param string $class + * @param array $params + * @return mixed + */ + protected function createObject($class, array $params = []) + { + return $this->getObjectManager()->create($class, $params); + } + + /** + * @param string $class + * @return mixed + */ + protected function getObject($class) + { + return $this->getObjectManager()->get($class); + } + + protected function performCheckout($couponCode) + { + $cartId = $this->cartManagement->createEmptyCart(); + + /** @var Product $productFixture */ + foreach ($this->productFixtures as $productFixture) { + $quantity = mt_rand(1, 3); + + /** @var CartItemInterface $quoteItem */ + $quoteItem = $this->createObject(CartItemInterface::class); + $quoteItem->setQuoteId($cartId); + $quoteItem->setProduct($productFixture); + $quoteItem->setQty($quantity); + $this->cartItemRepository->save($quoteItem); + } + + if ($couponCode !== null) { + $this->couponManagement->set($cartId, $couponCode); + } + + /** + * @var Quote $quote + */ + $quote = $this->quoteRepository->get($cartId); + $quote->getShippingAddress() + ->setCustomerId($this->customerFixture->getId()) + ->setFirstname('Linda') + ->setLastname('Heideich') + ->setCountryId('DE') + ->setPostcode('69115') + ->setCity('Heidelberg') + ->setTelephone(1234567890) + ->setFax(123456789) + ->setStreet('Vangerowstr. 18') + ->setShippingMethod('tablerate_bestway') + ->save(); + + /** @var Basket $basket */ + $basket = $this->basketHelper->convertQuoteToBasket($quote)->getBasket(); + + if (self::ENABLE_DEBUG_OUTPUT) { + $this->printBasketValues($quote); + $this->printItemsAndSums($basket); + } + + return $quote; + } + + protected function generateCustomerFixture() + { + /** @var \Magento\Tax\Model\ClassModel $customerTaxClass */ + $customerTaxClass = $this->createObject(ClassModel::class); + $customerTaxClass->load('Retail Customer', 'class_name'); + + /** @var \Magento\Customer\Model\Group $customerGroup */ + $customerGroup = $this->createObject(Group::class) + ->load('custom_group', 'customer_group_code'); + $customerGroup->setTaxClassId($customerTaxClass->getId())->save(); + + $customerFactory = $this->getObject('\Magento\Customer\Model\CustomerFactory'); + /** @var CustomerInterface $customer */ + $customer = $customerFactory->create() + ->setEmail('l.h@mail.com') + ->setFirstname('Linda') + ->setLastname('Heideich') + ->setPassword('123456789') + ->setGroupId($customerGroup->getId()) + ->save(); + + $addressFactory = $this->getObject('\Magento\Customer\Model\AddressFactory'); + $addressFactory->create() + ->setCustomerId($customer->getId()) + ->setFirstname('Linda') + ->setLastname('Heideich') + ->setCountryId('DE') + ->setPostcode('69115') + ->setCity('Heidelberg') + ->setTelephone(1234567890) + ->setFax(123456789) + ->setStreet('Vangerowstr. 18') + ->setIsDefaultBilling('1') + ->setIsDefaultShipping('1') + ->setSaveInAddressBook('1') + ->save(); + + $this->customerFixture = $customer; + } + + protected function generateProductFixtures($number) + { + /** @var ClassModel $productTaxClass */ + $productTaxClass = $this->createObject(ClassModel::class); + $productTaxClass->load('Taxable Goods', 'class_name'); + + // create product fixtures + for ($idx = 1; $idx <= $number; $idx++) { + $price = (mt_rand(1, 30000) / 100); + + /** @var Product $product */ + $product = $this->createObject(Product::class); + $product + ->setId($idx+2) + ->setTypeId(Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product ' . $idx) + ->setSku('simple' . $idx) + ->setPrice($price) + ->setData('news_from_date', null) + ->setData('news_to_date', null) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED) + ->setStockData( + ['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1] + ) + ->setUrlKey('url-key' . $idx) + ->setTaxClassId($productTaxClass->getId()) + ->save(); + + $this->productFixtures[] = $product; + } + } + + /** + * @param string $title + * @param array $data + */ + protected function echoToConsole($title, array $data = []) + { + echo "\n" . $title . ': ' . print_r($data, true); + } + + /** + * @param string $title + * @param array $data + */ + protected function debugOutput($title, array $data = []) + { + if (self::ENABLE_DEBUG_OUTPUT) { + $this->echoToConsole($title); + } + } + +} \ No newline at end of file diff --git a/Test/Integration/_files/categories.php b/Test/Integration/_files/categories.php new file mode 100644 index 00000000000..6fe6bff0bd4 --- /dev/null +++ b/Test/Integration/_files/categories.php @@ -0,0 +1,26 @@ + + * + * @package heidelpay/magento2 + */ + +/** @var $category \Magento\Catalog\Model\Category */ +$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(Magento\Catalog\Model\Category::class); +$category->isObjectNew(true); +$category->setId(3) + ->setName('Category 1') + ->setParentId(2) + ->setPath('1/2/3') + ->setLevel(2) + ->setAvailableSortBy('name') + ->setDefaultSortBy('name') + ->setIsActive(true) + ->setPosition(1) + ->setData('display_mode', 'new_products') + ->save(); \ No newline at end of file diff --git a/Test/Integration/_files/customer.php b/Test/Integration/_files/customer.php new file mode 100644 index 00000000000..4aa69ac64fd --- /dev/null +++ b/Test/Integration/_files/customer.php @@ -0,0 +1,57 @@ + + * + * @package heidelpay/magento2 + */ + +$yesterday = new DateTime(); +$yesterday->sub(new \DateInterval('P1D')); +$tomorrow= new DateTime(); +$tomorrow->add(new \DateInterval('P1D')); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var $product \Magento\Catalog\Model\Product */ +$customerFactory = $objectManager->create(Magento\Customer\Api\Data\CustomerInterface::class); + +/** @var \Magento\Tax\Model\ClassModel $customerTaxClass */ +$customerTaxClass = $objectManager->create(Magento\Tax\Model\ClassModel::class); +$customerTaxClass->load('Retail Customer', 'class_name'); + +/** @var \Magento\Customer\Model\Group $customerGroup */ +$customerGroup = $objectManager->create(Magento\Customer\Model\Group::class) + ->load('custom_group', 'customer_group_code'); +$customerGroup->setTaxClassId($customerTaxClass->getId())->save(); + +$customerFactory = $objectManager->get('\Magento\Customer\Model\CustomerFactory'); +/** @var CustomerInterface $customer */ +$customer = $customerFactory->create() + ->setEmail('l.h@mail.com') + ->setFirstname('Linda') + ->setLastname('Heideich') + ->setPassword('123456789') + ->setGroupId($customerGroup->getId()) + ->save(); + +$addressFactory = $objectManager->get('\Magento\Customer\Model\AddressFactory'); +$addressFactory->create() + ->setCustomerId($customer->getId()) + ->setFirstname('Linda') + ->setLastname('Heideich') + ->setCountryId('DE') + ->setPostcode('69115') + ->setCity('Heidelberg') + ->setTelephone(1234567890) + ->setFax(123456789) + ->setStreet('Vangerowstr. 18') + ->setIsDefaultBilling('1') + ->setIsDefaultShipping('1') + ->setSaveInAddressBook('1') + ->setIncrementId(2) + ->save(); \ No newline at end of file diff --git a/Test/Integration/_files/products.php b/Test/Integration/_files/products.php new file mode 100644 index 00000000000..40b2e8c523a --- /dev/null +++ b/Test/Integration/_files/products.php @@ -0,0 +1,58 @@ + + * + * @package heidelpay/magento2 + */ + +$yesterday = new DateTime(); +$yesterday->sub(new \DateInterval('P1D')); +$tomorrow= new DateTime(); +$tomorrow->add(new \DateInterval('P1D')); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create('Magento\Catalog\Model\Product'); +$product + ->setId(1) + ->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product 1') + ->setSku('simple1') + ->setPrice(10) + ->setData('news_from_date', $yesterday->format('Y-m-d H:i:s')) + ->setData('news_to_date', $tomorrow->format('Y-m-d H:i:s')) + ->setDescription('Description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setCategoryIds([2]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setUrlKey('my-url-key') + ->save(); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create('Magento\Catalog\Model\Product'); +$product + ->setId(2) + ->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Simple Product 2') + ->setSku('simple2') + ->setPrice(10) + ->setData('news_from_date', null) + ->setData('news_to_date', null) + ->setDescription('Description') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setCategoryIds([2]) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setUrlKey('my-url-key2') + ->save(); \ No newline at end of file diff --git a/Test/Integration/data/provider/PushResponse.php b/Test/Integration/data/provider/PushResponse.php new file mode 100644 index 00000000000..a18ee739166 --- /dev/null +++ b/Test/Integration/data/provider/PushResponse.php @@ -0,0 +1,111 @@ + + * + * @package heidelpay/magento2 + */ + +namespace Heidelpay\Gateway\Test\Integration\data\provider; + + +use SimpleXMLElement; + +class PushResponse +{ + public $xmlString = << + + + + 521 + 31HA07BC819A0F7EF2A6A76B5818D34D + 4242.8118.4858 + 2 + 31HA07BC819A0F7EF2A68B79A7E2E9C9 + DE00000000000000000000 + + + 2019-06-12 15:53:04 + ACK + NEW + SUCCESSFULL + Request successfully processed in 'Merchant in Connector Test Mode' + + + + 53.55 + EUR + 4242.8116.1848 Heidelpay QA + + + 53.55 + EUR + 4242.8116.1848 Heidelpay QA + + + + + DE + HEIDELPAYXY + 10000000 + 1234567890 + Heidelpay QA + DE01000000001234567890 + 4260.7131.1424 + + + + + SOFORT + 4242.8116.1848 + + + + Lemon + Mustermann + +
+ Hugo-Jünkers Straße 491 + 60386 + Frankfurt am Main + DE +
+ + david.owusu@heidelpay.de + +
+ + https://test-heidelpay.hpcgw.net/ngw/responsePa?state=9158be8fffffffff17fcff09 + + + d83f0dae2fca921d00cb70559762a365e55870e0cad5384177a931379e04d0204fb8d01ee16ef109f27ec67fb181e748d688119cf82966f59ab1db476d460a5e + false + + 2019-06-12 15:53:04 +
+
+XML; + + /** + * Provides a Xml template string for testing purposes. Its not completely authentic since it also contains a Connector node. + * + * @param array $specifyValue + * @return null|string|string[] + */ + public function providePushXml(array $specifyValue = []) + { + $xmlString = $this->xmlString; + foreach ($specifyValue as $key => $value) { + $pattern = '/<' .$key. '>.*<\/'.$key.'>/'; + $replacement = '<' . $key . '>'. $value . ''; + $xmlString = preg_replace($pattern, $replacement, $xmlString); + } + + return $xmlString; + } +} \ No newline at end of file diff --git a/Test/Integration/fixtures/Response/Push/push.xml b/Test/Integration/fixtures/Response/Push/push.xml new file mode 100644 index 00000000000..35fb33b0db0 --- /dev/null +++ b/Test/Integration/fixtures/Response/Push/push.xml @@ -0,0 +1,79 @@ + + + + + 63 + 31HA07BC81261C093AD2ACE322B1EEBC + 4247.1348.1822 + 2 + HPC + DE87ZZZ00000019937 + + + 2019-06-17 15:58:01 + ACK + NEW + SUCCESSFULL + Request successfully processed in 'Merchant in Connector Test Mode' + + + + 53.55 + EUR + 4247.1348.1822 Heidelpay QA + 2019-06-17 15:58:01 + +49 (0) 6543210123 + + + 53.55 + EUR + + + + + DE + HEIDELPAYXY + 10000000 + 1234567890 + Heidelpay QA + DE01000000001234567890 + 4247.1348.1822 + + + + + Lemon + Mustermann + MR + 1986-03-21 + +
+ Hugo-Jünkers Straße 491 + 60386 + Frankfurt am Main + DE +
+ + david.owusu@heidelpay.de + +
+ + https://test-heidelpay.hpcgw.net/ngw?state=cc35f464ffffffff0e4a125f + + + InvoiceB2CSecuredPaymentMethod + Heidelpay\PhpPaymentApi + Heidelpay Gateway 19.5.08 + ed2e8ffd124b43049b1f516a61e97f158391f987133b86bfcd572cf5bd9a23c1da06d353f88c4bbbda83ac3013f2a89663f48a69a78615bfa0e099a460ee5525 + v1.8.0 + http://qa.heidelpay.intern/david/magento/v2/default/hgw/index/push/ + Magento 2.2.8-Community + false + ACCEPTED + + 2019-06-17 15:58:01 + + 2019-06-27 15:58:02 + +
+
\ No newline at end of file diff --git a/Test/Mocks/Helper/Response.php b/Test/Mocks/Helper/Response.php new file mode 100644 index 00000000000..63e97164d67 --- /dev/null +++ b/Test/Mocks/Helper/Response.php @@ -0,0 +1,29 @@ + + * + * @package heidelpay/magento2 + */ + +namespace Heidelpay\Gateway\Test\Mocks\Helper; + + +use Heidelpay\Gateway\Helper\Response as ResponseHelper; + +class Response extends ResponseHelper +{ + /** Returns always true in order to bypass it for the tests. + * @param \Heidelpay\PhpPaymentApi\Response $response + * @param $remoteAddress + * @return bool + */ + public function validateSecurityHash($response, $remoteAddress) + { + return true; + } +} \ No newline at end of file diff --git a/Traits/DumpGetterReturnsTrait.php b/Traits/DumpGetterReturnsTrait.php index 2e98f042974..411c9da0546 100755 --- a/Traits/DumpGetterReturnsTrait.php +++ b/Traits/DumpGetterReturnsTrait.php @@ -3,7 +3,7 @@ * This trait enables to dump all simple getter return values into an array extracting the keys from the getter names. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/Wrapper/BaseWrapper.php b/Wrapper/BaseWrapper.php index 7c1950f7919..a85b701a402 100755 --- a/Wrapper/BaseWrapper.php +++ b/Wrapper/BaseWrapper.php @@ -3,7 +3,7 @@ * This is the base for all wrappers containing shared code. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/Wrapper/CustomerWrapper.php b/Wrapper/CustomerWrapper.php index b9aaf75c75c..f2cf5041e54 100644 --- a/Wrapper/CustomerWrapper.php +++ b/Wrapper/CustomerWrapper.php @@ -3,7 +3,7 @@ * This wrapper helps gathering information about a given customer. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2019-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2019-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/Wrapper/ItemWrapper.php b/Wrapper/ItemWrapper.php index 1008a11587e..fa9354f29dd 100755 --- a/Wrapper/ItemWrapper.php +++ b/Wrapper/ItemWrapper.php @@ -3,7 +3,7 @@ * This class wraps item objects to provide the values already adapted for the communication with the basket-api. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/Wrapper/QuoteWrapper.php b/Wrapper/QuoteWrapper.php index 4118aef1e0e..94e1a35c2e9 100755 --- a/Wrapper/QuoteWrapper.php +++ b/Wrapper/QuoteWrapper.php @@ -3,7 +3,7 @@ * This class wraps quote objects to provide the values already adapted for the communication with the basket-api. * * @license Use of this software requires acceptance of the Evaluation License Agreement. See LICENSE file. - * @copyright Copyright © 2016-present Heidelberger Payment GmbH. All rights reserved. + * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. * * @author Simon Gabriel * diff --git a/composer.json b/composer.json index 0091e27c4cf..41351f65c71 100755 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "heidelpay/magento2", "description": "This extension for Magento 2 provides a direct integration of the Heidelpay payment methods to your Magento 2 shop.", "require": { - "php": "~5.6.0|~7.0.0|~7.1.0 |~7.2.0", + "php": "~7.0.0|~7.1.0 |~7.2.0|~7.3.0", "magento/module-config": "^100.0.0 | ^101.0.0 | ^102.0.0", "magento/module-store": "^100.0.0 | ^101.0.0 | ^102.0.0", "magento/module-checkout": "^100.0.0 | ^101.0.0 | ^102.0.0", @@ -16,15 +16,17 @@ "heidelpay/php-basket-api": "~1.0", "heidelpay/php-payment-api": "~1.7", "ext-json": "*", - "netresearch/module-compatibility-m2": "*" + "netresearch/module-compatibility-m2": "*", + "ext-bcmath": "*" }, "require-dev": { "magento/marketplace-eqp": "~1.0.5", "heidelpay/phpdocumentor": "2.9.1", - "friendsofphp/php-cs-fixer": "2.1.0" + "friendsofphp/php-cs-fixer": "2.1.0", + "allure-framework/allure-phpunit": "~1.2.0" }, "suggest": { - "magento/module-checkout-agreements": "^100.0.0 | ^101.0.0" + "magento/module-checkout-agreements": "^100.0.0 | ^101.0.0 | ^102.0.0" }, "repositories": [ { diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml index 44c1ce4988c..f7af3bfc7fb 100644 --- a/etc/adminhtml/di.xml +++ b/etc/adminhtml/di.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index 7994ef456b5..e4a77c143ee 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -157,4 +157,18 @@ + + + + Heidelpay\Gateway\Model\ResourceModel\Order\Grid\Collection + + + + + + sales_order_grid + Magento\Sales\Model\ResourceModel\Order + + + \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml index 44560b6ef0b..eed23472e8b 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,5 +1,5 @@ - + diff --git a/view/adminhtml/ui_component/sales_order_grid.xml b/view/adminhtml/ui_component/sales_order_grid.xml new file mode 100644 index 00000000000..81e4447f01d --- /dev/null +++ b/view/adminhtml/ui_component/sales_order_grid.xml @@ -0,0 +1,13 @@ + ++ + + + + true + heidelpay TxnId + + + + + \ No newline at end of file diff --git a/view/frontend/web/js/view/payment/method-renderer/hgw-abstract.js b/view/frontend/web/js/view/payment/method-renderer/hgw-abstract.js index 6fa269b01f1..e806e6d83d6 100644 --- a/view/frontend/web/js/view/payment/method-renderer/hgw-abstract.js +++ b/view/frontend/web/js/view/payment/method-renderer/hgw-abstract.js @@ -1,191 +1,191 @@ -define( - [ - 'jquery', - 'Magento_Checkout/js/view/payment/default', - 'Heidelpay_Gateway/js/action/place-order', - 'Magento_Checkout/js/model/payment/additional-validators', - 'Magento_Checkout/js/action/select-payment-method', - 'Magento_Checkout/js/checkout-data', - 'Magento_Checkout/js/model/quote', - 'Magento_Checkout/js/action/select-billing-address', - 'moment' - ], - function ($, Component, placeOrderAction, additionalValidators, selectPaymentMethodAction, checkoutData, quote, selectBillingAddress, moment) { - 'use strict'; - - // add IBAN validator - $.validator.addMethod( - 'validate-iban', function (value) { - var pattern = /^[A-Z]{2}[0-9]{13,29}$/i; - return (pattern.test(value)); - }, $.mage.__('The given IBAN is invalid.') - ); - - $.validator.addMethod( - 'valid-date', function (date){ - return (date); - }, $.mage.__('Invalid date.') - ); - $.validator.addMethod( - 'is-customer-18', function (date){ - var inputDate = new Date(date); - var currentDate = new Date(); - var is18 = new Date(currentDate-inputDate).getFullYear() - new Date(0).getFullYear() >= 18; - - return is18; - }, $.mage.__('You have to be at least 18.') - ); - - $.validator.setDefaults({ - ignore: '' - }); - - return Component.extend({ - - /** - * Property that indicates, if the payment method is storing - * additional data. - */ - savesAdditionalData: false, - - defaults: { - template: 'Heidelpay_Gateway/payment/heidelpay-form', - useShippingAddressAsBillingAddress: false, - hgwDobYear: '', - hgwDobMonth: '', - hgwDobDay: '', - hgwSalutation: '' - }, - - /** - * Indicates if the payment method is storing additional - * information for the payment. - * - * @returns {boolean} - */ - isSavingAdditionalData: function() { - return this.savesAdditionalData; - }, - - /** - * Function to load additional payment data if the payment method requires/offers it. - * - * This method needs to be overloaded by the payment renderer components, if - * additional information is needed. - */ - getAdditionalPaymentInformation: function() {}, - - /** - * Function to receive the customer's birthdate. - * - * This method needs to be overloaded by the payment renderer component, if needed. - */ - getBirthdate: function() { - var day = this.hgwDobDay(); - var date = new Date(this.hgwDobYear(), this.hgwDobMonth(), day); - - // checks whether created date is same as input and return null if not. - if(!(Boolean(+date) && date.getDate() == day)) {return null;} - return moment(date).format('YYYY-MM-DD'); - }, - - /** - * Function to receive the customer's full name. - */ - getFullName: function() { - var billingAddress = quote.billingAddress(); - var name = this.getNameFromAddress(billingAddress); - - // fallback, if name isn't set yet. - if (name === '') { - var tmpName = window.customerData; - - if (tmpName !== null) { - if (typeof tmpName.firstname !== 'undefined' && tmpName.firstname !== null) { - name += tmpName.firstname; - } - - if (typeof tmpName.middlename !== 'undefined' && tmpName.middlename !== null) { - name += ' ' + tmpName.middlename; - } - - if (typeof tmpName.lastname !== 'undefined' && tmpName.lastname !== null) { - name += ' ' + tmpName.lastname; - } - } - } - - return name; - }, - - getNameFromAddress: function(address) { - var name = ''; - - if (address !== null) { - if (typeof address.firstname !== 'undefined' && address.firstname !== null) { - name += address.firstname; - } - - if (typeof address.middlename !== 'undefined' && address.middlename !== null) { - name += ' ' + address.middlename; - } - - if (typeof address.lastname !== 'undefined' && address.lastname !== null) { - name += ' ' + address.lastname; - } - } - return name; - }, - - /** - * Redirect to hgw controller - * Override magento placepayment function - */ - placeOrder: function (data, event) { - var self = this, - placeOrder; - - if (event) { - event.preventDefault(); - } - - if (this.validate() && additionalValidators.validate()) { - this.isPlaceOrderActionAllowed(false); - placeOrder = placeOrderAction( - this.getData(), - this.redirectAfterPlaceOrder, - this.messageContainer, - this.isSavingAdditionalData() - ); - - $.when(placeOrder).fail(function () { - self.isPlaceOrderActionAllowed(true); - }).done(this.afterPlaceOrder.bind(this)); - return true; - } - return false; - }, - - /** - * Extends the parent selectPaymentMethod function. - * - * @return {Boolean} - */ - selectPaymentMethod: function () { - // call to the function which pulls additional information for a payment method, if needed. - this.getAdditionalPaymentInformation(); - - // from here, the body matches the default selectPaymentMethod function. - - selectPaymentMethodAction(this.getData()); - checkoutData.setSelectedPaymentMethod(this.item.method); - - if(this.useShippingAddressAsBillingAddress) { - selectBillingAddress(quote.shippingAddress()); - } - - return true; - } - }); - } -); +define( + [ + 'jquery', + 'Magento_Checkout/js/view/payment/default', + 'Heidelpay_Gateway/js/action/place-order', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Checkout/js/action/select-payment-method', + 'Magento_Checkout/js/checkout-data', + 'Magento_Checkout/js/model/quote', + 'Magento_Checkout/js/action/select-billing-address', + 'moment' + ], + function ($, Component, placeOrderAction, additionalValidators, selectPaymentMethodAction, checkoutData, quote, selectBillingAddress, moment) { + 'use strict'; + + // add IBAN validator + $.validator.addMethod( + 'validate-iban', function (value) { + var pattern = /^[A-Z]{2}[0-9]{13,29}$/i; + return (pattern.test(value)); + }, $.mage.__('The given IBAN is invalid.') + ); + // if selected date was invalid method will be called with date = null and validation will fail. + $.validator.addMethod( + 'valid-date', function (date){ + return (date); + }, $.mage.__('Invalid date.') + ); + $.validator.addMethod( + 'is-customer-18', function (date){ + var inputDate = new Date(date); + var currentDate = new Date(); + var is18 = new Date(currentDate-inputDate).getFullYear() - new Date(0).getFullYear() >= 18; + + return is18; + }, $.mage.__('You have to be at least 18.') + ); + + $.validator.setDefaults({ + ignore: '' + }); + + return Component.extend({ + + /** + * Property that indicates, if the payment method is storing + * additional data. + */ + savesAdditionalData: false, + + defaults: { + template: 'Heidelpay_Gateway/payment/heidelpay-form', + useShippingAddressAsBillingAddress: false, + hgwDobYear: '', + hgwDobMonth: '', + hgwDobDay: '', + hgwSalutation: '' + }, + + /** + * Indicates if the payment method is storing additional + * information for the payment. + * + * @returns {boolean} + */ + isSavingAdditionalData: function() { + return this.savesAdditionalData; + }, + + /** + * Function to load additional payment data if the payment method requires/offers it. + * + * This method needs to be overloaded by the payment renderer components, if + * additional information is needed. + */ + getAdditionalPaymentInformation: function() {}, + + /** + * Function to receive the customer's birthdate. + * + * This method needs to be overloaded by the payment renderer component, if needed. + */ + getBirthdate: function() { + var day = this.hgwDobDay(); + var date = new Date(this.hgwDobYear(), this.hgwDobMonth(), day); + + // checks whether created date is same as input and return null if not. + if(!(Boolean(+date) && date.getDate() == day)) {return null;} + return moment(date).format('YYYY-MM-DD'); + }, + + /** + * Function to receive the customer's full name. + */ + getFullName: function() { + var billingAddress = quote.billingAddress(); + var name = this.getNameFromAddress(billingAddress); + + // fallback, if name isn't set yet. + if (name === '') { + var tmpName = window.customerData; + + if (tmpName !== null) { + if (typeof tmpName.firstname !== 'undefined' && tmpName.firstname !== null) { + name += tmpName.firstname; + } + + if (typeof tmpName.middlename !== 'undefined' && tmpName.middlename !== null) { + name += ' ' + tmpName.middlename; + } + + if (typeof tmpName.lastname !== 'undefined' && tmpName.lastname !== null) { + name += ' ' + tmpName.lastname; + } + } + } + + return name; + }, + + getNameFromAddress: function(address) { + var name = ''; + + if (address !== null) { + if (typeof address.firstname !== 'undefined' && address.firstname !== null) { + name += address.firstname; + } + + if (typeof address.middlename !== 'undefined' && address.middlename !== null) { + name += ' ' + address.middlename; + } + + if (typeof address.lastname !== 'undefined' && address.lastname !== null) { + name += ' ' + address.lastname; + } + } + return name; + }, + + /** + * Redirect to hgw controller + * Override magento placepayment function + */ + placeOrder: function (data, event) { + var self = this, + placeOrder; + + if (event) { + event.preventDefault(); + } + + if (this.validate() && additionalValidators.validate()) { + this.isPlaceOrderActionAllowed(false); + placeOrder = placeOrderAction( + this.getData(), + this.redirectAfterPlaceOrder, + this.messageContainer, + this.isSavingAdditionalData() + ); + + $.when(placeOrder).fail(function () { + self.isPlaceOrderActionAllowed(true); + }).done(this.afterPlaceOrder.bind(this)); + return true; + } + return false; + }, + + /** + * Extends the parent selectPaymentMethod function. + * + * @return {Boolean} + */ + selectPaymentMethod: function () { + // call to the function which pulls additional information for a payment method, if needed. + this.getAdditionalPaymentInformation(); + + // from here, the body matches the default selectPaymentMethod function. + + selectPaymentMethodAction(this.getData()); + checkoutData.setSelectedPaymentMethod(this.item.method); + + if(this.useShippingAddressAsBillingAddress) { + selectBillingAddress(quote.shippingAddress()); + } + + return true; + } + }); + } +);