From f0b2356629ce1c6cc0d49f8ce41a33c9704dae4f Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Mon, 17 Jun 2019 15:48:33 +0200 Subject: [PATCH 01/44] (MAGE2-108) change: Create order from push, if it doesn't exists already --- Controller/Index/Push.php | 188 +++++++++++++++++++++------------- Controller/Index/Response.php | 8 +- Helper/Order.php | 140 +++++++++++++++++++++++++ Helper/Payment.php | 57 +++++++++-- 4 files changed, 307 insertions(+), 86 deletions(-) create mode 100644 Helper/Order.php diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 3869c30f014..197586039da 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -2,16 +2,18 @@ namespace Heidelpay\Gateway\Controller\Index; +use Heidelpay\Gateway\Helper\Payment as PaymentHelper; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; use Magento\Framework\Api\SearchCriteriaBuilder; +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\OrderRepository; -use Magento\Sales\Model\Order; use Magento\Sales\Model\ResourceModel\Order\Collection; -use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; /** * heidelpay Push Controller @@ -36,6 +38,18 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var SearchCriteriaBuilder */ private $searchCriteriaBuilder; + /** + * @var PaymentHelper + */ + private $paymentHelper; + /** + * @var QuoteRepository + */ + private $quoteRepository; + /** + * @var \Heidelpay\Gateway\Helper\Order + */ + private $orderHelper; /** * @param \Magento\Framework\App\Action\Context $context @@ -47,7 +61,7 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract * @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 PaymentHelper $paymentHelper * @param OrderSender $orderSender * @param InvoiceSender $invoiceSender * @param OrderCommentSender $orderCommentSender @@ -56,6 +70,8 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract * @param OrderRepository $orderRepository * @param \Heidelpay\PhpPaymentApi\Push $heidelpayPush * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param QuoteRepository $quoteRepository + * @param \Heidelpay\Gateway\Helper\Order $orderHelper */ public function __construct( \Magento\Framework\App\Action\Context $context, @@ -67,7 +83,7 @@ public function __construct( \Magento\Quote\Api\CartManagementInterface $cartManagement, \Magento\Quote\Api\CartRepositoryInterface $quoteObject, \Magento\Framework\View\Result\PageFactory $resultPageFactory, - \Heidelpay\Gateway\Helper\Payment $paymentHelper, + PaymentHelper $paymentHelper, OrderSender $orderSender, InvoiceSender $invoiceSender, OrderCommentSender $orderCommentSender, @@ -75,7 +91,9 @@ public function __construct( \Magento\Customer\Model\Url $customerUrl, OrderRepository $orderRepository, \Heidelpay\PhpPaymentApi\Push $heidelpayPush, - SearchCriteriaBuilder $searchCriteriaBuilder + SearchCriteriaBuilder $searchCriteriaBuilder, + QuoteRepository $quoteRepository, + \Heidelpay\Gateway\Helper\Order $orderHelper ) { parent::__construct( $context, @@ -98,6 +116,9 @@ public function __construct( $this->orderRepository = $orderRepository; $this->heidelpayPush = $heidelpayPush; $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->paymentHelper = $paymentHelper; + $this->quoteRepository = $quoteRepository; + $this->orderHelper = $orderHelper; } /** @@ -114,7 +135,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"'); } @@ -134,86 +155,109 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); + $data = $this->paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( $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; - } + // in case of receipts, we process the push message for receipts. + if ($pushResponse->isSuccess() && $this->paymentHelper->isNewOrderType($paymentType)) { + + $transactionId = $pushResponse->getIdentification()->getTransactionId(); + $order = $this->orderHelper->fetchOrder($transactionId); - $paidAmount = (float)$pushResponse->getPresentation()->getAmount(); - $dueLeft = $order->getTotalDue() - $paidAmount; + // create order if it doesn't exists already. + if ($order === null || $order->isEmpty()) { + $this->_paymentHelper->saveHeidelpayTransaction($pushResponse, $data, 'PUSH'); + $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' + . $transactionId); - $state = Order::STATE_PROCESSING; - $comment = 'heidelpay - Purchase Complete'; + $quote = $this->quoteRepository->get($transactionId); + 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($data, $order); + $this->_logger->debug('order status: ' . $order->getStatus()); + $this->orderHelper->handleOrderMail($order); + $this->orderHelper->handleInvoiceMails($order); + $this->orderRepository->save($order); + //TODO: Handle additional payment info from response } - // 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(); + 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(); + + /** @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; + + $state = Order::STATE_PROCESSING; + $comment = 'heidelpay - Purchase Complete'; - // create a child transaction. - $payment->setTransactionId($transactionID) - ->setParentTransactionId($pushResponse->getIdentification()->getReferenceId()) - ->setIsTransactionClosed(true) - ->addTransaction(Transaction::TYPE_CAPTURE, null, true); + // 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 \Magento\Sales\Model\Order\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); - $this->orderRepository->save($order); + // 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 ac1cd0656b9..5a409db1284 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -46,9 +46,6 @@ class Response extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var HeidelpayResponse The heidelpay response object */ private $heidelpayResponse; - /** @var TransactionFactory */ - private $transactionFactory; - /** @var CollectionFactory */ private $paymentInformationCollectionFactory; /** @@ -129,7 +126,6 @@ public function __construct( $this->resultFactory = $rawResultFactory; $this->quoteRepository = $quoteRepository; $this->paymentInformationCollectionFactory = $paymentInformationCollectionFactory; - $this->transactionFactory = $transactionFactory; $this->salesHelper = $salesHelper; $this->orderRepository = $orderRepository; } @@ -227,7 +223,6 @@ public function execute() $order = $this->_paymentHelper->createOrderFromQuote($quote); } catch (\Exception $e) { $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); - return $result; } @@ -249,12 +244,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/Helper/Order.php b/Helper/Order.php new file mode 100644 index 00000000000..a46ac06869c --- /dev/null +++ b/Helper/Order.php @@ -0,0 +1,140 @@ +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('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 4db074f33ed..0aab3c5477c 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -2,6 +2,7 @@ namespace Heidelpay\Gateway\Helper; use Heidelpay\MessageCodeMapper\MessageCodeMapper; +use Heidelpay\PhpPaymentApi\Constants\TransactionType; use Heidelpay\PhpPaymentApi\Response; use Magento\Framework\App\Helper\AbstractHelper; use Magento\Framework\App\Helper\Context; @@ -11,6 +12,7 @@ use Magento\Sales\Model\Order; use Magento\Sales\Model\Order\Invoice; use Heidelpay\Gateway\Model\TransactionFactory; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; /** * Heidelpay payment helper @@ -49,6 +51,12 @@ class Payment extends AbstractHelper */ private $heidelpayTransactionFactory; + const NEW_ORDER_TRANSACTION_TYPE_ARRAY = [ + TransactionType::RECEIPT, + TransactionType::DEBIT, + TransactionType::RESERVATION + ]; + /** * @param Context $context * @param \Magento\Framework\HTTP\ZendClientFactory $httpClientFactory @@ -103,12 +111,14 @@ public function mapStatus($data, $order, $message = false) return; } + /** @var HeidelpayAbstractPaymentMethod $paymentMethod */ + $paymentMethod = $order->getPayment()->getMethodInstance(); if ($data['PROCESSING_RESULT'] == 'NOK') { - $order->getPayment()->getMethodInstance()->cancelledTransactionProcessing($order, $message); + $paymentMethod->cancelledTransactionProcessing($order, $message); } elseif ($this->isProcessing($paymentCode[1], $data)) { - $order->getPayment()->getMethodInstance()->processingTransactionProcessing($data, $order); + $paymentMethod->processingTransactionProcessing($data, $order); } else { - $order->getPayment()->getMethodInstance()->pendingTransactionProcessing($data, $order, $message); + $paymentMethod->pendingTransactionProcessing($data, $order, $message); } } @@ -124,6 +134,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 * @@ -138,6 +159,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. * @@ -204,11 +239,7 @@ public function isPreAuthorization(array $data) $paymentCode = $this->splitPaymentCode($data['PAYMENT_CODE']); - if ($paymentCode[1] == 'PA') { - return true; - } - - return false; + return $paymentCode[1] === 'PA'; } /** @@ -328,4 +359,14 @@ public function createOrderFromQuote($quote) return $this->_cartManagement->submit($quote); } + + /** + * 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); + } } From 92179f429eb6117ce903b94e49f9bb136580a5d5 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 2 Jul 2019 17:51:25 +0200 Subject: [PATCH 02/44] (MAGE2-108) change: Create basic integration test for push notification handling - Order creation from push. --- .../Index/PushHandlingTestTestAbstract.php | 237 ++++++++++++++++ Test/Integration/IntegrationTestAbstract.php | 260 ++++++++++++++++++ Test/Integration/_files/categories.php | 15 + Test/Integration/_files/customer.php | 46 ++++ Test/Integration/_files/products.php | 47 ++++ .../data/provider/PushResponse.php | 95 +++++++ .../fixtures/Response/Push/push.xml | 79 ++++++ 7 files changed, 779 insertions(+) create mode 100644 Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php create mode 100644 Test/Integration/IntegrationTestAbstract.php create mode 100644 Test/Integration/_files/categories.php create mode 100644 Test/Integration/_files/customer.php create mode 100644 Test/Integration/_files/products.php create mode 100644 Test/Integration/data/provider/PushResponse.php create mode 100644 Test/Integration/fixtures/Response/Push/push.xml diff --git a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php b/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php new file mode 100644 index 00000000000..1cc77bee5fd --- /dev/null +++ b/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php @@ -0,0 +1,237 @@ +getRequest(); + + /** Set Request type */ + $request->setMethod($request::METHOD_POST); + $request->setHeaders(Headers::fromString('content-type: application/xml')); + + /*$this->loggerMock = $this->createMock(Logger::class); //createMOck can use + + $this->getObjectManager()->addSharedInstance($this->loggerMock,get_class($this->loggerMock)); + + $this->getObjectManager()->configure([ + 'preferences' => [ + LoggerInterface::class => get_class($this->loggerMock) + ] + ]);*/ + } + + public static function loadFixture() + { + include __DIR__ . '/../../_files/products.php'; + include __DIR__ . '/../../_files/categories.php'; + include __DIR__ . '/../../_files/coupons.php'; + include __DIR__ . '/../../_files/customer.php'; + } + + public function testTrue() + { + $this->assertTrue(true); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testEmptyRequest() + { + $request = $this->getRequest(); + $request->setMethod($request::METHOD_GET); + + $this->dispatch(self::CONTROLLER_PATH); + $this->getResponse(); + $response = $this->getResponse()->getBody(); + $this->assertEmpty($response, $response); + } + + /** + * @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 + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testPushCreatesNewTransaction($pushSpecification = null) + { + $pushSpecification = []; + /** Step 0 - Create fictures (products, customer etc.)and save them to database */ + //$this->generateCustomerFixture(); + list($customer, $quote) = $this->generateQuote(); + + $this->assertNotNull($quote); + + /** Step 2 - Load push */ + /** @var PushResponse $pushProvider */ + $pushProvider = $this->createObject(PushResponse::class); + + $pushSpecification['TransactionID'] = isset($pushSpecification['TransactionID'])?:$quote->getId(); + $pushSpecification['Amount'] = number_format($quote->getGrandTotal(), 2, '.', ''); + $pushSpecification['ShopperID'] = $customer->getId($customer->getId()); + + /** @var SimpleXMLElement $xml */ + $xml = new SimpleXMLElement($pushProvider->providePushXml($pushSpecification)); + + /** Step 3 - Modify push to match cart id And so on [Pushprovider] */ + + /** Step 4 - Set request content (xml) */ + $this->getRequest()->setContent($xml->saveXML()); + + /** Assertions vor dem push */ + /** @var Order $order */ + $order = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($order->isEmpty()); + + /** Step 5 - perform the actual test request on controller */ + $this->dispatch(self::CONTROLLER_PATH); + + echo 'Response-Content: ' . $this->getResponse()->getContent(); + /** Step 6 - Evaluate expected results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); + $this->assertNotNull($fetchedQuote); + + /** @var Order $order */ + $order = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertFalse($order->isEmpty(), 'Order creation failed: Order is empty'); + $collection = $this->transactionFactory->create(); + + /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); + $this->assertNotNull($heidelpayTransaction); + $this->assertFalse($heidelpayTransaction->isEmpty()); + echo 'transaction: ' . $heidelpayTransaction->getUniqueId(); + + $histories = $order->getAllStatusHistory(); + + $historyComments = []; + + foreach ($histories as $entry) { + $historyComments[] = $entry->getComment(); + } + + $debug = [ + 'order' => [ + 'state' => $order->getStatus(), + 'total' => $order->getGrandTotal(), + 'paid' => $order->getTotalPaid(), + 'history' => $historyComments + ], + '$quote' => [ + 'state' => $quote->getStatus(), + 'total' => 30.0,//number_format($quote->getGrandTotal(), 2, '.', ''), + 'paid' => $quote->getTotalPaid(), + ], + 'dataArray' => $this->getResponse()->getBody() + ]; + + echo "\n" . 'debug:' . "\n" . print_r($debug, 1); + + $this->assertEquals( + (float)$xml->Transaction->Payment->Clearing->Amount, + (float)$order->getGrandTotal(), + 'grand total amount doesn\'t match'); + + $this->assertEquals( + (float)$xml->Transaction->Payment->Clearing->Amount, + (float)$order->getTotalPaid(), + 'Order state: ' .$order->getStatus() .'. total paid amount doesn\'t match'); + } + + public function dataProviderPushCreatesNewTransactionDP() + { + + return [ + 'default Push-XML' => [null], + 'Create from IV.PA' => [ + + ], + ]; + } + + /** + * @return array + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + protected function generateQuote() + { + $quoteId = $this->cartManagement->createEmptyCart(); + /** @var CustomerManagementInterface $customerRepository */ + $customerRepository = $this->createObject(\Magento\Customer\Api\CustomerRepositoryInterface::class); + + /** @var Customer $customer */ + $customer = $customerRepository->get('l.h@mail.com'); + + /** Step 1 - 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('hgwsue'); + //$quote->getBillingAddress()->addData($addressData); + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setCustomerId($customer->getId()) + ->collectShippingRates() + ->setFreeShipping(true) + ->setShippingMethod('flatrate_flatrate') + ->setPaymentMethod('hgwcc'); + + $quote->collectTotals(); + $quote->save(); + return array($customer, $quote); + } + +} \ No newline at end of file diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php new file mode 100644 index 00000000000..afb651207e9 --- /dev/null +++ b/Test/Integration/IntegrationTestAbstract.php @@ -0,0 +1,260 @@ +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; + } + } + +} \ 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..8ac86f2b557 --- /dev/null +++ b/Test/Integration/_files/categories.php @@ -0,0 +1,15 @@ +create('Magento\Catalog\Model\Category'); +$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..784995355f6 --- /dev/null +++ b/Test/Integration/_files/customer.php @@ -0,0 +1,46 @@ +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'); + +/** @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..56c58ef621a --- /dev/null +++ b/Test/Integration/_files/products.php @@ -0,0 +1,47 @@ +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..864abc24b2c --- /dev/null +++ b/Test/Integration/data/provider/PushResponse.php @@ -0,0 +1,95 @@ + + + + + 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 + + + + + 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 + + + Magento 2.2.8-Community + Heidelpay\PhpPaymentApi + d83f0dae2fca921d00cb70559762a365e55870e0cad5384177a931379e04d0204fb8d01ee16ef109f27ec67fb181e748d688119cf82966f59ab1db476d460a5e + v1.8.0 + SofortPaymentMethod + Heidelpay Gateway 19.5.08 + false + + 2019-06-12 15:53:04 +
+
+XML; + + 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 From 00ca1784c46bfcedbcaf94d15a84745448757bdf Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Wed, 3 Jul 2019 18:49:51 +0200 Subject: [PATCH 03/44] (MAGE2-108) change: add test cases for different transaction types. Also added a negative test to prevent unintentional order creation. --- ...tTestAbstract.php => PushHandlingTest.php} | 212 +++++++++++------- Test/Integration/IntegrationTestAbstract.php | 20 ++ .../data/provider/PushResponse.php | 24 +- 3 files changed, 170 insertions(+), 86 deletions(-) rename Test/Integration/Controller/Index/{PushHandlingTestTestAbstract.php => PushHandlingTest.php} (50%) diff --git a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php b/Test/Integration/Controller/Index/PushHandlingTest.php similarity index 50% rename from Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php rename to Test/Integration/Controller/Index/PushHandlingTest.php index 1cc77bee5fd..26715d62683 100644 --- a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -44,16 +44,6 @@ public function setUp() /** Set Request type */ $request->setMethod($request::METHOD_POST); $request->setHeaders(Headers::fromString('content-type: application/xml')); - - /*$this->loggerMock = $this->createMock(Logger::class); //createMOck can use - - $this->getObjectManager()->addSharedInstance($this->loggerMock,get_class($this->loggerMock)); - - $this->getObjectManager()->configure([ - 'preferences' => [ - LoggerInterface::class => get_class($this->loggerMock) - ] - ]);*/ } public static function loadFixture() @@ -85,6 +75,8 @@ public function testEmptyRequest() } /** + * Test creation of new order via push if no order exists already. + * * @dataProvider dataProviderPushCreatesNewTransactionDP * @magentoDbIsolation enabled * @@ -92,106 +84,116 @@ public function testEmptyRequest() * @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 \Magento\Framework\Exception\CouldNotSaveException * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function testPushCreatesNewTransaction($pushSpecification = null) + public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMethod) { - $pushSpecification = []; - /** Step 0 - Create fictures (products, customer etc.)and save them to database */ - //$this->generateCustomerFixture(); - list($customer, $quote) = $this->generateQuote(); - - $this->assertNotNull($quote); - - /** Step 2 - Load push */ - /** @var PushResponse $pushProvider */ - $pushProvider = $this->createObject(PushResponse::class); - - $pushSpecification['TransactionID'] = isset($pushSpecification['TransactionID'])?:$quote->getId(); - $pushSpecification['Amount'] = number_format($quote->getGrandTotal(), 2, '.', ''); - $pushSpecification['ShopperID'] = $customer->getId($customer->getId()); - - /** @var SimpleXMLElement $xml */ - $xml = new SimpleXMLElement($pushProvider->providePushXml($pushSpecification)); - - /** Step 3 - Modify push to match cart id And so on [Pushprovider] */ + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->dispatch(self::CONTROLLER_PATH); - /** Step 4 - Set request content (xml) */ - $this->getRequest()->setContent($xml->saveXML()); + /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); - /** Assertions vor dem push */ /** @var Order $order */ - $order = $this->orderHelper->fetchOrder($quote->getId()); - $this->assertTrue($order->isEmpty()); + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); - /** Step 5 - perform the actual test request on controller */ - $this->dispatch(self::CONTROLLER_PATH); - - echo 'Response-Content: ' . $this->getResponse()->getContent(); - /** Step 6 - Evaluate expected results (heidelpay)Transaction, Quotes, Orders */ - $fetchedQuote = $this->quoteRepository->get($quote->getId()); $this->assertNotNull($fetchedQuote); + $this->assertEquals('0', $fetchedQuote->getIsActive()); - /** @var Order $order */ - $order = $this->orderHelper->fetchOrder($quote->getId()); - $this->assertFalse($order->isEmpty(), 'Order creation failed: Order is empty'); + $this->assertFalse($fetchedOrder->isEmpty(), 'Order creation failed: Order is empty'); + + // Check Transaction $collection = $this->transactionFactory->create(); + // Check Transaction /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); $this->assertNotNull($heidelpayTransaction); $this->assertFalse($heidelpayTransaction->isEmpty()); - echo 'transaction: ' . $heidelpayTransaction->getUniqueId(); - - $histories = $order->getAllStatusHistory(); - - $historyComments = []; - - foreach ($histories as $entry) { - $historyComments[] = $entry->getComment(); - } - - $debug = [ - 'order' => [ - 'state' => $order->getStatus(), - 'total' => $order->getGrandTotal(), - 'paid' => $order->getTotalPaid(), - 'history' => $historyComments - ], - '$quote' => [ - 'state' => $quote->getStatus(), - 'total' => 30.0,//number_format($quote->getGrandTotal(), 2, '.', ''), - 'paid' => $quote->getTotalPaid(), - ], - 'dataArray' => $this->getResponse()->getBody() - ]; - - echo "\n" . 'debug:' . "\n" . print_r($debug, 1); + // Check Amounts $this->assertEquals( - (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$order->getGrandTotal(), + $fetchedOrder->getGrandTotal(), + $xml->Transaction->Payment->Clearing->Amount, 'grand total amount doesn\'t match'); $this->assertEquals( (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$order->getTotalPaid(), - 'Order state: ' .$order->getStatus() .'. total paid amount doesn\'t match'); + (float)$fetchedOrder->getTotalPaid(), + 'Order state: ' .$fetchedOrder->getStatus() .'. total paid amount doesn\'t match'); } public function dataProviderPushCreatesNewTransactionDP() { - return [ - 'default Push-XML' => [null], - 'Create from IV.PA' => [ + 'Create from IV.RC' => ['IV.RC', 'hgwivs'], + 'Create from CC.DB' => ['CC.DB', 'hgwcc'], + 'Create from DD.DB' => ['DD.DB', 'hgwdd'], + 'Create from OT.RC' => ['OT.RC', 'hgwsue'], + 'Create from PP.RC' => ['PP.RC', 'hgwpp'], + ]; + } - ], + public function CreateNoOrderFromInvalidTransactionTypesDP() + { + return [ + 'create no order from IV.RV' => ['IV.RV', 'hgwivs'], + 'create no order from CC.RF' => ['CC.RF', 'hgwcc'], + 'create no order from IV.IN' => ['IV.IN', 'hgwivs'], + 'create no order from IV.FI' => ['IV.FI', 'hgwivs'], ]; } + /** + * No order should be created for transaction types other then defined. + * + * @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 \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) + { + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->dispatch(self::CONTROLLER_PATH); + + /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); + + /** @var Order $order */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + + $this->assertNotNull($fetchedQuote); + $this->assertEquals('1', $fetchedQuote->getIsActive()); + + $this->assertTrue($fetchedOrder->isEmpty(), 'no Order should be created here'); + + // Check Transaction + $collection = $this->transactionFactory->create(); + + // Check Transaction + /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); + $this->assertNotNull($heidelpayTransaction); + $this->assertTrue($heidelpayTransaction->isEmpty()); + + // Check amount of history entries. + $histories = $fetchedOrder->getAllStatusHistory(); + $this->assertCount(0, $histories); + } + /** * @return array * @throws \Magento\Framework\Exception\CouldNotSaveException @@ -199,7 +201,7 @@ public function dataProviderPushCreatesNewTransactionDP() * @throws \Magento\Framework\Exception\NoSuchEntityException * @throws \Magento\Framework\Exception\CouldNotSaveException */ - protected function generateQuote() + protected function generateQuote($paymentMethod) { $quoteId = $this->cartManagement->createEmptyCart(); /** @var CustomerManagementInterface $customerRepository */ @@ -220,7 +222,7 @@ protected function generateQuote() $quote->addProduct($product); /** @var Payment $payment */ - $quote->getPayment()->setMethod('hgwsue'); + $quote->getPayment()->setMethod($paymentMethod); //$quote->getBillingAddress()->addData($addressData); $shippingAddress = $quote->getShippingAddress(); $shippingAddress->setCustomerId($customer->getId()) @@ -234,4 +236,54 @@ protected function generateQuote() return array($customer, $quote); } + /** + * @param array $pushSpecification + * @param $paymentCode + * @param $quote + * @param $customer + * @return SimpleXMLElement + */ + protected function preparePushNotification($paymentCode, $quote, $customer) + { + $pushProvider = $this->createObject(PushResponse::class); + + $pushSpecification = [ + 'TransactionID' => $quote->getId(), + 'Amount' => $quote->getGrandTotal(), + 'ShopperID' => $customer->getId($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 \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + protected function prepareRequest($paymentCode, $paymentMethod) + { + /** Step 1 - Prepare data. Quote, Customer, XML */ + list($customer, $quote) = $this->generateQuote($paymentMethod); + + /** @var PushResponse $pushProvider */ + $xml = $this->preparePushNotification($paymentCode, $quote, $customer); + + /** Step 2 Assertions before push controller is called */ + /** @var Order $fetchedOrder */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($fetchedOrder->isEmpty()); + $this->assertNotNull($quote); + + /** Step 3 - Perform the actual test request on controller */ + $this->getRequest()->setContent($xml->saveXML()); + return array($quote, $xml); + } + } \ No newline at end of file diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php index afb651207e9..0447bea66fe 100644 --- a/Test/Integration/IntegrationTestAbstract.php +++ b/Test/Integration/IntegrationTestAbstract.php @@ -257,4 +257,24 @@ protected function generateProductFixtures($number) } } + /** + * @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/data/provider/PushResponse.php b/Test/Integration/data/provider/PushResponse.php index 864abc24b2c..09a26303eca 100644 --- a/Test/Integration/data/provider/PushResponse.php +++ b/Test/Integration/data/provider/PushResponse.php @@ -32,7 +32,7 @@ class PushResponse SUCCESSFULL Request successfully processed in 'Merchant in Connector Test Mode' - + 53.55 EUR @@ -44,6 +44,17 @@ class PushResponse 4242.8116.1848 Heidelpay QA + + + DE + HEIDELPAYXY + 10000000 + 1234567890 + Heidelpay QA + DE01000000001234567890 + 4260.7131.1424 + + SOFORT @@ -68,12 +79,7 @@ class PushResponse https://test-heidelpay.hpcgw.net/ngw/responsePa?state=9158be8fffffffff17fcff09 - Magento 2.2.8-Community - Heidelpay\PhpPaymentApi d83f0dae2fca921d00cb70559762a365e55870e0cad5384177a931379e04d0204fb8d01ee16ef109f27ec67fb181e748d688119cf82966f59ab1db476d460a5e - v1.8.0 - SofortPaymentMethod - Heidelpay Gateway 19.5.08 false 2019-06-12 15:53:04 @@ -81,6 +87,12 @@ class PushResponse 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; From b1087a7ed4d3d944b5f0163e98357d9d5c7e4085 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 4 Jul 2019 13:58:44 +0200 Subject: [PATCH 04/44] (MAGE2-108) change: also handle additional payment info in push. --- Controller/Index/Push.php | 30 +++++----------- Controller/Index/Response.php | 28 +-------------- Helper/Payment.php | 35 ++++++++++++++++++- .../Controller/Index/PushHandlingTest.php | 28 +++++++++------ 4 files changed, 62 insertions(+), 59 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 197586039da..a35b25b026b 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -36,19 +36,9 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var \Heidelpay\PhpPaymentApi\Push */ private $heidelpayPush; - /** @var SearchCriteriaBuilder */ - private $searchCriteriaBuilder; - /** - * @var PaymentHelper - */ - private $paymentHelper; - /** - * @var QuoteRepository - */ + /** @var QuoteRepository */ private $quoteRepository; - /** - * @var \Heidelpay\Gateway\Helper\Order - */ + /** @var \Heidelpay\Gateway\Helper\Order */ private $orderHelper; /** @@ -91,7 +81,6 @@ public function __construct( \Magento\Customer\Model\Url $customerUrl, OrderRepository $orderRepository, \Heidelpay\PhpPaymentApi\Push $heidelpayPush, - SearchCriteriaBuilder $searchCriteriaBuilder, QuoteRepository $quoteRepository, \Heidelpay\Gateway\Helper\Order $orderHelper ) { @@ -115,8 +104,6 @@ public function __construct( $this->orderRepository = $orderRepository; $this->heidelpayPush = $heidelpayPush; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->paymentHelper = $paymentHelper; $this->quoteRepository = $quoteRepository; $this->orderHelper = $orderHelper; } @@ -155,7 +142,7 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); - $data = $this->paymentHelper->getDataFromResponse($pushResponse); + $data = $this->_paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( @@ -163,10 +150,11 @@ public function execute() ); // in case of receipts, we process the push message for receipts. - if ($pushResponse->isSuccess() && $this->paymentHelper->isNewOrderType($paymentType)) { + if ($pushResponse->isSuccess() && $this->_paymentHelper->isNewOrderType($paymentType)) { $transactionId = $pushResponse->getIdentification()->getTransactionId(); $order = $this->orderHelper->fetchOrder($transactionId); + $quote = $this->quoteRepository->get($transactionId); // create order if it doesn't exists already. if ($order === null || $order->isEmpty()) { @@ -174,9 +162,8 @@ public function execute() $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' . $transactionId); - $quote = $this->quoteRepository->get($transactionId); try { - $order = $this->paymentHelper->createOrderFromQuote($quote); + $order = $this->_paymentHelper->createOrderFromQuote($quote); if ($order === null || $order->isEmpty()) { $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); @@ -187,13 +174,14 @@ public function execute() return; } - $this->paymentHelper->mapStatus($data, $order); + $this->_paymentHelper->mapStatus($data, $order); $this->_logger->debug('order status: ' . $order->getStatus()); $this->orderHelper->handleOrderMail($order); $this->orderHelper->handleInvoiceMails($order); $this->orderRepository->save($order); - //TODO: Handle additional payment info from response } + $this->_paymentHelper->handleAdditionalPaymentInformation($quote); + if ($this->_paymentHelper->isReceiptAble($paymentMethod, $paymentType)) { // load the referenced order to receive the order information. diff --git a/Controller/Index/Response.php b/Controller/Index/Response.php index 5a409db1284..f7efec76fc7 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -235,7 +235,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. @@ -275,32 +275,6 @@ protected function handleInvoiceMails($order) } } - /** - * 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 - */ - protected 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(); - } - } - } - /** * Validate Hash to prevent manipulation * @param HeidelpayResponse $response diff --git a/Helper/Payment.php b/Helper/Payment.php index 0aab3c5477c..e87e58f84cc 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -13,6 +13,7 @@ use Magento\Sales\Model\Order\Invoice; use Heidelpay\Gateway\Model\TransactionFactory; use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; +use Heidelpay\Gateway\Model\ResourceModel\PaymentInformation\CollectionFactory as PaymentInformationCollectionFactory; /** * Heidelpay payment helper @@ -56,6 +57,10 @@ class Payment extends AbstractHelper TransactionType::DEBIT, TransactionType::RESERVATION ]; + /** + * @var PaymentInformationCollectionFactory + */ + private $paymentInformationCollectionFactory; /** * @param Context $context @@ -71,7 +76,8 @@ public function __construct( \Magento\Framework\DB\TransactionFactory $transactionFactory, \Magento\Framework\Locale\Resolver $localeResolver, QuoteManagement $cartManagement, - TransactionFactory $heidelpayTransactionFactory + TransactionFactory $heidelpayTransactionFactory, + PaymentInformationCollectionFactory $paymentInformationCollectionFactory ) { $this->httpClientFactory = $httpClientFactory; $this->transactionFactory = $transactionFactory; @@ -80,6 +86,7 @@ public function __construct( parent::__construct($context); $this->_cartManagement = $cartManagement; $this->heidelpayTransactionFactory = $heidelpayTransactionFactory; + $this->paymentInformationCollectionFactory = $paymentInformationCollectionFactory; } public function splitPaymentCode($PAYMENT_CODE) @@ -369,4 +376,30 @@ 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/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 26715d62683..3b1883921af 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -90,7 +90,7 @@ public function testEmptyRequest() * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMethod) + public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); $this->dispatch(self::CONTROLLER_PATH); @@ -115,16 +115,23 @@ public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMe $this->assertNotNull($heidelpayTransaction); $this->assertFalse($heidelpayTransaction->isEmpty()); + $isPreAuthorization = 'PA' ===$this->paymentHelper->splitPaymentCode($paymentCode)[1]; // Check Amounts - $this->assertEquals( - $fetchedOrder->getGrandTotal(), - $xml->Transaction->Payment->Clearing->Amount, - 'grand total amount doesn\'t match'); - - $this->assertEquals( - (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$fetchedOrder->getTotalPaid(), - 'Order state: ' .$fetchedOrder->getStatus() .'. total paid amount doesn\'t match'); + $this->assertEquals( + $fetchedOrder->getGrandTotal(), + $xml->Transaction->Payment->Clearing->Amount, + 'grand total amount doesn\'t match'); + + if (!$isPreAuthorization) + { + $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()); + } + } public function dataProviderPushCreatesNewTransactionDP() @@ -134,6 +141,7 @@ public function dataProviderPushCreatesNewTransactionDP() 'Create from CC.DB' => ['CC.DB', 'hgwcc'], 'Create from DD.DB' => ['DD.DB', 'hgwdd'], 'Create from OT.RC' => ['OT.RC', 'hgwsue'], + 'Create from OT.PA' => ['OT.PA', 'hgwsue'], 'Create from PP.RC' => ['PP.RC', 'hgwpp'], ]; } From b025189282be28081e1a653900c7aadbc19eb31e Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Mon, 17 Jun 2019 15:48:33 +0200 Subject: [PATCH 05/44] (MAGE2-108) change: Create order from push, if it doesn't exists already --- Controller/Index/Push.php | 188 +++++++++++++++++++++------------- Controller/Index/Response.php | 3 +- Helper/Order.php | 140 +++++++++++++++++++++++++ Helper/Payment.php | 55 +++++++++- 4 files changed, 308 insertions(+), 78 deletions(-) create mode 100644 Helper/Order.php diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 3869c30f014..197586039da 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -2,16 +2,18 @@ namespace Heidelpay\Gateway\Controller\Index; +use Heidelpay\Gateway\Helper\Payment as PaymentHelper; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; use Magento\Framework\Api\SearchCriteriaBuilder; +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\OrderRepository; -use Magento\Sales\Model\Order; use Magento\Sales\Model\ResourceModel\Order\Collection; -use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; /** * heidelpay Push Controller @@ -36,6 +38,18 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var SearchCriteriaBuilder */ private $searchCriteriaBuilder; + /** + * @var PaymentHelper + */ + private $paymentHelper; + /** + * @var QuoteRepository + */ + private $quoteRepository; + /** + * @var \Heidelpay\Gateway\Helper\Order + */ + private $orderHelper; /** * @param \Magento\Framework\App\Action\Context $context @@ -47,7 +61,7 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract * @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 PaymentHelper $paymentHelper * @param OrderSender $orderSender * @param InvoiceSender $invoiceSender * @param OrderCommentSender $orderCommentSender @@ -56,6 +70,8 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract * @param OrderRepository $orderRepository * @param \Heidelpay\PhpPaymentApi\Push $heidelpayPush * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param QuoteRepository $quoteRepository + * @param \Heidelpay\Gateway\Helper\Order $orderHelper */ public function __construct( \Magento\Framework\App\Action\Context $context, @@ -67,7 +83,7 @@ public function __construct( \Magento\Quote\Api\CartManagementInterface $cartManagement, \Magento\Quote\Api\CartRepositoryInterface $quoteObject, \Magento\Framework\View\Result\PageFactory $resultPageFactory, - \Heidelpay\Gateway\Helper\Payment $paymentHelper, + PaymentHelper $paymentHelper, OrderSender $orderSender, InvoiceSender $invoiceSender, OrderCommentSender $orderCommentSender, @@ -75,7 +91,9 @@ public function __construct( \Magento\Customer\Model\Url $customerUrl, OrderRepository $orderRepository, \Heidelpay\PhpPaymentApi\Push $heidelpayPush, - SearchCriteriaBuilder $searchCriteriaBuilder + SearchCriteriaBuilder $searchCriteriaBuilder, + QuoteRepository $quoteRepository, + \Heidelpay\Gateway\Helper\Order $orderHelper ) { parent::__construct( $context, @@ -98,6 +116,9 @@ public function __construct( $this->orderRepository = $orderRepository; $this->heidelpayPush = $heidelpayPush; $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->paymentHelper = $paymentHelper; + $this->quoteRepository = $quoteRepository; + $this->orderHelper = $orderHelper; } /** @@ -114,7 +135,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"'); } @@ -134,86 +155,109 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); + $data = $this->paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( $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; - } + // in case of receipts, we process the push message for receipts. + if ($pushResponse->isSuccess() && $this->paymentHelper->isNewOrderType($paymentType)) { + + $transactionId = $pushResponse->getIdentification()->getTransactionId(); + $order = $this->orderHelper->fetchOrder($transactionId); - $paidAmount = (float)$pushResponse->getPresentation()->getAmount(); - $dueLeft = $order->getTotalDue() - $paidAmount; + // create order if it doesn't exists already. + if ($order === null || $order->isEmpty()) { + $this->_paymentHelper->saveHeidelpayTransaction($pushResponse, $data, 'PUSH'); + $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' + . $transactionId); - $state = Order::STATE_PROCESSING; - $comment = 'heidelpay - Purchase Complete'; + $quote = $this->quoteRepository->get($transactionId); + 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($data, $order); + $this->_logger->debug('order status: ' . $order->getStatus()); + $this->orderHelper->handleOrderMail($order); + $this->orderHelper->handleInvoiceMails($order); + $this->orderRepository->save($order); + //TODO: Handle additional payment info from response } - // 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(); + 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(); + + /** @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; + + $state = Order::STATE_PROCESSING; + $comment = 'heidelpay - Purchase Complete'; - // create a child transaction. - $payment->setTransactionId($transactionID) - ->setParentTransactionId($pushResponse->getIdentification()->getReferenceId()) - ->setIsTransactionClosed(true) - ->addTransaction(Transaction::TYPE_CAPTURE, null, true); + // 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 \Magento\Sales\Model\Order\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); - $this->orderRepository->save($order); + // 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 568dddc49d8..55d033f7c69 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -273,12 +273,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/Helper/Order.php b/Helper/Order.php new file mode 100644 index 00000000000..a46ac06869c --- /dev/null +++ b/Helper/Order.php @@ -0,0 +1,140 @@ +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('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..d938d321d82 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -4,6 +4,7 @@ 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; @@ -24,6 +25,8 @@ use Magento\Sales\Model\Order\Invoice; use Heidelpay\Gateway\Model\Transaction; use Heidelpay\Gateway\Model\TransactionFactory as HgwTransactionFactory; +use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; + /** * Heidelpay payment helper @@ -61,6 +64,12 @@ class Payment extends AbstractHelper /** @var HgwTransactionFactory */ private $heidelpayTransactionFactory; + const NEW_ORDER_TRANSACTION_TYPE_ARRAY = [ + TransactionType::RECEIPT, + TransactionType::DEBIT, + TransactionType::RESERVATION + ]; + /** * @param Context $context * @param ZendClientFactory $httpClientFactory @@ -117,13 +126,14 @@ public function mapStatus($data, $order, $message = false) return; } - $payment = $order->getPayment(); - if ($data['PROCESSING_RESULT'] === ProcessingResult::NOK) { - $payment->getMethodInstance()->cancelledTransactionProcessing($order, $message); + /** @var HeidelpayAbstractPaymentMethod $paymentMethod */ + $paymentMethod = $order->getPayment()->getMethodInstance(); + if ($data['PROCESSING_RESULT'] == 'NOK') { + $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 +149,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 +174,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 +387,14 @@ 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); + } } From 0ff81e689004671ac1fc54803055e211d037828a Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 2 Jul 2019 17:51:25 +0200 Subject: [PATCH 06/44] (MAGE2-108) change: Create basic integration test for push notification handling - Order creation from push. --- .../Index/PushHandlingTestTestAbstract.php | 237 ++++++++++++++++ Test/Integration/IntegrationTestAbstract.php | 260 ++++++++++++++++++ Test/Integration/_files/categories.php | 15 + Test/Integration/_files/customer.php | 46 ++++ Test/Integration/_files/products.php | 47 ++++ .../data/provider/PushResponse.php | 95 +++++++ .../fixtures/Response/Push/push.xml | 79 ++++++ 7 files changed, 779 insertions(+) create mode 100644 Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php create mode 100644 Test/Integration/IntegrationTestAbstract.php create mode 100644 Test/Integration/_files/categories.php create mode 100644 Test/Integration/_files/customer.php create mode 100644 Test/Integration/_files/products.php create mode 100644 Test/Integration/data/provider/PushResponse.php create mode 100644 Test/Integration/fixtures/Response/Push/push.xml diff --git a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php b/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php new file mode 100644 index 00000000000..1cc77bee5fd --- /dev/null +++ b/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php @@ -0,0 +1,237 @@ +getRequest(); + + /** Set Request type */ + $request->setMethod($request::METHOD_POST); + $request->setHeaders(Headers::fromString('content-type: application/xml')); + + /*$this->loggerMock = $this->createMock(Logger::class); //createMOck can use + + $this->getObjectManager()->addSharedInstance($this->loggerMock,get_class($this->loggerMock)); + + $this->getObjectManager()->configure([ + 'preferences' => [ + LoggerInterface::class => get_class($this->loggerMock) + ] + ]);*/ + } + + public static function loadFixture() + { + include __DIR__ . '/../../_files/products.php'; + include __DIR__ . '/../../_files/categories.php'; + include __DIR__ . '/../../_files/coupons.php'; + include __DIR__ . '/../../_files/customer.php'; + } + + public function testTrue() + { + $this->assertTrue(true); + } + + /** + * @magentoDbIsolation enabled + * @magentoAppIsolation enabled + */ + public function testEmptyRequest() + { + $request = $this->getRequest(); + $request->setMethod($request::METHOD_GET); + + $this->dispatch(self::CONTROLLER_PATH); + $this->getResponse(); + $response = $this->getResponse()->getBody(); + $this->assertEmpty($response, $response); + } + + /** + * @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 + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testPushCreatesNewTransaction($pushSpecification = null) + { + $pushSpecification = []; + /** Step 0 - Create fictures (products, customer etc.)and save them to database */ + //$this->generateCustomerFixture(); + list($customer, $quote) = $this->generateQuote(); + + $this->assertNotNull($quote); + + /** Step 2 - Load push */ + /** @var PushResponse $pushProvider */ + $pushProvider = $this->createObject(PushResponse::class); + + $pushSpecification['TransactionID'] = isset($pushSpecification['TransactionID'])?:$quote->getId(); + $pushSpecification['Amount'] = number_format($quote->getGrandTotal(), 2, '.', ''); + $pushSpecification['ShopperID'] = $customer->getId($customer->getId()); + + /** @var SimpleXMLElement $xml */ + $xml = new SimpleXMLElement($pushProvider->providePushXml($pushSpecification)); + + /** Step 3 - Modify push to match cart id And so on [Pushprovider] */ + + /** Step 4 - Set request content (xml) */ + $this->getRequest()->setContent($xml->saveXML()); + + /** Assertions vor dem push */ + /** @var Order $order */ + $order = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($order->isEmpty()); + + /** Step 5 - perform the actual test request on controller */ + $this->dispatch(self::CONTROLLER_PATH); + + echo 'Response-Content: ' . $this->getResponse()->getContent(); + /** Step 6 - Evaluate expected results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); + $this->assertNotNull($fetchedQuote); + + /** @var Order $order */ + $order = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertFalse($order->isEmpty(), 'Order creation failed: Order is empty'); + $collection = $this->transactionFactory->create(); + + /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); + $this->assertNotNull($heidelpayTransaction); + $this->assertFalse($heidelpayTransaction->isEmpty()); + echo 'transaction: ' . $heidelpayTransaction->getUniqueId(); + + $histories = $order->getAllStatusHistory(); + + $historyComments = []; + + foreach ($histories as $entry) { + $historyComments[] = $entry->getComment(); + } + + $debug = [ + 'order' => [ + 'state' => $order->getStatus(), + 'total' => $order->getGrandTotal(), + 'paid' => $order->getTotalPaid(), + 'history' => $historyComments + ], + '$quote' => [ + 'state' => $quote->getStatus(), + 'total' => 30.0,//number_format($quote->getGrandTotal(), 2, '.', ''), + 'paid' => $quote->getTotalPaid(), + ], + 'dataArray' => $this->getResponse()->getBody() + ]; + + echo "\n" . 'debug:' . "\n" . print_r($debug, 1); + + $this->assertEquals( + (float)$xml->Transaction->Payment->Clearing->Amount, + (float)$order->getGrandTotal(), + 'grand total amount doesn\'t match'); + + $this->assertEquals( + (float)$xml->Transaction->Payment->Clearing->Amount, + (float)$order->getTotalPaid(), + 'Order state: ' .$order->getStatus() .'. total paid amount doesn\'t match'); + } + + public function dataProviderPushCreatesNewTransactionDP() + { + + return [ + 'default Push-XML' => [null], + 'Create from IV.PA' => [ + + ], + ]; + } + + /** + * @return array + * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws \Magento\Framework\Exception\CouldNotSaveException + */ + protected function generateQuote() + { + $quoteId = $this->cartManagement->createEmptyCart(); + /** @var CustomerManagementInterface $customerRepository */ + $customerRepository = $this->createObject(\Magento\Customer\Api\CustomerRepositoryInterface::class); + + /** @var Customer $customer */ + $customer = $customerRepository->get('l.h@mail.com'); + + /** Step 1 - 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('hgwsue'); + //$quote->getBillingAddress()->addData($addressData); + $shippingAddress = $quote->getShippingAddress(); + $shippingAddress->setCustomerId($customer->getId()) + ->collectShippingRates() + ->setFreeShipping(true) + ->setShippingMethod('flatrate_flatrate') + ->setPaymentMethod('hgwcc'); + + $quote->collectTotals(); + $quote->save(); + return array($customer, $quote); + } + +} \ No newline at end of file diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php new file mode 100644 index 00000000000..afb651207e9 --- /dev/null +++ b/Test/Integration/IntegrationTestAbstract.php @@ -0,0 +1,260 @@ +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; + } + } + +} \ 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..8ac86f2b557 --- /dev/null +++ b/Test/Integration/_files/categories.php @@ -0,0 +1,15 @@ +create('Magento\Catalog\Model\Category'); +$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..784995355f6 --- /dev/null +++ b/Test/Integration/_files/customer.php @@ -0,0 +1,46 @@ +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'); + +/** @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..56c58ef621a --- /dev/null +++ b/Test/Integration/_files/products.php @@ -0,0 +1,47 @@ +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..864abc24b2c --- /dev/null +++ b/Test/Integration/data/provider/PushResponse.php @@ -0,0 +1,95 @@ + + + + + 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 + + + + + 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 + + + Magento 2.2.8-Community + Heidelpay\PhpPaymentApi + d83f0dae2fca921d00cb70559762a365e55870e0cad5384177a931379e04d0204fb8d01ee16ef109f27ec67fb181e748d688119cf82966f59ab1db476d460a5e + v1.8.0 + SofortPaymentMethod + Heidelpay Gateway 19.5.08 + false + + 2019-06-12 15:53:04 +
+
+XML; + + 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 From b8599f6177f1db65e345fa5bcebd8071dbf5c486 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Wed, 3 Jul 2019 18:49:51 +0200 Subject: [PATCH 07/44] (MAGE2-108) change: add test cases for different transaction types. Also added a negative test to prevent unintentional order creation. --- ...tTestAbstract.php => PushHandlingTest.php} | 212 +++++++++++------- Test/Integration/IntegrationTestAbstract.php | 20 ++ .../data/provider/PushResponse.php | 24 +- 3 files changed, 170 insertions(+), 86 deletions(-) rename Test/Integration/Controller/Index/{PushHandlingTestTestAbstract.php => PushHandlingTest.php} (50%) diff --git a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php b/Test/Integration/Controller/Index/PushHandlingTest.php similarity index 50% rename from Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php rename to Test/Integration/Controller/Index/PushHandlingTest.php index 1cc77bee5fd..26715d62683 100644 --- a/Test/Integration/Controller/Index/PushHandlingTestTestAbstract.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -44,16 +44,6 @@ public function setUp() /** Set Request type */ $request->setMethod($request::METHOD_POST); $request->setHeaders(Headers::fromString('content-type: application/xml')); - - /*$this->loggerMock = $this->createMock(Logger::class); //createMOck can use - - $this->getObjectManager()->addSharedInstance($this->loggerMock,get_class($this->loggerMock)); - - $this->getObjectManager()->configure([ - 'preferences' => [ - LoggerInterface::class => get_class($this->loggerMock) - ] - ]);*/ } public static function loadFixture() @@ -85,6 +75,8 @@ public function testEmptyRequest() } /** + * Test creation of new order via push if no order exists already. + * * @dataProvider dataProviderPushCreatesNewTransactionDP * @magentoDbIsolation enabled * @@ -92,106 +84,116 @@ public function testEmptyRequest() * @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 \Magento\Framework\Exception\CouldNotSaveException * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function testPushCreatesNewTransaction($pushSpecification = null) + public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMethod) { - $pushSpecification = []; - /** Step 0 - Create fictures (products, customer etc.)and save them to database */ - //$this->generateCustomerFixture(); - list($customer, $quote) = $this->generateQuote(); - - $this->assertNotNull($quote); - - /** Step 2 - Load push */ - /** @var PushResponse $pushProvider */ - $pushProvider = $this->createObject(PushResponse::class); - - $pushSpecification['TransactionID'] = isset($pushSpecification['TransactionID'])?:$quote->getId(); - $pushSpecification['Amount'] = number_format($quote->getGrandTotal(), 2, '.', ''); - $pushSpecification['ShopperID'] = $customer->getId($customer->getId()); - - /** @var SimpleXMLElement $xml */ - $xml = new SimpleXMLElement($pushProvider->providePushXml($pushSpecification)); - - /** Step 3 - Modify push to match cart id And so on [Pushprovider] */ + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->dispatch(self::CONTROLLER_PATH); - /** Step 4 - Set request content (xml) */ - $this->getRequest()->setContent($xml->saveXML()); + /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); - /** Assertions vor dem push */ /** @var Order $order */ - $order = $this->orderHelper->fetchOrder($quote->getId()); - $this->assertTrue($order->isEmpty()); + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); - /** Step 5 - perform the actual test request on controller */ - $this->dispatch(self::CONTROLLER_PATH); - - echo 'Response-Content: ' . $this->getResponse()->getContent(); - /** Step 6 - Evaluate expected results (heidelpay)Transaction, Quotes, Orders */ - $fetchedQuote = $this->quoteRepository->get($quote->getId()); $this->assertNotNull($fetchedQuote); + $this->assertEquals('0', $fetchedQuote->getIsActive()); - /** @var Order $order */ - $order = $this->orderHelper->fetchOrder($quote->getId()); - $this->assertFalse($order->isEmpty(), 'Order creation failed: Order is empty'); + $this->assertFalse($fetchedOrder->isEmpty(), 'Order creation failed: Order is empty'); + + // Check Transaction $collection = $this->transactionFactory->create(); + // Check Transaction /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); $this->assertNotNull($heidelpayTransaction); $this->assertFalse($heidelpayTransaction->isEmpty()); - echo 'transaction: ' . $heidelpayTransaction->getUniqueId(); - - $histories = $order->getAllStatusHistory(); - - $historyComments = []; - - foreach ($histories as $entry) { - $historyComments[] = $entry->getComment(); - } - - $debug = [ - 'order' => [ - 'state' => $order->getStatus(), - 'total' => $order->getGrandTotal(), - 'paid' => $order->getTotalPaid(), - 'history' => $historyComments - ], - '$quote' => [ - 'state' => $quote->getStatus(), - 'total' => 30.0,//number_format($quote->getGrandTotal(), 2, '.', ''), - 'paid' => $quote->getTotalPaid(), - ], - 'dataArray' => $this->getResponse()->getBody() - ]; - - echo "\n" . 'debug:' . "\n" . print_r($debug, 1); + // Check Amounts $this->assertEquals( - (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$order->getGrandTotal(), + $fetchedOrder->getGrandTotal(), + $xml->Transaction->Payment->Clearing->Amount, 'grand total amount doesn\'t match'); $this->assertEquals( (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$order->getTotalPaid(), - 'Order state: ' .$order->getStatus() .'. total paid amount doesn\'t match'); + (float)$fetchedOrder->getTotalPaid(), + 'Order state: ' .$fetchedOrder->getStatus() .'. total paid amount doesn\'t match'); } public function dataProviderPushCreatesNewTransactionDP() { - return [ - 'default Push-XML' => [null], - 'Create from IV.PA' => [ + 'Create from IV.RC' => ['IV.RC', 'hgwivs'], + 'Create from CC.DB' => ['CC.DB', 'hgwcc'], + 'Create from DD.DB' => ['DD.DB', 'hgwdd'], + 'Create from OT.RC' => ['OT.RC', 'hgwsue'], + 'Create from PP.RC' => ['PP.RC', 'hgwpp'], + ]; + } - ], + public function CreateNoOrderFromInvalidTransactionTypesDP() + { + return [ + 'create no order from IV.RV' => ['IV.RV', 'hgwivs'], + 'create no order from CC.RF' => ['CC.RF', 'hgwcc'], + 'create no order from IV.IN' => ['IV.IN', 'hgwivs'], + 'create no order from IV.FI' => ['IV.FI', 'hgwivs'], ]; } + /** + * No order should be created for transaction types other then defined. + * + * @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 \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) + { + list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); + $this->dispatch(self::CONTROLLER_PATH); + + /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + $fetchedQuote = $this->quoteRepository->get($quote->getId()); + + /** @var Order $order */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + + $this->assertNotNull($fetchedQuote); + $this->assertEquals('1', $fetchedQuote->getIsActive()); + + $this->assertTrue($fetchedOrder->isEmpty(), 'no Order should be created here'); + + // Check Transaction + $collection = $this->transactionFactory->create(); + + // Check Transaction + /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); + $this->assertNotNull($heidelpayTransaction); + $this->assertTrue($heidelpayTransaction->isEmpty()); + + // Check amount of history entries. + $histories = $fetchedOrder->getAllStatusHistory(); + $this->assertCount(0, $histories); + } + /** * @return array * @throws \Magento\Framework\Exception\CouldNotSaveException @@ -199,7 +201,7 @@ public function dataProviderPushCreatesNewTransactionDP() * @throws \Magento\Framework\Exception\NoSuchEntityException * @throws \Magento\Framework\Exception\CouldNotSaveException */ - protected function generateQuote() + protected function generateQuote($paymentMethod) { $quoteId = $this->cartManagement->createEmptyCart(); /** @var CustomerManagementInterface $customerRepository */ @@ -220,7 +222,7 @@ protected function generateQuote() $quote->addProduct($product); /** @var Payment $payment */ - $quote->getPayment()->setMethod('hgwsue'); + $quote->getPayment()->setMethod($paymentMethod); //$quote->getBillingAddress()->addData($addressData); $shippingAddress = $quote->getShippingAddress(); $shippingAddress->setCustomerId($customer->getId()) @@ -234,4 +236,54 @@ protected function generateQuote() return array($customer, $quote); } + /** + * @param array $pushSpecification + * @param $paymentCode + * @param $quote + * @param $customer + * @return SimpleXMLElement + */ + protected function preparePushNotification($paymentCode, $quote, $customer) + { + $pushProvider = $this->createObject(PushResponse::class); + + $pushSpecification = [ + 'TransactionID' => $quote->getId(), + 'Amount' => $quote->getGrandTotal(), + 'ShopperID' => $customer->getId($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 \Magento\Framework\Exception\CouldNotSaveException + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + protected function prepareRequest($paymentCode, $paymentMethod) + { + /** Step 1 - Prepare data. Quote, Customer, XML */ + list($customer, $quote) = $this->generateQuote($paymentMethod); + + /** @var PushResponse $pushProvider */ + $xml = $this->preparePushNotification($paymentCode, $quote, $customer); + + /** Step 2 Assertions before push controller is called */ + /** @var Order $fetchedOrder */ + $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); + $this->assertTrue($fetchedOrder->isEmpty()); + $this->assertNotNull($quote); + + /** Step 3 - Perform the actual test request on controller */ + $this->getRequest()->setContent($xml->saveXML()); + return array($quote, $xml); + } + } \ No newline at end of file diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php index afb651207e9..0447bea66fe 100644 --- a/Test/Integration/IntegrationTestAbstract.php +++ b/Test/Integration/IntegrationTestAbstract.php @@ -257,4 +257,24 @@ protected function generateProductFixtures($number) } } + /** + * @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/data/provider/PushResponse.php b/Test/Integration/data/provider/PushResponse.php index 864abc24b2c..09a26303eca 100644 --- a/Test/Integration/data/provider/PushResponse.php +++ b/Test/Integration/data/provider/PushResponse.php @@ -32,7 +32,7 @@ class PushResponse SUCCESSFULL Request successfully processed in 'Merchant in Connector Test Mode' - + 53.55 EUR @@ -44,6 +44,17 @@ class PushResponse 4242.8116.1848 Heidelpay QA + + + DE + HEIDELPAYXY + 10000000 + 1234567890 + Heidelpay QA + DE01000000001234567890 + 4260.7131.1424 + + SOFORT @@ -68,12 +79,7 @@ class PushResponse https://test-heidelpay.hpcgw.net/ngw/responsePa?state=9158be8fffffffff17fcff09 - Magento 2.2.8-Community - Heidelpay\PhpPaymentApi d83f0dae2fca921d00cb70559762a365e55870e0cad5384177a931379e04d0204fb8d01ee16ef109f27ec67fb181e748d688119cf82966f59ab1db476d460a5e - v1.8.0 - SofortPaymentMethod - Heidelpay Gateway 19.5.08 false 2019-06-12 15:53:04 @@ -81,6 +87,12 @@ class PushResponse 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; From 305e6fbb94c439748c8b803d0c92a565bf4d7e2f Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 4 Jul 2019 13:58:44 +0200 Subject: [PATCH 08/44] (MAGE2-108) change: also handle additional payment info in push. --- Controller/Index/Push.php | 30 +++++------------ Controller/Index/Response.php | 28 +--------------- Helper/Payment.php | 33 +++++++++++++++++++ .../Controller/Index/PushHandlingTest.php | 28 ++++++++++------ 4 files changed, 61 insertions(+), 58 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 197586039da..a35b25b026b 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -36,19 +36,9 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var \Heidelpay\PhpPaymentApi\Push */ private $heidelpayPush; - /** @var SearchCriteriaBuilder */ - private $searchCriteriaBuilder; - /** - * @var PaymentHelper - */ - private $paymentHelper; - /** - * @var QuoteRepository - */ + /** @var QuoteRepository */ private $quoteRepository; - /** - * @var \Heidelpay\Gateway\Helper\Order - */ + /** @var \Heidelpay\Gateway\Helper\Order */ private $orderHelper; /** @@ -91,7 +81,6 @@ public function __construct( \Magento\Customer\Model\Url $customerUrl, OrderRepository $orderRepository, \Heidelpay\PhpPaymentApi\Push $heidelpayPush, - SearchCriteriaBuilder $searchCriteriaBuilder, QuoteRepository $quoteRepository, \Heidelpay\Gateway\Helper\Order $orderHelper ) { @@ -115,8 +104,6 @@ public function __construct( $this->orderRepository = $orderRepository; $this->heidelpayPush = $heidelpayPush; - $this->searchCriteriaBuilder = $searchCriteriaBuilder; - $this->paymentHelper = $paymentHelper; $this->quoteRepository = $quoteRepository; $this->orderHelper = $orderHelper; } @@ -155,7 +142,7 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); - $data = $this->paymentHelper->getDataFromResponse($pushResponse); + $data = $this->_paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( @@ -163,10 +150,11 @@ public function execute() ); // in case of receipts, we process the push message for receipts. - if ($pushResponse->isSuccess() && $this->paymentHelper->isNewOrderType($paymentType)) { + if ($pushResponse->isSuccess() && $this->_paymentHelper->isNewOrderType($paymentType)) { $transactionId = $pushResponse->getIdentification()->getTransactionId(); $order = $this->orderHelper->fetchOrder($transactionId); + $quote = $this->quoteRepository->get($transactionId); // create order if it doesn't exists already. if ($order === null || $order->isEmpty()) { @@ -174,9 +162,8 @@ public function execute() $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' . $transactionId); - $quote = $this->quoteRepository->get($transactionId); try { - $order = $this->paymentHelper->createOrderFromQuote($quote); + $order = $this->_paymentHelper->createOrderFromQuote($quote); if ($order === null || $order->isEmpty()) { $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); @@ -187,13 +174,14 @@ public function execute() return; } - $this->paymentHelper->mapStatus($data, $order); + $this->_paymentHelper->mapStatus($data, $order); $this->_logger->debug('order status: ' . $order->getStatus()); $this->orderHelper->handleOrderMail($order); $this->orderHelper->handleInvoiceMails($order); $this->orderRepository->save($order); - //TODO: Handle additional payment info from response } + $this->_paymentHelper->handleAdditionalPaymentInformation($quote); + if ($this->_paymentHelper->isReceiptAble($paymentMethod, $paymentType)) { // load the referenced order to receive the order information. diff --git a/Controller/Index/Response.php b/Controller/Index/Response.php index 55d033f7c69..0572ab29dbb 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -262,7 +262,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. @@ -304,32 +304,6 @@ protected function handleInvoiceMails(Order $order) } } - /** - * 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 - */ - protected 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 PaymentInformation $paymentInfo */ - $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( - $quote->getStoreId(), - $quote->getBillingAddress()->getEmail(), - $quote->getPayment()->getMethod() - ); - - if (!$paymentInfo->isEmpty()) { - $paymentInfo->delete(); - } - } - } - /** * Validate Hash to prevent manipulation * @param HeidelpayResponse $response diff --git a/Helper/Payment.php b/Helper/Payment.php index d938d321d82..29c76d26b3d 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -26,6 +26,7 @@ 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; /** @@ -69,6 +70,10 @@ class Payment extends AbstractHelper TransactionType::DEBIT, TransactionType::RESERVATION ]; + /** + * @var PaymentInformationCollectionFactory + */ + private $paymentInformationCollectionFactory; /** * @param Context $context @@ -84,6 +89,7 @@ public function __construct( TransactionFactory $transactionFactory, Resolver $localeResolver, QuoteManagement $cartManagement, + PaymentInformationCollectionFactory $paymentInformationCollectionFactory, HgwTransactionFactory $heidelpayTransactionFactory ) { $this->httpClientFactory = $httpClientFactory; @@ -93,6 +99,7 @@ public function __construct( parent::__construct($context); $this->_cartManagement = $cartManagement; $this->heidelpayTransactionFactory = $heidelpayTransactionFactory; + $this->paymentInformationCollectionFactory = $paymentInformationCollectionFactory; } /** @@ -397,4 +404,30 @@ 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/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 26715d62683..3b1883921af 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -90,7 +90,7 @@ public function testEmptyRequest() * @throws \Magento\Framework\Exception\LocalizedException * @throws \Magento\Framework\Exception\NoSuchEntityException */ - public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMethod) + public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); $this->dispatch(self::CONTROLLER_PATH); @@ -115,16 +115,23 @@ public function testPushCreatesNewTransaction($paymentCode = 'OT.RC', $paymentMe $this->assertNotNull($heidelpayTransaction); $this->assertFalse($heidelpayTransaction->isEmpty()); + $isPreAuthorization = 'PA' ===$this->paymentHelper->splitPaymentCode($paymentCode)[1]; // Check Amounts - $this->assertEquals( - $fetchedOrder->getGrandTotal(), - $xml->Transaction->Payment->Clearing->Amount, - 'grand total amount doesn\'t match'); - - $this->assertEquals( - (float)$xml->Transaction->Payment->Clearing->Amount, - (float)$fetchedOrder->getTotalPaid(), - 'Order state: ' .$fetchedOrder->getStatus() .'. total paid amount doesn\'t match'); + $this->assertEquals( + $fetchedOrder->getGrandTotal(), + $xml->Transaction->Payment->Clearing->Amount, + 'grand total amount doesn\'t match'); + + if (!$isPreAuthorization) + { + $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()); + } + } public function dataProviderPushCreatesNewTransactionDP() @@ -134,6 +141,7 @@ public function dataProviderPushCreatesNewTransactionDP() 'Create from CC.DB' => ['CC.DB', 'hgwcc'], 'Create from DD.DB' => ['DD.DB', 'hgwdd'], 'Create from OT.RC' => ['OT.RC', 'hgwsue'], + 'Create from OT.PA' => ['OT.PA', 'hgwsue'], 'Create from PP.RC' => ['PP.RC', 'hgwpp'], ]; } From b72f991cab7c9eb23295db64fb23198c6ba80c0b Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Wed, 10 Jul 2019 10:46:46 +0200 Subject: [PATCH 09/44] (MAGE2-108) fix style issue --- Helper/Payment.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Helper/Payment.php b/Helper/Payment.php index 29c76d26b3d..c30a04e8d67 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -8,7 +8,6 @@ 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; From 9f649742c38566d9d6a3b93f8975137d58c0d264 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 1 Aug 2019 16:34:14 +0200 Subject: [PATCH 10/44] (MAGE2-108) fix: cleanup code --- Controller/Index/Push.php | 83 ++++++++++++-------- Test/Integration/IntegrationTestAbstract.php | 4 - 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index a35b25b026b..4c976a9fce5 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -2,9 +2,26 @@ 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 Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Model\Session; +use Magento\Customer\Model\Session as CustomerSession; +use Magento\Customer\Model\Url; 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; @@ -12,8 +29,9 @@ use Magento\Sales\Model\Order\Email\Sender\OrderSender; 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\ResourceModel\Order\Collection; +use Psr\Log\LoggerInterface; /** * heidelpay Push Controller @@ -28,7 +46,7 @@ * * @package heidelpay\magento2\controllers */ -class Push extends \Heidelpay\Gateway\Controller\HgwAbstract +class Push extends HgwAbstract { /** @var OrderRepository $orderRepository */ private $orderRepository; @@ -38,51 +56,51 @@ class Push extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var QuoteRepository */ private $quoteRepository; - /** @var \Heidelpay\Gateway\Helper\Order */ + /** @var orderHelper */ private $orderHelper; /** - * @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 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 SearchCriteriaBuilder $searchCriteriaBuilder * @param QuoteRepository $quoteRepository - * @param \Heidelpay\Gateway\Helper\Order $orderHelper + * @param orderHelper $orderHelper */ 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, + 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, QuoteRepository $quoteRepository, - \Heidelpay\Gateway\Helper\Order $orderHelper + orderHelper $orderHelper ) { parent::__construct( $context, @@ -109,12 +127,13 @@ public function __construct( } /** - * @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()) { @@ -169,7 +188,7 @@ public function execute() $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); return; } - } catch (\Exception $e) { + } catch (Exception $e) { $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); return; } @@ -218,7 +237,7 @@ public function execute() // set the invoice states to 'paid', if no due is left. if ($dueLeft <= 0.00) { - /** @var \Magento\Sales\Model\Order\Invoice $invoice */ + /** @var Invoice $invoice */ foreach ($order->getInvoiceCollection() as $invoice) { $invoice->setState(Invoice::STATE_PAID)->save(); } diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php index 0447bea66fe..2d1a888aa74 100644 --- a/Test/Integration/IntegrationTestAbstract.php +++ b/Test/Integration/IntegrationTestAbstract.php @@ -5,7 +5,6 @@ use Heidelpay\Gateway\Helper\BasketHelper; use Heidelpay\Gateway\Helper\Order as OrderHelper; use Heidelpay\Gateway\Helper\Payment; -use Heidelpay\Gateway\Wrapper\QuoteWrapper; use Heidelpay\PhpBasketApi\Object\Basket; use Heidelpay\PhpBasketApi\Object\BasketItem; use Magento\Catalog\Model\Product\Attribute\Source\Status; @@ -22,13 +21,10 @@ use Magento\Quote\Api\CartRepositoryInterface; use Magento\Quote\Api\CouponManagementInterface; use Magento\Catalog\Api\ProductRepositoryInterface; -use Magento\Quote\Api\Data\CartInterface; use Magento\Quote\Api\Data\CartItemInterface; -use Magento\SalesRule\Api\RuleRepositoryInterface; use Magento\Tax\Model\ClassModel; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\AbstractController; -use Magento\SalesRule\Model\Rule; use \Magento\Quote\Model\Quote; use Magento\OfflineShippingSampleData\Model\Tablerate; use Heidelpay\Gateway\Model\ResourceModel\Transaction\CollectionFactory as HeidelpayTransactionCollectionFactory; From d3ff282361a6a6a22d8009ed84ae339164cc4c30 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Wed, 7 Aug 2019 17:32:28 +0200 Subject: [PATCH 11/44] (MAGE2-108) fix merge issues. --- Controller/Index/Push.php | 3 +-- Test/Integration/Controller/Index/PushHandlingTest.php | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 8fca1971636..5125e38534d 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -8,7 +8,6 @@ use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; use Heidelpay\PhpPaymentApi\Exceptions\XmlResponseParserException; use Magento\Checkout\Model\Session as CheckoutSession; -use Magento\Customer\Model\Session; use Magento\Customer\Model\Session as CustomerSession; use Magento\Customer\Model\Url; use Heidelpay\Gateway\Helper\Response as ResponseHelper; @@ -105,7 +104,7 @@ public function __construct( OrderRepository $orderRepository, \Heidelpay\PhpPaymentApi\Push $heidelpayPush, QuoteRepository $quoteRepository, - orderHelper $orderHelper + orderHelper $orderHelper, SearchCriteriaBuilder $searchCriteriaBuilder, ResponseHelper $repsonseHelper ) { diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 3b1883921af..0e5a0d03e52 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -108,8 +108,6 @@ public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) // Check Transaction $collection = $this->transactionFactory->create(); - - // Check Transaction /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); $this->assertNotNull($heidelpayTransaction); From 210ecbd04df4392b8b0dddb960335414d0b41f64 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 8 Aug 2019 13:41:41 +0200 Subject: [PATCH 12/44] (MAGE2-108) [refactor] cleanup code. --- Controller/Index/Push.php | 7 ++-- .../Controller/Index/PushHandlingTest.php | 39 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 5125e38534d..03f6f72eabb 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -7,6 +7,7 @@ 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; @@ -51,7 +52,7 @@ class Push extends HgwAbstract /** @var OrderRepository $orderRepository */ private $orderRepository; - /** @var \Heidelpay\PhpPaymentApi\Push */ + /** @var heidelpayPush */ private $heidelpayPush; /** @var QuoteRepository */ @@ -79,7 +80,7 @@ class Push extends HgwAbstract * @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 @@ -102,7 +103,7 @@ public function __construct( Encryptor $encryptor, Url $customerUrl, OrderRepository $orderRepository, - \Heidelpay\PhpPaymentApi\Push $heidelpayPush, + heidelpayPush $heidelpayPush, QuoteRepository $quoteRepository, orderHelper $orderHelper, SearchCriteriaBuilder $searchCriteriaBuilder, diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 0e5a0d03e52..3c181eb1434 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -9,10 +9,15 @@ namespace Heidelpay\Gateway\Test\Integration\Controller\Index; +use Heidelpay\Gateway\Model\ResourceModel\Transaction\Collection; +use Heidelpay\Gateway\Model\Transaction; use Heidelpay\Gateway\Test\Integration\IntegrationTestAbstract; use Heidelpay\Gateway\Test\Integration\data\provider\PushResponse; use Magento\Customer\Api\CustomerManagementInterface; use Magento\Customer\Model\Customer; +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; @@ -86,9 +91,9 @@ public function testEmptyRequest() * @magentoConfigFixture default_store currency/options/allow EUR * @param string $paymentCode * @param $paymentMethod - * @throws \Magento\Framework\Exception\CouldNotSaveException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException */ public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) { @@ -102,17 +107,18 @@ public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); $this->assertNotNull($fetchedQuote); - $this->assertEquals('0', $fetchedQuote->getIsActive()); $this->assertFalse($fetchedOrder->isEmpty(), 'Order creation failed: Order is empty'); // Check Transaction $collection = $this->transactionFactory->create(); - /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + /** @var Transaction $heidelpayTransaction */ $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); $this->assertNotNull($heidelpayTransaction); $this->assertFalse($heidelpayTransaction->isEmpty()); + $this->assertEquals('0', $fetchedQuote->getIsActive()); + $isPreAuthorization = 'PA' ===$this->paymentHelper->splitPaymentCode($paymentCode)[1]; // Check Amounts $this->assertEquals( @@ -166,16 +172,16 @@ public function CreateNoOrderFromInvalidTransactionTypesDP() * @magentoConfigFixture default_store currency/options/allow EUR * @param string $paymentCode * @param $paymentMethod - * @throws \Magento\Framework\Exception\CouldNotSaveException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException */ public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); $this->dispatch(self::CONTROLLER_PATH); - /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ $fetchedQuote = $this->quoteRepository->get($quote->getId()); /** @var Order $order */ @@ -187,6 +193,7 @@ public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paym $this->assertTrue($fetchedOrder->isEmpty(), 'no Order should be created here'); // Check Transaction + /** @var Collection $collection */ $collection = $this->transactionFactory->create(); // Check Transaction @@ -202,10 +209,10 @@ public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paym /** * @return array - * @throws \Magento\Framework\Exception\CouldNotSaveException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException - * @throws \Magento\Framework\Exception\CouldNotSaveException + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException + * @throws CouldNotSaveException */ protected function generateQuote($paymentMethod) { @@ -269,9 +276,9 @@ protected function preparePushNotification($paymentCode, $quote, $customer) * @param $paymentCode * @param $paymentMethod * @return array - * @throws \Magento\Framework\Exception\CouldNotSaveException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Magento\Framework\Exception\NoSuchEntityException + * @throws CouldNotSaveException + * @throws LocalizedException + * @throws NoSuchEntityException */ protected function prepareRequest($paymentCode, $paymentMethod) { From 8c4a010cd3b95fc03423814cbd2c2b869c121185 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 8 Aug 2019 19:18:23 +0200 Subject: [PATCH 13/44] (MAGE2-108) [change] Test: Add ResponseHelperMock in order to make them work with hash validation. --- .../Controller/Index/PushHandlingTest.php | 6 ++++++ Test/Mocks/Helper/Response.php | 15 +++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 Test/Mocks/Helper/Response.php diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 3c181eb1434..52b6d7f4ff6 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -9,10 +9,12 @@ 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\IntegrationTestAbstract; use Heidelpay\Gateway\Test\Integration\data\provider\PushResponse; +use Heidelpay\Gateway\Test\Mocks\Helper\Response as ResponseHelperMock; use Magento\Customer\Api\CustomerManagementInterface; use Magento\Customer\Model\Customer; use Magento\Framework\Exception\CouldNotSaveException; @@ -282,6 +284,10 @@ protected function preparePushNotification($paymentCode, $quote, $customer) */ protected function prepareRequest($paymentCode, $paymentMethod) { + $this->getObjectManager()->configure( + ['preferences' => [ResponseHelper::class => ResponseHelperMock::class]] + ); + /** Step 1 - Prepare data. Quote, Customer, XML */ list($customer, $quote) = $this->generateQuote($paymentMethod); diff --git a/Test/Mocks/Helper/Response.php b/Test/Mocks/Helper/Response.php new file mode 100644 index 00000000000..fb9196feaa7 --- /dev/null +++ b/Test/Mocks/Helper/Response.php @@ -0,0 +1,15 @@ + Date: Thu, 15 Aug 2019 16:51:11 +0200 Subject: [PATCH 14/44] (MAGE2-108) [change] code style. --- Controller/Index/Push.php | 8 ++++---- Test/Integration/Controller/Index/PushHandlingTest.php | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 03f6f72eabb..2881a9491fe 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -170,7 +170,7 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); - $data = $this->_paymentHelper->getDataFromResponse($pushResponse); + $transactionData = $this->_paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); // Stop processing if hash validation fails. @@ -183,7 +183,7 @@ public function execute() $pushResponse->getPayment()->getCode() ); - // in case of receipts, we process the push message for receipts. + // Only process transactions that my potentially create new order, this includes receipts receipts. if ($pushResponse->isSuccess() && $this->_paymentHelper->isNewOrderType($paymentType)) { $transactionId = $pushResponse->getIdentification()->getTransactionId(); @@ -192,7 +192,7 @@ public function execute() // create order if it doesn't exists already. if ($order === null || $order->isEmpty()) { - $this->_paymentHelper->saveHeidelpayTransaction($pushResponse, $data, 'PUSH'); + $this->_paymentHelper->saveHeidelpayTransaction($pushResponse, $transactionData, 'PUSH'); $this->_logger->debug('heidelpay Push - Order does not exist for transaction. heidelpay transaction id: ' . $transactionId); @@ -208,7 +208,7 @@ public function execute() return; } - $this->_paymentHelper->mapStatus($data, $order); + $this->_paymentHelper->mapStatus($transactionData, $order); $this->_logger->debug('order status: ' . $order->getStatus()); $this->orderHelper->handleOrderMail($order); $this->orderHelper->handleInvoiceMails($order); diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 52b6d7f4ff6..171dbe4c006 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -260,6 +260,7 @@ protected function generateQuote($paymentMethod) */ protected function preparePushNotification($paymentCode, $quote, $customer) { + /** @var PushResponse $pushProvider */ $pushProvider = $this->createObject(PushResponse::class); $pushSpecification = [ @@ -284,11 +285,12 @@ protected function preparePushNotification($paymentCode, $quote, $customer) */ protected function prepareRequest($paymentCode, $paymentMethod) { + /** Disable hash validation */ $this->getObjectManager()->configure( ['preferences' => [ResponseHelper::class => ResponseHelperMock::class]] ); - /** Step 1 - Prepare data. Quote, Customer, XML */ + /** Prepare data. Quote, Customer, XML */ list($customer, $quote) = $this->generateQuote($paymentMethod); /** @var PushResponse $pushProvider */ From 479f95a0bea2c87aaca2d4a0a7c5631ebbca3b5b Mon Sep 17 00:00:00 2001 From: David Owusu <33735090+Ryouzanpaku@users.noreply.github.com> Date: Thu, 24 Oct 2019 11:59:33 +0200 Subject: [PATCH 15/44] Update Controller/Index/Push.php Co-Authored-By: Simon Gabriel --- Controller/Index/Push.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 2881a9491fe..5e507cc9324 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -183,7 +183,7 @@ public function execute() $pushResponse->getPayment()->getCode() ); - // Only process transactions that my potentially create new order, this includes receipts receipts. + // Only process transactions that might potentially create new order, this includes receipts. if ($pushResponse->isSuccess() && $this->_paymentHelper->isNewOrderType($paymentType)) { $transactionId = $pushResponse->getIdentification()->getTransactionId(); From b1f0f23c146a15b8451dc7cd9ea2e8b5b99c983e Mon Sep 17 00:00:00 2001 From: David Owusu <33735090+Ryouzanpaku@users.noreply.github.com> Date: Thu, 24 Oct 2019 12:46:22 +0200 Subject: [PATCH 16/44] Update Helper/Payment.php Co-Authored-By: Simon Gabriel --- Helper/Payment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Helper/Payment.php b/Helper/Payment.php index c30a04e8d67..9b5919eb8c2 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -134,7 +134,7 @@ public function mapStatus($data, $order, $message = false) /** @var HeidelpayAbstractPaymentMethod $paymentMethod */ $paymentMethod = $order->getPayment()->getMethodInstance(); - if ($data['PROCESSING_RESULT'] == 'NOK') { + if ($data['PROCESSING_RESULT'] === ProcessingResult::NOK) { $paymentMethod->cancelledTransactionProcessing($order, $message); } elseif ($this->isProcessing($paymentCode[1], $data)) { $paymentMethod->processingTransactionProcessing($data, $order); From 991562b6ff08841155f4e291f28351f6bda4108f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 24 Oct 2019 12:46:34 +0200 Subject: [PATCH 17/44] [change] (MAGE2-242) Basket: Fix several code style issues. --- Test/Integration/BasketApiTest.php | 46 +++++++++++++++++++++--------- composer.json | 5 ++-- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/Test/Integration/BasketApiTest.php b/Test/Integration/BasketApiTest.php index 400d930d976..8dc2f92aaf0 100755 --- a/Test/Integration/BasketApiTest.php +++ b/Test/Integration/BasketApiTest.php @@ -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 { @@ -134,7 +139,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 +162,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 +186,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 +199,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) { @@ -272,16 +289,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 +308,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 +347,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 +418,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 +444,10 @@ private function printBasketValues($quote) /** * @param $couponCode - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException + * @throws CouldNotSaveException + * @throws InputException + * @throws InvalidBasketitemPositionException + * @throws NoSuchEntityException */ private function assertResult($couponCode) { diff --git a/composer.json b/composer.json index 0091e27c4cf..c63a4f69375 100755 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ "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", @@ -24,7 +25,7 @@ "friendsofphp/php-cs-fixer": "2.1.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": [ { From 08e8c51049dc3f54e318d30e36fec7a91389893e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 24 Oct 2019 12:48:02 +0200 Subject: [PATCH 18/44] [change] (MAGE2-242) Tests: Add missing dev dependency. --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c63a4f69375..bdbe67c6b6a 100755 --- a/composer.json +++ b/composer.json @@ -22,7 +22,8 @@ "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 | ^102.0.0" From cfdb8a2d90b2566a14cd3588a56ffef0f0ef53ac Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 24 Oct 2019 12:51:07 +0200 Subject: [PATCH 19/44] [change] (MAGE2-242) Basket: Reorganise test class. --- Test/Integration/BasketApiTest.php | 32 ++++++++++++++++++------------ 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/Test/Integration/BasketApiTest.php b/Test/Integration/BasketApiTest.php index 8dc2f92aaf0..671fbdbf201 100755 --- a/Test/Integration/BasketApiTest.php +++ b/Test/Integration/BasketApiTest.php @@ -113,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 @@ -252,6 +240,8 @@ private function performCheckout($couponCode) return array($quote, $basket); } + // + // /** @@ -469,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'] + ]; + } + // } From 4dbf96b65d969946d9db3d8dfbf698e83ba075d5 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 24 Oct 2019 13:06:47 +0200 Subject: [PATCH 20/44] (MAGE2-231) [refactor] code style. --- Controller/Index/Push.php | 2 +- Helper/Order.php | 14 +- .../payment/method-renderer/hgw-abstract.js | 382 +++++++++--------- 3 files changed, 195 insertions(+), 203 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 5e507cc9324..f6ffd41c1bc 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -170,7 +170,6 @@ public function execute() } $pushResponse = $this->heidelpayPush->getResponse(); - $transactionData = $this->_paymentHelper->getDataFromResponse($pushResponse); $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); // Stop processing if hash validation fails. @@ -192,6 +191,7 @@ public function execute() // 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); diff --git a/Helper/Order.php b/Helper/Order.php index a46ac06869c..427ae0eb630 100644 --- a/Helper/Order.php +++ b/Helper/Order.php @@ -88,9 +88,7 @@ public function handleInvoiceMails($order) 'canInvoice' => $order->canInvoice(), 'canSendNewInvoiceEmail' => $this->salesHelper->canSendNewInvoiceEmail($order->getStore()->getId()) ]; - $this->_logger->debug('handling invoices... ' . print_r( - $debugArray, 1 - ) + $this->_logger->debug('heidelpay - handling invoices' . print_r($debugArray, 1) ); if (!$order->canInvoice() && $this->salesHelper->canSendNewInvoiceEmail($order->getStore()->getId())) { @@ -114,9 +112,7 @@ public function handleOrderMail($order) $this->orderSender->send($order); } } catch (\Exception $e) { - $this->_logger->error( - 'Heidelpay - Response: Cannot send order confirmation E-Mail. ' . $e->getMessage() - ); + $this->_logger->error('heidelpay - Response: Cannot send order confirmation E-Mail. ' . $e->getMessage()); } } @@ -126,11 +122,7 @@ public function handleOrderMail($order) */ public function fetchOrder($transactionId) { - $criteria = $this->searchCriteriaBuilder - ->addFilter( - 'quote_id', - $transactionId - )->create(); + $criteria = $this->searchCriteriaBuilder->addFilter('quote_id', $transactionId)->create(); /** @var Collection $orderList */ $orderList = $this->orderRepository->getList($criteria); 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; + } + }); + } +); From f4d1443952f75804aa26bf2bac3798ecae60fa3d Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 24 Oct 2019 13:14:49 +0200 Subject: [PATCH 21/44] (MAGE2-231) [refactor] correct some file headers. --- Gateway/Config/HgwMainConfigInterface.php | 2 +- Helper/BasketHelper.php | 2 +- Helper/Order.php | 2 +- Test/Integration/BasketApiTest.php | 2 +- .../Controller/Index/PushHandlingTest.php | 12 ++++++++---- Traits/DumpGetterReturnsTrait.php | 2 +- Wrapper/BaseWrapper.php | 2 +- Wrapper/CustomerWrapper.php | 2 +- Wrapper/ItemWrapper.php | 2 +- Wrapper/QuoteWrapper.php | 2 +- 10 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Gateway/Config/HgwMainConfigInterface.php b/Gateway/Config/HgwMainConfigInterface.php index 2cd085d1c77..ac621fd854a 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..202d8d95d84 100755 --- a/Helper/BasketHelper.php +++ b/Helper/BasketHelper.php @@ -18,7 +18,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 * diff --git a/Helper/Order.php b/Helper/Order.php index 427ae0eb630..dc9ab3f2c78 100644 --- a/Helper/Order.php +++ b/Helper/Order.php @@ -18,7 +18,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 * diff --git a/Test/Integration/BasketApiTest.php b/Test/Integration/BasketApiTest.php index 400d930d976..a29c2a27702 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 * diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 171dbe4c006..d64b14a1f7e 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -1,9 +1,13 @@ + * + * @package heidelpay/magento2 */ namespace Heidelpay\Gateway\Test\Integration\Controller\Index; 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 * From fbc9a9ef49bd812db8f4ff4404110f45216ed4fd Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Thu, 24 Oct 2019 13:26:35 +0200 Subject: [PATCH 22/44] (MAGE2-231) [refactor] use test annotations for push tests. --- .../Controller/Index/PushHandlingTest.php | 24 +++++++++---------- composer.json | 3 ++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index d64b14a1f7e..eec166d7de7 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -65,16 +65,13 @@ public static function loadFixture() include __DIR__ . '/../../_files/customer.php'; } - public function testTrue() - { - $this->assertTrue(true); - } - /** + * @test + * * @magentoDbIsolation enabled * @magentoAppIsolation enabled */ - public function testEmptyRequest() + public function EmptyRequest() { $request = $this->getRequest(); $request->setMethod($request::METHOD_GET); @@ -88,6 +85,8 @@ public function testEmptyRequest() /** * Test creation of new order via push if no order exists already. * + * @test + * * @dataProvider dataProviderPushCreatesNewTransactionDP * @magentoDbIsolation enabled * @@ -101,12 +100,12 @@ public function testEmptyRequest() * @throws LocalizedException * @throws NoSuchEntityException */ - public function testPushCreatesNewTransaction($paymentCode, $paymentMethod) + public function PushCreatesNewTransaction($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); $this->dispatch(self::CONTROLLER_PATH); - /** Step 4 - Evaluate end results (heidelpay)Transaction, Quotes, Orders */ + /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ $fetchedQuote = $this->quoteRepository->get($quote->getId()); /** @var Order $order */ @@ -169,6 +168,7 @@ public function CreateNoOrderFromInvalidTransactionTypesDP() /** * No order should be created for transaction types other then defined. * + * @test * @dataProvider CreateNoOrderFromInvalidTransactionTypesDP * @magentoDbIsolation enabled * @@ -182,7 +182,7 @@ public function CreateNoOrderFromInvalidTransactionTypesDP() * @throws LocalizedException * @throws NoSuchEntityException */ - public function testCreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) + public function CreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); $this->dispatch(self::CONTROLLER_PATH); @@ -229,7 +229,7 @@ protected function generateQuote($paymentMethod) /** @var Customer $customer */ $customer = $customerRepository->get('l.h@mail.com'); - /** Step 1 - Create a cart | Sometimes also create an order for that cart.*/ + /** Create a cart | Sometimes also create an order for that cart.*/ /** @var Quote $quote */ $quote = $this->quoteRepository->get($quoteId); @@ -300,13 +300,13 @@ protected function prepareRequest($paymentCode, $paymentMethod) /** @var PushResponse $pushProvider */ $xml = $this->preparePushNotification($paymentCode, $quote, $customer); - /** Step 2 Assertions before push controller is called */ + /** Assertions before push controller is called */ /** @var Order $fetchedOrder */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); $this->assertTrue($fetchedOrder->isEmpty()); $this->assertNotNull($quote); - /** Step 3 - Perform the actual test request on controller */ + /** Perform the actual test request on controller */ $this->getRequest()->setContent($xml->saveXML()); return array($quote, $xml); } diff --git a/composer.json b/composer.json index d9aad8c76f3..b87f02cb279 100755 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "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", + "zendframework/zend-http": "^2", }, "suggest": { "magento/module-checkout-agreements": "^100.0.0 | ^101.0.0" From eb41ea05504e7c61bb7a56176899585d7066c30c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 25 Oct 2019 15:10:56 +0200 Subject: [PATCH 23/44] [cleanup] (MAGE2-242) Cleanup the code. --- Helper/BasketHelper.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Helper/BasketHelper.php b/Helper/BasketHelper.php index f30d3dacaae..b4accc66672 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 @@ -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) { @@ -76,7 +77,7 @@ public function convertQuoteToBasket(Quote $quote) ->setAmountTotalDiscount($basketTotals->getTotalDiscountAmount()) ->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 +132,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) { From 9e32fe86b6ede06db43cf1ab6b187962096f175e Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 25 Oct 2019 15:12:09 +0200 Subject: [PATCH 24/44] [cleanup] (MAGE2-242) Make sure the basket value equals the gross value of the order. --- Helper/BasketHelper.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Helper/BasketHelper.php b/Helper/BasketHelper.php index b4accc66672..c76c2df0b6f 100755 --- a/Helper/BasketHelper.php +++ b/Helper/BasketHelper.php @@ -72,9 +72,7 @@ public function convertQuoteToBasket(Quote $quote) $basketReferenceId = $basketTotals->getBasketReferenceId(); $basket = $basketRequest->getBasket(); $basket->setCurrencyCode($basketTotals->getCurrencyCode()) - ->setAmountTotalNet($basketTotals->getSubtotalWithDiscountAndShipping()) - ->setAmountTotalVat($basketTotals->getActualTaxAmount()) - ->setAmountTotalDiscount($basketTotals->getTotalDiscountAmount()) + ->setAmountTotalNet($basketTotals->normalizeValue($quote->getGrandTotal())) ->setBasketReferenceId($basketReferenceId); /** @var Item $item */ From 3ee58e5a4913f841932f866f18eefc6557da460c Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 25 Oct 2019 15:17:37 +0200 Subject: [PATCH 25/44] [bugfix] (MAGE2-242) Update changelog. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c26b6b1b775..1ef5b9e91f6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ## 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 + +## X.X.X +### Fixed +- Made sure the reserved value matches the gross value of the order to avoid problems finalizing. + ## 19.10.17 ### Added - Hash validation to push requests. From cbd7151a6c120a6b4512ff131f28e3317a06bae6 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Mon, 28 Oct 2019 10:52:38 +0100 Subject: [PATCH 26/44] (MAGE2-231) [fix] composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b87f02cb279..5a0277b0b51 100755 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "magento/marketplace-eqp": "~1.0.5", "heidelpay/phpdocumentor": "2.9.1", "friendsofphp/php-cs-fixer": "2.1.0", - "zendframework/zend-http": "^2", + "zendframework/zend-http": "^2" }, "suggest": { "magento/module-checkout-agreements": "^100.0.0 | ^101.0.0" From 3bdfc7418d36077c1a4bce45a93ab8685cc8926e Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 12 Nov 2019 09:37:39 +0100 Subject: [PATCH 27/44] (MAGE2-231) [fix] Add missing headers --- Test/Integration/IntegrationTestAbstract.php | 11 ++++++++++- Test/Integration/_files/categories.php | 13 ++++++++++++- Test/Integration/_files/customer.php | 11 +++++++++++ Test/Integration/_files/products.php | 11 +++++++++++ Test/Integration/data/provider/PushResponse.php | 12 ++++++++---- Test/Mocks/Helper/Response.php | 16 +++++++++++++++- 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/Test/Integration/IntegrationTestAbstract.php b/Test/Integration/IntegrationTestAbstract.php index 2d1a888aa74..81f9814b89f 100644 --- a/Test/Integration/IntegrationTestAbstract.php +++ b/Test/Integration/IntegrationTestAbstract.php @@ -1,5 +1,14 @@ + * + * @package heidelpay/magento2 + */ namespace Heidelpay\Gateway\Test\Integration; use Heidelpay\Gateway\Helper\BasketHelper; diff --git a/Test/Integration/_files/categories.php b/Test/Integration/_files/categories.php index 8ac86f2b557..6fe6bff0bd4 100644 --- a/Test/Integration/_files/categories.php +++ b/Test/Integration/_files/categories.php @@ -1,6 +1,17 @@ + * + * @package heidelpay/magento2 + */ + /** @var $category \Magento\Catalog\Model\Category */ -$category = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('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') diff --git a/Test/Integration/_files/customer.php b/Test/Integration/_files/customer.php index 784995355f6..dedfcdab641 100644 --- a/Test/Integration/_files/customer.php +++ b/Test/Integration/_files/customer.php @@ -1,4 +1,15 @@ + * + * @package heidelpay/magento2 + */ + $yesterday = new DateTime(); $yesterday->sub(new \DateInterval('P1D')); $tomorrow= new DateTime(); diff --git a/Test/Integration/_files/products.php b/Test/Integration/_files/products.php index 56c58ef621a..40b2e8c523a 100644 --- a/Test/Integration/_files/products.php +++ b/Test/Integration/_files/products.php @@ -1,4 +1,15 @@ + * + * @package heidelpay/magento2 + */ + $yesterday = new DateTime(); $yesterday->sub(new \DateInterval('P1D')); $tomorrow= new DateTime(); diff --git a/Test/Integration/data/provider/PushResponse.php b/Test/Integration/data/provider/PushResponse.php index 09a26303eca..a18ee739166 100644 --- a/Test/Integration/data/provider/PushResponse.php +++ b/Test/Integration/data/provider/PushResponse.php @@ -1,9 +1,13 @@ + * + * @package heidelpay/magento2 */ namespace Heidelpay\Gateway\Test\Integration\data\provider; diff --git a/Test/Mocks/Helper/Response.php b/Test/Mocks/Helper/Response.php index fb9196feaa7..63e97164d67 100644 --- a/Test/Mocks/Helper/Response.php +++ b/Test/Mocks/Helper/Response.php @@ -1,5 +1,14 @@ + * + * @package heidelpay/magento2 + */ namespace Heidelpay\Gateway\Test\Mocks\Helper; @@ -8,6 +17,11 @@ 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; From 49862001af27d5e5bee5fc657db0110920975104 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 12 Nov 2019 12:20:57 +0100 Subject: [PATCH 28/44] (MAGE2-231) [change] Refactor tests. --- .../Controller/Index/PushHandlingTest.php | 155 +++++++++++------- Test/Integration/_files/customer.php | 2 +- 2 files changed, 93 insertions(+), 64 deletions(-) diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index eec166d7de7..fea22ea454d 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -16,11 +16,15 @@ use Heidelpay\Gateway\Helper\Response as ResponseHelper; use Heidelpay\Gateway\Model\ResourceModel\Transaction\Collection; use Heidelpay\Gateway\Model\Transaction; -use Heidelpay\Gateway\Test\Integration\IntegrationTestAbstract; 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; @@ -34,9 +38,9 @@ /** * @inheritDoc * - * @property \Magento\Framework\App\Request\Http $_request + * @property Http $_request * - * @method \Magento\Framework\App\Request\Http getResponse() + * @method Http getResponse() * */ class PushHandlingTest extends IntegrationTestAbstract @@ -49,7 +53,7 @@ public function setUp() { parent::setUp(); - /** @var \Magento\Framework\App\Request\Http $request */ + /** @var Http $request */ $request = $this->getRequest(); /** Set Request type */ @@ -103,36 +107,28 @@ public function EmptyRequest() public function PushCreatesNewTransaction($paymentCode, $paymentMethod) { list($quote, $xml) = $this->prepareRequest($paymentCode, $paymentMethod); - $this->dispatch(self::CONTROLLER_PATH); + $this->assertQuoteHasNoOrder($quote); + $this->dispatch(self::CONTROLLER_PATH); // Call push controller. - /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ - $fetchedQuote = $this->quoteRepository->get($quote->getId()); + /** Evaluate end results. Quote, Order, Transaction */ + $this->assertQuoteStatus($quote->getId()); /** @var Order $order */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); - - $this->assertNotNull($fetchedQuote); - $this->assertFalse($fetchedOrder->isEmpty(), 'Order creation failed: Order is empty'); - // Check Transaction - $collection = $this->transactionFactory->create(); - /** @var Transaction $heidelpayTransaction */ - $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); - $this->assertNotNull($heidelpayTransaction); - $this->assertFalse($heidelpayTransaction->isEmpty()); + $uniqueId = $xml->Transaction->Identification->UniqueID; + $this->AssertMagentoTransactionExists($uniqueId); - $this->assertEquals('0', $fetchedQuote->getIsActive()); + // Check Amounts + $this->assertEquals( + $xml->Transaction->Payment->Clearing->Amount, + $fetchedOrder->getGrandTotal(), + 'Grand total amount doesn\'t match'); - $isPreAuthorization = 'PA' ===$this->paymentHelper->splitPaymentCode($paymentCode)[1]; - // Check Amounts - $this->assertEquals( - $fetchedOrder->getGrandTotal(), - $xml->Transaction->Payment->Clearing->Amount, - 'grand total amount doesn\'t match'); - if (!$isPreAuthorization) - { + $shouldBeMarkedAsPaid = TransactionType::RESERVATION !== $this->paymentHelper->splitPaymentCode($paymentCode)[1]; + if ($shouldBeMarkedAsPaid) { $this->assertEquals( (float)$xml->Transaction->Payment->Clearing->Amount, (float)$fetchedOrder->getTotalPaid(), @@ -143,25 +139,30 @@ public function PushCreatesNewTransaction($paymentCode, $paymentMethod) } + /** Data provider for transaction types that should create new order. + * @return array + */ public function dataProviderPushCreatesNewTransactionDP() { return [ - 'Create from IV.RC' => ['IV.RC', 'hgwivs'], - 'Create from CC.DB' => ['CC.DB', 'hgwcc'], - 'Create from DD.DB' => ['DD.DB', 'hgwdd'], - 'Create from OT.RC' => ['OT.RC', 'hgwsue'], - 'Create from OT.PA' => ['OT.PA', 'hgwsue'], - 'Create from PP.RC' => ['PP.RC', 'hgwpp'], + '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 IV.RV' => ['IV.RV', 'hgwivs'], - 'create no order from CC.RF' => ['CC.RF', 'hgwcc'], - 'create no order from IV.IN' => ['IV.IN', 'hgwivs'], - 'create no order from IV.FI' => ['IV.FI', 'hgwivs'], + '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'], ]; } @@ -185,48 +186,40 @@ public function CreateNoOrderFromInvalidTransactionTypesDP() 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 */ - $fetchedQuote = $this->quoteRepository->get($quote->getId()); + $this->assertQuoteStatus($quote->getId(), '1'); /** @var Order $order */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); - - $this->assertNotNull($fetchedQuote); - $this->assertEquals('1', $fetchedQuote->getIsActive()); - - $this->assertTrue($fetchedOrder->isEmpty(), 'no Order should be created here'); + $this->assertTrue($fetchedOrder->isEmpty(), 'No Order should be created here'); // Check Transaction /** @var Collection $collection */ $collection = $this->transactionFactory->create(); - // Check Transaction - /** @var \Heidelpay\Gateway\Model\Transaction $heidelpayTransaction */ + /** @var Transaction $heidelpayTransaction */ $heidelpayTransaction = $collection->loadByTransactionId($xml->Transaction->Identification->UniqueID); $this->assertNotNull($heidelpayTransaction); $this->assertTrue($heidelpayTransaction->isEmpty()); - - // Check amount of history entries. - $histories = $fetchedOrder->getAllStatusHistory(); - $this->assertCount(0, $histories); } /** + * @param $paymentMethod * @return array * @throws CouldNotSaveException * @throws LocalizedException * @throws NoSuchEntityException - * @throws CouldNotSaveException */ protected function generateQuote($paymentMethod) { $quoteId = $this->cartManagement->createEmptyCart(); /** @var CustomerManagementInterface $customerRepository */ - $customerRepository = $this->createObject(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $customerRepository = $this->createObject(CustomerRepositoryInterface::class); - /** @var Customer $customer */ + /** @var Customer|CustomerInterface $customer */ $customer = $customerRepository->get('l.h@mail.com'); /** Create a cart | Sometimes also create an order for that cart.*/ @@ -250,19 +243,17 @@ protected function generateQuote($paymentMethod) ->setShippingMethod('flatrate_flatrate') ->setPaymentMethod('hgwcc'); - $quote->collectTotals(); - $quote->save(); + $quote->collectTotals()->save(); return array($customer, $quote); } /** - * @param array $pushSpecification * @param $paymentCode - * @param $quote - * @param $customer + * @param Quote $quote + * @param Customer $customer * @return SimpleXMLElement */ - protected function preparePushNotification($paymentCode, $quote, $customer) + protected function preparePushNotification($paymentCode, Quote $quote, $customer) { /** @var PushResponse $pushProvider */ $pushProvider = $this->createObject(PushResponse::class); @@ -270,7 +261,7 @@ protected function preparePushNotification($paymentCode, $quote, $customer) $pushSpecification = [ 'TransactionID' => $quote->getId(), 'Amount' => $quote->getGrandTotal(), - 'ShopperID' => $customer->getId($customer->getId()) + 'ShopperID' => $customer->getId() ]; /** @var SimpleXMLElement $xml */ @@ -300,15 +291,53 @@ protected function prepareRequest($paymentCode, $paymentMethod) /** @var PushResponse $pushProvider */ $xml = $this->preparePushNotification($paymentCode, $quote, $customer); - /** Assertions before push controller is called */ + /** 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); - - /** Perform the actual test request on controller */ - $this->getRequest()->setContent($xml->saveXML()); - return array($quote, $xml); } -} \ No newline at end of file + /** Assert that quote status is set as expected. + * @param $quoteId + * @param string $expectedStatus + * @throws NoSuchEntityException + */ + private function assertQuoteStatus($quoteId, $expectedStatus = '0') + { + $fetchedQuote = $this->quoteRepository->get($quoteId); + $this->assertNotNull($fetchedQuote); + + $message = 'New order was created - Quote should NOT be active anymore!'; + if ($expectedStatus !== '0') { + $message = 'No order was created - Quote should still be active!'; + } + + $this->assertEquals( + $expectedStatus, + $fetchedQuote->getIsActive(), + $message); + } +} diff --git a/Test/Integration/_files/customer.php b/Test/Integration/_files/customer.php index dedfcdab641..4aa69ac64fd 100644 --- a/Test/Integration/_files/customer.php +++ b/Test/Integration/_files/customer.php @@ -18,7 +18,7 @@ $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); /** @var $product \Magento\Catalog\Model\Product */ -$customerFactory = $objectManager->create('Magento\Customer\Api\Data\CustomerInterface'); +$customerFactory = $objectManager->create(Magento\Customer\Api\Data\CustomerInterface::class); /** @var \Magento\Tax\Model\ClassModel $customerTaxClass */ $customerTaxClass = $objectManager->create(Magento\Tax\Model\ClassModel::class); From 0d82181a8b586abd99a59d8b91cf797a56d1df6d Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 12 Nov 2019 12:22:43 +0100 Subject: [PATCH 29/44] (MAGE2-231) [change] cleanup composer.json --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 5cc862a38e7..bdbe67c6b6a 100755 --- a/composer.json +++ b/composer.json @@ -23,8 +23,7 @@ "magento/marketplace-eqp": "~1.0.5", "heidelpay/phpdocumentor": "2.9.1", "friendsofphp/php-cs-fixer": "2.1.0", - "allure-framework/allure-phpunit": "~1.2.0", - "zendframework/zend-http": "^2" + "allure-framework/allure-phpunit": "~1.2.0" }, "suggest": { "magento/module-checkout-agreements": "^100.0.0 | ^101.0.0 | ^102.0.0" From b2b93895f7c2bf9c1bc310b4305ff8d28c69b1d4 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Fri, 15 Nov 2019 17:21:00 +0100 Subject: [PATCH 30/44] (MAGE2-231) [change] code style. --- .../Controller/Index/PushHandlingTest.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index fea22ea454d..6a5e9b5a073 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -111,14 +111,14 @@ public function PushCreatesNewTransaction($paymentCode, $paymentMethod) $this->dispatch(self::CONTROLLER_PATH); // Call push controller. /** Evaluate end results. Quote, Order, Transaction */ - $this->assertQuoteStatus($quote->getId()); + $this->assertQuoteIsActive($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); + $this->assertMagentoTransactionExists($uniqueId); // Check Amounts $this->assertEquals( @@ -190,7 +190,7 @@ public function CreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentM $this->dispatch(self::CONTROLLER_PATH); /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ - $this->assertQuoteStatus($quote->getId(), '1'); + $this->assertQuoteIsActive($quote->getId(), true); /** @var Order $order */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); @@ -299,7 +299,7 @@ protected function prepareRequest($paymentCode, $paymentMethod) /** Assert that magento transaction with given unique id exists. * @param $uniqueId */ - private function AssertMagentoTransactionExists($uniqueId) + private function assertMagentoTransactionExists($uniqueId) { $collection = $this->transactionFactory->create(); /** @var Transaction $heidelpayTransaction */ @@ -320,24 +320,26 @@ private function assertQuoteHasNoOrder(Quote $quote) $this->assertNotNull($quote); } - /** Assert that quote status is set as expected. + /** Assertion whether quote should be active or not. * @param $quoteId - * @param string $expectedStatus + * @param bool $expectIsActive * @throws NoSuchEntityException */ - private function assertQuoteStatus($quoteId, $expectedStatus = '0') + private function assertQuoteIsActive($quoteId, $expectIsActive) { $fetchedQuote = $this->quoteRepository->get($quoteId); $this->assertNotNull($fetchedQuote); $message = 'New order was created - Quote should NOT be active anymore!'; - if ($expectedStatus !== '0') { + if ($expectIsActive === true) { $message = 'No order was created - Quote should still be active!'; } + $isActive = $fetchedQuote->getIsActive() === '1'; + $this->assertEquals( - $expectedStatus, - $fetchedQuote->getIsActive(), + $expectIsActive, + $isActive, $message); } } From 151b2c05ac80521522701c05b0d84713e92f2fde Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Fri, 15 Nov 2019 17:34:16 +0100 Subject: [PATCH 31/44] (MAGE2-231) [change] code style. --- Test/Integration/Controller/Index/PushHandlingTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Test/Integration/Controller/Index/PushHandlingTest.php b/Test/Integration/Controller/Index/PushHandlingTest.php index 6a5e9b5a073..5903964ff71 100644 --- a/Test/Integration/Controller/Index/PushHandlingTest.php +++ b/Test/Integration/Controller/Index/PushHandlingTest.php @@ -111,7 +111,7 @@ public function PushCreatesNewTransaction($paymentCode, $paymentMethod) $this->dispatch(self::CONTROLLER_PATH); // Call push controller. /** Evaluate end results. Quote, Order, Transaction */ - $this->assertQuoteIsActive($quote->getId(), false); + $this->assertQuoteActive($quote->getId(), false); /** @var Order $order */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); @@ -190,7 +190,7 @@ public function CreateNoOrderFromInvalidTransactionTypes($paymentCode, $paymentM $this->dispatch(self::CONTROLLER_PATH); /** Evaluate end results (heidelpay)Transaction, Quotes, Orders */ - $this->assertQuoteIsActive($quote->getId(), true); + $this->assertQuoteActive($quote->getId(), true); /** @var Order $order */ $fetchedOrder = $this->orderHelper->fetchOrder($quote->getId()); @@ -325,7 +325,7 @@ private function assertQuoteHasNoOrder(Quote $quote) * @param bool $expectIsActive * @throws NoSuchEntityException */ - private function assertQuoteIsActive($quoteId, $expectIsActive) + private function assertQuoteActive($quoteId, $expectIsActive) { $fetchedQuote = $this->quoteRepository->get($quoteId); $this->assertNotNull($fetchedQuote); From b818849fd1907609c506bb1a6f9b6fdcc3ab405f Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 10 Jan 2020 11:42:47 +0100 Subject: [PATCH 32/44] [change] (MAGE2-257) Add refund to iDeal payment method. --- CHANGELOG.md | 3 +++ PaymentMethods/HeidelpayIDealPaymentMethod.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ef5b9e91f6..fce0b13ec88 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ 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 ## X.X.X +### Added +- Refund to iDeal payment method. + ### Fixed - Made sure the reserved value matches the gross value of the order to avoid problems finalizing. 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; } /** From 520b7b2782ea1074dbef41835538ecfe75742c87 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Mon, 27 Jan 2020 10:02:25 +0100 Subject: [PATCH 33/44] [change] (MAGE2-262) Add BasketId to Sales-Order-Grid. --- Model/ResourceModel/Order/Grid/Collection.php | 19 +++++++++++++++++++ etc/di.xml | 14 ++++++++++++++ .../ui_component/sales_order_grid.xml | 13 +++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 Model/ResourceModel/Order/Grid/Collection.php create mode 100644 view/adminhtml/ui_component/sales_order_grid.xml diff --git a/Model/ResourceModel/Order/Grid/Collection.php b/Model/ResourceModel/Order/Grid/Collection.php new file mode 100644 index 00000000000..5597cd93eef --- /dev/null +++ b/Model/ResourceModel/Order/Grid/Collection.php @@ -0,0 +1,19 @@ +join( + [$this->getTable('sales_order')], + 'main_table.entity_id = '.$this->getTable('sales_order').'.entity_id', + array('quote_id') + ); + + return $this; + } +} \ 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/view/adminhtml/ui_component/sales_order_grid.xml b/view/adminhtml/ui_component/sales_order_grid.xml new file mode 100644 index 00000000000..d00bfeb09f2 --- /dev/null +++ b/view/adminhtml/ui_component/sales_order_grid.xml @@ -0,0 +1,13 @@ + ++ + + + + true + QuoteId + + + + + \ No newline at end of file From a855cc7f1ede4f765a9bfaff8ae1c36a0c52c088 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 30 Jan 2020 17:02:13 +0100 Subject: [PATCH 34/44] [change] (MAGE2262) Add quote id to sales_order_grid only for heidelpay methods. --- Model/ResourceModel/Order/Grid/Collection.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Model/ResourceModel/Order/Grid/Collection.php b/Model/ResourceModel/Order/Grid/Collection.php index 5597cd93eef..6e776fd9dce 100644 --- a/Model/ResourceModel/Order/Grid/Collection.php +++ b/Model/ResourceModel/Order/Grid/Collection.php @@ -2,18 +2,20 @@ namespace Heidelpay\Gateway\Model\ResourceModel\Order\Grid; use Magento\Framework\View\Element\UiComponent\DataProvider\SearchResult; +use Zend_Db_Expr; class Collection extends SearchResult { protected function _initSelect() { parent::_initSelect(); - $this->join( - [$this->getTable('sales_order')], - 'main_table.entity_id = '.$this->getTable('sales_order').'.entity_id', - array('quote_id') + $subquery = new Zend_Db_Expr( + '(SELECT sales_order.quote_id,sales_order.entity_id FROM `sales_order_grid` AS `mt` ' . + 'INNER JOIN `sales_order` ON mt.entity_id = sales_order.entity_id where mt.payment_method like "hgw%")' ); + $this->getSelect()->joinLeft(['t' => $subquery], 'main_table.entity_id = t.entity_id', array('quote_id')); + return $this; } -} \ No newline at end of file +} From 963e2f937ce2be410060462235b1387be9fd8302 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 30 Jan 2020 17:31:08 +0100 Subject: [PATCH 35/44] [change] (MAGE2-262) Move sales-order-grid addition to adminhtml/di.xml. --- etc/adminhtml/di.xml | 14 ++++++++++++++ etc/di.xml | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml index 44c1ce4988c..e3732d3b188 100644 --- a/etc/adminhtml/di.xml +++ b/etc/adminhtml/di.xml @@ -2,4 +2,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/di.xml b/etc/di.xml index e4a77c143ee..7994ef456b5 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -157,18 +157,4 @@ - - - - Heidelpay\Gateway\Model\ResourceModel\Order\Grid\Collection - - - - - - sales_order_grid - Magento\Sales\Model\ResourceModel\Order - - - \ No newline at end of file From 3746a7cfcc489fc4a1fc61e41c23d5ae920fce88 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Thu, 30 Jan 2020 17:32:39 +0100 Subject: [PATCH 36/44] [change] (MAGE2-262) Remove translation for new sales_order_grid column. --- view/adminhtml/ui_component/sales_order_grid.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/adminhtml/ui_component/sales_order_grid.xml b/view/adminhtml/ui_component/sales_order_grid.xml index d00bfeb09f2..81e4447f01d 100644 --- a/view/adminhtml/ui_component/sales_order_grid.xml +++ b/view/adminhtml/ui_component/sales_order_grid.xml @@ -5,7 +5,7 @@ true - QuoteId + heidelpay TxnId From 308e85771a62b30d36fcd5f57d5dd7f481278866 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 31 Jan 2020 10:17:51 +0100 Subject: [PATCH 37/44] [change] (MAGE2-262) Add doc comment. --- Model/ResourceModel/Order/Grid/Collection.php | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Model/ResourceModel/Order/Grid/Collection.php b/Model/ResourceModel/Order/Grid/Collection.php index 6e776fd9dce..38a51ba594a 100644 --- a/Model/ResourceModel/Order/Grid/Collection.php +++ b/Model/ResourceModel/Order/Grid/Collection.php @@ -1,20 +1,36 @@ getSelect()->joinLeft(['t' => $subquery], 'main_table.entity_id = t.entity_id', array('quote_id')); + $this->getSelect()->joinLeft(['t' => $subQuery], 'main_table.entity_id = t.entity_id', array('quote_id')); return $this; } From 2da5d4afe5c5d0552dc2cb146db1732f987ee0a6 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 31 Jan 2020 10:19:17 +0100 Subject: [PATCH 38/44] [change] (MAGE2-262) Update CHANGELOG.md. --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fce0b13ec88..11b239a71bf 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ This project does not follow a versioning standard. Versions are crafted after t ## X.X.X ### Added -- Refund to iDeal payment method. +- Refund to iDeal payment method. +- Add column `heidelpay TxnId` to `sales_order_grid` to enable better mapping between magento order and hIP transactions. ### Fixed - Made sure the reserved value matches the gross value of the order to avoid problems finalizing. From cb487c2f80eed80e2b9c746091bbb86cbdd5c079 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Mon, 10 Feb 2020 13:30:23 +0100 Subject: [PATCH 39/44] (MAGE2-108) [add] Update changelog. --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11b239a71bf..3c558e3fc37 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,9 @@ This project does not follow a versioning standard. Versions are crafted after t ## X.X.X ### Added -- Refund to iDeal payment method. -- Add column `heidelpay TxnId` to `sales_order_grid` to enable better mapping between magento order and hIP transactions. +- 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 doesnt exist already for an successful reservation or payment. ### Fixed - Made sure the reserved value matches the gross value of the order to avoid problems finalizing. From a20f25f211b60c79c2d2b239b645c29f15f9cdd2 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Fri, 14 Feb 2020 09:46:05 +0100 Subject: [PATCH 40/44] [change] (MAGE2-262) Fix problem with invoice and shipping table. --- etc/adminhtml/di.xml | 13 ------------- etc/di.xml | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/etc/adminhtml/di.xml b/etc/adminhtml/di.xml index e3732d3b188..f7af3bfc7fb 100644 --- a/etc/adminhtml/di.xml +++ b/etc/adminhtml/di.xml @@ -3,17 +3,4 @@ - - - - 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/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 From da3a1c89c4df16d4de94e8511998c9bcfbfb342d Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Fri, 14 Feb 2020 12:57:32 +0100 Subject: [PATCH 41/44] (MAGE2-269) [change] adjust total calculation of basket. --- Helper/BasketHelper.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Helper/BasketHelper.php b/Helper/BasketHelper.php index eb959b5d064..34006160813 100755 --- a/Helper/BasketHelper.php +++ b/Helper/BasketHelper.php @@ -71,8 +71,13 @@ 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->normalizeValue($quote->getGrandTotal())) + ->setAmountTotalNet($amountTotalNet) + ->setAmountTotalVat($amountGrandTotal - $amountTotalNet) ->setBasketReferenceId($basketReferenceId); /** @var Item $item */ From 63ae6b4d31af5b1597d1c1e6dacdb9a4eb3af368 Mon Sep 17 00:00:00 2001 From: sixer1182 Date: Tue, 18 Feb 2020 12:57:50 +0100 Subject: [PATCH 42/44] [change] (MAGE2-276) Remove PHP 5.6 and add PHP 7.3 support. --- CHANGELOG.md | 4 ++++ README.md | 4 ++-- composer.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c558e3fc37..2e9daf8817e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,14 @@ This project does not follow a versioning standard. Versions are crafted after t - 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 doesnt 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/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/composer.json b/composer.json index bdbe67c6b6a..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", From d57be585b1e7548b14031cd23cbae2ab4fdac683 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Tue, 18 Feb 2020 16:50:45 +0100 Subject: [PATCH 43/44] (MAGE2-108) [change] push - dont create order fo pending transactions. --- Controller/Index/Push.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index f6ffd41c1bc..9702c8ead5b 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -183,8 +183,11 @@ public function execute() ); // Only process transactions that might potentially create new order, this includes receipts. - if ($pushResponse->isSuccess() && $this->_paymentHelper->isNewOrderType($paymentType)) { - + if ( + $pushResponse->isSuccess() && + !$pushResponse->isPending() && + $this->_paymentHelper->isNewOrderType($paymentType) + ) { $transactionId = $pushResponse->getIdentification()->getTransactionId(); $order = $this->orderHelper->fetchOrder($transactionId); $quote = $this->quoteRepository->get($transactionId); From 5ef567a3ade1c32db2592ef5554506097514c5a6 Mon Sep 17 00:00:00 2001 From: "David.Owusu" Date: Fri, 21 Feb 2020 13:45:42 +0100 Subject: [PATCH 44/44] (MAGE2-273) [change] Set module version 20.2.24. --- CHANGELOG.md | 4 ++-- Helper/Order.php | 2 +- Helper/Payment.php | 2 +- Helper/Response.php | 2 +- etc/module.xml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e9daf8817e..f770ec37a8e 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,11 @@ 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 -## X.X.X +## 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 doesnt exist already for an successful reservation or payment. +- 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 diff --git a/Helper/Order.php b/Helper/Order.php index dc9ab3f2c78..a3966665f3d 100644 --- a/Helper/Order.php +++ b/Helper/Order.php @@ -15,7 +15,7 @@ /** * Heidelpay order helper * - * The payment helper is a collection of function to prepare an send + * The order helper is a collection of functions to handle common order tasks * * @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/Helper/Payment.php b/Helper/Payment.php index 9b5919eb8c2..d2c11e37c66 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -31,7 +31,7 @@ /** * 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. 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/etc/module.xml b/etc/module.xml index 44560b6ef0b..eed23472e8b 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,5 +1,5 @@ - +