diff --git a/.gitignore b/.gitignore index 3caf4b3c474..5465c3d8df8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /composer.phar /composer.lock /auth.json -/.idea \ No newline at end of file +/.idea +/generated/ diff --git a/Api/Data/PaymentInformationInterface.php b/Api/Data/PaymentInformationInterface.php index 19acf7bbe3b..a21881d9930 100755 --- a/Api/Data/PaymentInformationInterface.php +++ b/Api/Data/PaymentInformationInterface.php @@ -1,7 +1,4 @@ + * + * @package heidelpay/magento2 + */ +namespace Heidelpay\Gateway\Api\Data; + +interface TransactionInterface +{ + /** + * @return string + */ + public function getPaymentMethod(); + + /** + * @param string $paymentMethod + * @return $this + */ + public function setPaymentMethod($paymentMethod); + + /** + * @return string + */ + public function getPaymentType(); + + /** + * @param string $paymentType + * @return $this + */ + public function setPaymentType($paymentType); + + /** + * @return string + */ + public function getTransactionId(); + + /** + * @param string $transactionId + * @return $this + */ + public function setTransactionId($transactionId); + + /** + * @return string + */ + public function getUniqueId(); + + /** + * @param string $uniqueId + * @return $this + */ + public function setUniqueId($uniqueId); + + /** + * @return string + */ + public function getShortId(); + + /** + * @param string $shortId + * @return $this + */ + public function setShortId($shortId); + + /** + * @return string + */ + public function getResult(); + + /** + * @param string $result + * @return $this + */ + public function setResult($result); + + /** + * @return integer + */ + public function getStatusCode(); + + /** + * @param integer $statusCode + * @return $this + */ + public function setStatusCode($statusCode); + + /** + * @return string + */ + public function getReturnMessage(); + + /** + * @param string $returnMessage + * @return $this + */ + public function setReturnMessage($returnMessage); + + /** + * @return string + */ + public function getReturnCode(); + + /** + * @param string $returnCode + * @return $this + */ + public function setReturnCode($returnCode); + + /** + * @return array + */ + public function getJsonResponse(); + + /** + * @param string $jsonResponse + * @return $this + */ + public function setJsonResponse($jsonResponse); + + /** + * @return string + */ + public function getDatetime(); + + /** + * @return string + */ + public function getSource(); + + /** + * @param string $source + * @return $this + */ + public function setSource($source); +} diff --git a/Api/Data/TransactionSearchResultInterface.php b/Api/Data/TransactionSearchResultInterface.php new file mode 100644 index 00000000000..d157f109ca7 --- /dev/null +++ b/Api/Data/TransactionSearchResultInterface.php @@ -0,0 +1,29 @@ + + * + * @package heidelpay/magento2 + */ +namespace Heidelpay\Gateway\Api\Data; + +use Magento\Framework\Api\SearchResultsInterface; + +interface TransactionSearchResultInterface extends SearchResultsInterface +{ + /** + * @return \Heidelpay\Gateway\Api\Data\TransactionInterface[] + */ + public function getItems(); + + /** + * @param \Heidelpay\Gateway\Api\Data\TransactionInterface[] $items + * @return void + */ + public function setItems(array $items); +} diff --git a/Api/Payment.php b/Api/Payment.php index 325d54c4404..fc88345f8a7 100755 --- a/Api/Payment.php +++ b/Api/Payment.php @@ -1,13 +1,5 @@ quoteRepository = $quoteRepository; $this->quoteIdMaskFactory = $quoteIdMaskFactory; @@ -77,6 +87,8 @@ public function __construct( /** * @inheritdoc + + * @throws NoSuchEntityException */ public function getAdditionalPaymentInformation($quoteId, $paymentMethod) { @@ -88,18 +100,18 @@ public function getAdditionalPaymentInformation($quoteId, $paymentMethod) // get the recognition configuration for the given payment method and store id. $allowRecognition = $this->scopeConfig->getValue( 'payment/' . $paymentMethod . '/recognition', - \Magento\Store\Model\ScopeInterface::SCOPE_STORE, + ScopeInterface::SCOPE_STORE, $quote->getStoreId() ); // if recognition is set to 'never', we don't return any data. - if ($allowRecognition == Recognition::RECOGNITION_NEVER) { + if ($allowRecognition === Recognition::RECOGNITION_NEVER) { return json_encode(null); } // get the customer payment information by given data from the request. $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + /** @var PaymentInformation $paymentInfo */ $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $quote->getCustomerEmail(), @@ -115,8 +127,8 @@ public function getAdditionalPaymentInformation($quoteId, $paymentMethod) // we only return additional payment data, if the shipping data is the same (to prevent fraud) if ($allowRecognition === Recognition::RECOGNITION_SAME_SHIPPING_ADDRESS) { - // if the shipping hashes are the same, we can safely return the addtional payment data. - if ($this->createShippingHash($quote->getShippingAddress()) == $paymentInfo->getShippingHash()) { + // if the shipping hashes are the same, we can safely return the additional payment data. + if ($this->createShippingHash($quote->getShippingAddress()) === $paymentInfo->getShippingHash()) { $result = $paymentInfo->getAdditionalData(); } } @@ -133,35 +145,44 @@ public function getAdditionalPaymentInformation($quoteId, $paymentMethod) /** * @inheritdoc + * @throws NoSuchEntityException*@throws Exception + * @throws Exception */ public function saveAdditionalPaymentInfo($cartId, $method, $additionalData) { + $returnValue = true; + // get the quote information by cart id $quote = $this->quoteRepository->get($cartId); - // if the quote is empty, there is no relation that - // we can work with... so we return false. + // if the quote is empty, there is no relation that we can work with... so we return false. if ($quote->isEmpty()) { - return json_encode(false); + $this->logger->warning('Heidelpay: Could not find quote with id ' . $cartId . '.'); + $returnValue = false; } // save the information with the given quote and additional data. // if there is nothing stored, we'll return false... - if (!$this->savePaymentInformation($quote, $method, $quote->getCustomerEmail(), $additionalData)) { - return json_encode(false); + if ($returnValue && !$this->savePaymentInformation($quote, $method, $quote->getCustomerEmail(), $additionalData)) { + $this->logger->warning('Heidelpay: Could not save payment information for quote id ' . $cartId . '.'); + $returnValue = false; } // ... if it was successful, we return true. - return json_encode(true); + return json_encode($returnValue); } /** * @inheritdoc + * + * @throws Exception */ public function saveGuestAdditionalPaymentInfo($cartId, $method, $additionalData) { + $returnValue = true; + // get the real quote id by guest cart id (masked random string serves as guest cart id) - /** @var \Magento\Quote\Model\QuoteIdMask $quoteIdMask */ + /** @var QuoteIdMask $quoteIdMask */ $quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id'); $quoteId = $quoteIdMask->getQuoteId(); @@ -171,27 +192,27 @@ public function saveGuestAdditionalPaymentInfo($cartId, $method, $additionalData // if the quote is empty, there is no relation that // we can work with... so we return false. if ($quote->isEmpty()) { - return json_encode(false); + $returnValue = false; } // save the information with the given quote and additional data. // if there is nothing stored, we'll return false... // - since guest email is stored in the billing information, we have to pull it from there. - if (!$this->savePaymentInformation($quote, $method, $quote->getBillingAddress()->getEmail(), $additionalData)) { - return json_encode(false); + if ($returnValue && !$this->savePaymentInformation($quote, $method, $quote->getBillingAddress()->getEmail(), $additionalData)) { + $returnValue = false; } // ... if it was successful, we return true. - return json_encode(true); + return json_encode($returnValue); } /** * Create a shipping hash. * - * @param \Magento\Quote\Api\Data\AddressInterface $address + * @param AddressInterface $address * @return string */ - private function createShippingHash(\Magento\Quote\Api\Data\AddressInterface $address) + private function createShippingHash(AddressInterface $address) { return $this->encryptor->hash( implode('', [ @@ -216,7 +237,7 @@ private function createShippingHash(\Magento\Quote\Api\Data\AddressInterface $ad * the Billing address. * * @param string $method - * @param \Magento\Quote\Model\Quote $quote + * @param Quote $quote * @return array|null */ private function getAdditionalDataForPaymentMethod($method, $quote) @@ -251,19 +272,22 @@ private function getAdditionalDataForPaymentMethod($method, $quote) * If a data set with the given information exists, it will just * be updated. Else, a new data set will be created. * - * @param \Magento\Quote\Model\Quote $quote + * @param Quote $quote * @param string $method * @param string $email * @param array $additionalData * @param string $paymentRef - * @return \Heidelpay\Gateway\Api\Data\PaymentInformationInterface + * + * @return PaymentInformationInterface + * + * @throws Exception */ private function savePaymentInformation($quote, $method, $email, $additionalData, $paymentRef = null) { - // make some additional data changes, if neccessary - array_walk($additionalData, function (&$value, $key) { - // if somehow the country code in the IBAN is lowercase, convert it to uppercase. - if ($key == 'hgw_iban') { + // make some additional data changes, if necessary + array_walk($additionalData, static function (&$value, $key) { + // make sure the country code in the IBAN is uppercase. + if ($key === 'hgw_iban') { $value = strtoupper($value); } }); @@ -272,7 +296,7 @@ private function savePaymentInformation($quote, $method, $email, $additionalData $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); // load payment information by the customer's quote. - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + /** @var PaymentInformationInterface $paymentInfo */ $paymentInformation = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $email, diff --git a/Api/PaymentInterface.php b/Api/PaymentInterface.php index 0c9cb60f130..7e2686e29bc 100755 --- a/Api/PaymentInterface.php +++ b/Api/PaymentInterface.php @@ -6,7 +6,7 @@ * API implementation for the heidelpay Payment functionality * * To work with additional data, the module stored customer payment information - * in a seperate data set to avoid mixing up Magento 2 and heidelpay data. + * in a separate data set to avoid mixing up Magento 2 and heidelpay data. * * @license Use of this software requires acceptance of the License Agreement. See LICENSE file. * @copyright Copyright © 2016-present heidelpay GmbH. All rights reserved. diff --git a/Api/TransactionRepositoryInterface.php b/Api/TransactionRepositoryInterface.php new file mode 100644 index 00000000000..84a33cbc5c2 --- /dev/null +++ b/Api/TransactionRepositoryInterface.php @@ -0,0 +1,72 @@ + + * + * @package heidelpay/magento2 + */ +namespace Heidelpay\Gateway\Api; + +use Heidelpay\Gateway\Model\Transaction; +use Magento\Framework\Exception\CouldNotDeleteException; +use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Api\SearchCriteriaInterface; + +interface TransactionRepositoryInterface +{ + /** + * Retrieves the transaction with the given id. + * + * @param int $id + * + * @return \Heidelpay\Gateway\Api\Data\TransactionInterface + * + * @throws NoSuchEntityException + */ + public function getById($id); + + /** + * Saves the given transaction. + * + * @param Transaction $transaction + * + * @return \Heidelpay\Gateway\Api\Data\TransactionInterface + * + * @throws \Magento\Framework\Exception\AlreadyExistsException + */ + public function save(Transaction $transaction); + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + /** + * Lists transactions that match specified search criteria. + * + * This call returns an array of objects, but detailed information about each object’s attributes might not be + * included. + * + * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria The search criteria. + * + * @return \Heidelpay\Gateway\Api\Data\TransactionSearchResultInterface + */ + public function getList(SearchCriteriaInterface $searchCriteria); + + /** + * Deletes the given transaction. + * + * @param Transaction $transaction + * + * @return \Heidelpay\Gateway\Api\Data\TransactionSearchResultInterface + * + * @throws CouldNotDeleteException + */ + public function delete(Transaction $transaction); + + + +} \ No newline at end of file diff --git a/Block/Hgw.php b/Block/Hgw.php index 5ce879a1eb0..9b512317ae5 100755 --- a/Block/Hgw.php +++ b/Block/Hgw.php @@ -1,10 +1,11 @@ _hgwUrl = $url; - } - - protected function getHgwUrl() { - return $this->_hgwUrl; - } - */ } diff --git a/Block/HgwInstallmentPlan.php b/Block/HgwInstallmentPlan.php new file mode 100644 index 00000000000..08849bae9df --- /dev/null +++ b/Block/HgwInstallmentPlan.php @@ -0,0 +1,25 @@ +orderResository = $orderRepository; $this->logger = $logger; @@ -88,11 +89,11 @@ public function beforeExecute() } // get the order to receive heidelpay payment method instance - /** @var \Magento\Sales\Model\Order $order */ + /** @var Order $order */ $order = $this->orderResository->get($this->getRequest()->getParam('order_id')); // get the payment method instance and the heidelpay method instance - /** @var \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod $method */ + /** @var HeidelpayAbstractPaymentMethod $method */ $method = $order->getPayment()->getMethodInstance(); // only fire the shipping when a heidelpay payment method is used. @@ -101,7 +102,7 @@ public function beforeExecute() $heidelpayMethod = $method->getHeidelpayPaymentMethodInstance(); // if the payment method uses the Finalize Transaction type, we'll send a FIN request to the payment api. - if (in_array(FinalizeTransactionType::class, class_uses($heidelpayMethod))) { + if (in_array(FinalizeTransactionType::class, class_uses($heidelpayMethod), true)) { /** @var HgwMainConfigInterface $mainConfig */ $mainConfig = $method->getMainConfig(); @@ -125,7 +126,7 @@ public function beforeExecute() ); // send the finalize request - /** @var \Heidelpay\PhpPaymentApi\Response $response */ + /** @var Response $response */ $heidelpayMethod->finalize($order->getPayment()->getLastTransId()); // if the response isn't successful, redirect back to the order view. @@ -145,8 +146,7 @@ public function beforeExecute() // set order state to "pending payment" $state = Order::STATE_PENDING_PAYMENT; - $order->setState($state) - ->addStatusHistoryComment('heidelpay - Finalizing Order', true); + $order->setState($state)->addStatusHistoryComment('heidelpay - Finalizing Order', true); $this->orderResository->save($order); diff --git a/Controller/HgwAbstract.php b/Controller/HgwAbstract.php index 4795434dee9..59d56e1262d 100755 --- a/Controller/HgwAbstract.php +++ b/Controller/HgwAbstract.php @@ -3,6 +3,7 @@ namespace Heidelpay\Gateway\Controller; use Heidelpay\Gateway\Helper\Payment as HeidelpayHelper; +use Magento\Quote\Model\QuoteManagement; use Magento\Sales\Model\Order\Email\Sender\OrderSender; use Magento\Sales\Model\Order\Email\Sender\OrderCommentSender; use Magento\Sales\Model\Order\Email\Sender\InvoiceSender; @@ -45,9 +46,7 @@ abstract class HgwAbstract extends \Magento\Framework\App\Action\Action protected $_quoteObject; - /** - * @var \Magento\Quote\Model\QuoteManagement - */ + /** @var QuoteManagement */ protected $_cartManagement; /** diff --git a/Controller/Index/Index.php b/Controller/Index/Index.php index afbb2314469..8bf0171689a 100755 --- a/Controller/Index/Index.php +++ b/Controller/Index/Index.php @@ -2,13 +2,31 @@ namespace Heidelpay\Gateway\Controller\Index; +use Exception; +use Heidelpay\Gateway\Controller\HgwAbstract; +use Heidelpay\Gateway\Block\Hgw; use Heidelpay\Gateway\Helper\Payment as HeidelpayHelper; +use Heidelpay\Gateway\PaymentMethods\Exceptions\CheckoutValidationException; use Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod; +use Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException; +use Heidelpay\PhpPaymentApi\Response as HeidelpayResponse; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Model\Session; +use Magento\Customer\Model\Url; use Magento\Framework\App\Action\Context; +use Magento\Framework\Encryption\Encryptor; use Magento\Framework\Escaper; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Url\Helper\Data; +use Magento\Framework\View\Result\PageFactory; +use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Api\CartRepositoryInterface; 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\OrderFactory; +use Psr\Log\LoggerInterface; +use Magento\Framework\Controller\ResultFactory; /** * Customer redirect to heidelpay payment or used to display the payment frontend to the customer @@ -20,27 +38,27 @@ * * @package heidelpay\magento2\controllers */ -class Index extends \Heidelpay\Gateway\Controller\HgwAbstract +class Index extends HgwAbstract { /** @var Escaper */ private $escaper; public function __construct( 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, + Session $customerSession, + CheckoutSession $checkoutSession, + OrderFactory $orderFactory, + Data $urlHelper, + LoggerInterface $logger, + CartManagementInterface $cartManagement, + CartRepositoryInterface $quoteObject, + PageFactory $resultPageFactory, HeidelpayHelper $paymentHelper, OrderSender $orderSender, InvoiceSender $invoiceSender, OrderCommentSender $orderCommentSender, - \Magento\Framework\Encryption\Encryptor $encryptor, - \Magento\Customer\Model\Url $customerUrl, + Encryptor $encryptor, + Url $customerUrl, Escaper $escaper ) { parent::__construct( @@ -66,18 +84,18 @@ public function __construct( /** * {@inheritDoc} - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Exception + * @throws InvalidBasketitemPositionException + * @throws LocalizedException + * @throws Exception */ public function execute() { $session = $this->getCheckout(); $quote = $session->getQuote(); + $errorMessage = __('An unexpected error occurred. Please contact us to get further information.'); if (!$quote->getId()) { - $message = __('An unexpected error occurred. Please contact us to get further information.'); - $this->messageManager->addErrorMessage($this->escaper->escapeHtml($message)); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($errorMessage)); return $this->_redirect('checkout/cart/', ['_secure' => true]); } @@ -86,8 +104,8 @@ public function execute() $payment = $quote->getPayment()->getMethodInstance(); // get the response object from the initial request. - /** @var \Heidelpay\PhpPaymentApi\Response $response */ - $response = $payment->getHeidelpayUrl($quote); + /** @var HeidelpayResponse $response */ + $response = $payment->getHeidelpayUrl($quote, $this->getRequest()->getParams()); $this->_logger->debug('Heidelpay init response : ' . print_r($response, 1)); @@ -99,19 +117,19 @@ public function execute() $resultPage = $this->_resultPageFactory->create(); $resultPage->getConfig()->getTitle()->prepend(__('Please confirm your payment:')); - $resultPage->getLayout()->getBlock('heidelpay_gateway')->setHgwUrl( - $response->getPaymentFormUrl() - ); - $resultPage->getLayout()->getBlock('heidelpay_gateway')->setHgwCode($payment->getCode()); + + /** @var Hgw $hgwBlock */ + $hgwBlock = $resultPage->getLayout()->getBlock('heidelpay_gateway'); + $hgwBlock->setHgwUrl($response->getPaymentFormUrl()); return $resultPage; } - $this->_logger->error('Heidelpay init error : ' . $response->getError()['message']); - - // get an error message for the given error code, and add it to the message container. - $message = $this->_paymentHelper->handleError($response->getError()['code']); - $this->messageManager->addErrorMessage($this->escaper->escapeHtml($message)); + // get an error errorMessage for the given error code, and add it to the errorMessage container. + $code = $response->getError()['code']; + $this->_logger->error('Heidelpay init error (' . $code . '): ' . $response->getError()['message']); + $errorMessage = $this->_paymentHelper->handleError($code); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($errorMessage)); return $this->_redirect('checkout/cart/', ['_secure' => true]); } diff --git a/Controller/Index/InstallmentPlan.php b/Controller/Index/InstallmentPlan.php new file mode 100644 index 00000000000..6cd899c8cda --- /dev/null +++ b/Controller/Index/InstallmentPlan.php @@ -0,0 +1,215 @@ +escaper = $escaper; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->transactionRepository = $transactionRepository; + $this->sortOrderBuilder = $sortOrderBuilder; + } + + /** + * {@inheritDoc} + * @throws Exception + */ + public function execute() + { + $session = $this->getCheckout(); + $quote = $session->getQuote(); + + if (!$quote->getId()) { + $message = __('An unexpected error occurred. Please contact us to get further information.'); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($message)); + + return $this->_redirect('checkout/cart/', ['_secure' => true]); + } + + /** @var HeidelpayAbstractPaymentMethod $methodInstance */ + $methodInstance = $quote->getPayment()->getMethodInstance(); + if (!$methodInstance instanceof HeidelpayAbstractPaymentMethod) { + $message = __('An unexpected error occurred. Please contact us to get further information.'); + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($message)); + + return $this->_redirect('checkout/cart/', ['_secure' => true]); + } + + $installmentPlanUrl = null; + $initReferenceId = null; + + // fetch the latest installment plan for the selected HP-method + $paymentMethodInstance = $methodInstance->getHeidelpayPaymentMethodInstance(); + if ($paymentMethodInstance->getPaymentCode() === PaymentMethod::HIRE_PURCHASE) { + /** @var TransactionSearchResultInterface $results */ + $results = $this->getInitializationsForQuote($quote); + foreach ($results->getItems() as $item) { + /** @var TransactionInterface $item */ + $heidelpayResponse = new Response($item->getJsonResponse()); + if ($heidelpayResponse->getAccount()->getBrand() === $paymentMethodInstance->getBrand()) { + $contractUrlField = $paymentMethodInstance->getBrand() . '_PDF_URL'; + $installmentPlanUrl = $heidelpayResponse->getCriterion()->get($contractUrlField); + $initReferenceId = $heidelpayResponse->getPaymentReferenceId(); + break; + } + } + } + + if (!empty($installmentPlanUrl) && !empty($initReferenceId)) { + $resultPage = $this->_resultPageFactory->create(); + $resultPage->getConfig()->getTitle()->prepend(__('Please confirm your payment:')); + + /** @var HgwInstallmentPlan $hgwInstallmentPlan */ + $hgwInstallmentPlan = $resultPage->getLayout()->getBlock('InstallmentPlan'); + $hgwInstallmentPlan->setInstallmentPlanUrl($installmentPlanUrl); + $hgwInstallmentPlan->setInitReferenceId($initReferenceId); + + return $resultPage; + } + + $this->_logger->error('Heidelpay InstallmentPlan Error: Could not find installment plan URL.'); + + // get an error message for the given error code and add it to the message container. + $message = 'Heidelpay InstallmentPlan Error: Could not find installment plan URL.'; + $this->messageManager->addErrorMessage($this->escaper->escapeHtml($message)); + + return $this->_redirect('checkout/cart/', ['_secure' => true]); + } + + /** + * Returns all Initialization transactions for HirePurchase payment methods of the given quote. + * + * @param Quote $quote + * @param string $direction + * @return TransactionSearchResultInterface + */ + private function getInitializationsForQuote(Quote $quote, $direction = SortOrder::SORT_DESC) + { + $sortOrder = $this->sortOrderBuilder->setField(Transaction::ID)->setDirection($direction)->create(); + $criteria = $this->searchCriteriaBuilder + ->addFilter(Transaction::QUOTE_ID, $quote->getId()) + ->addFilter(Transaction::PAYMENT_TYPE, TransactionType::INITIALIZE) + ->addFilter(Transaction::PAYMENT_METHOD, PaymentMethod::HIRE_PURCHASE) + ->addFilter(Transaction::RESULT, ProcessingResult::ACK) + ->addSortOrder($sortOrder) + ->create(); + + /** @var TransactionSearchResultInterface $results */ + $results = $this->transactionRepository->getList($criteria); + return $results; + } +} diff --git a/Controller/Index/Push.php b/Controller/Index/Push.php index 875ac3d0a9c..3869c30f014 100755 --- a/Controller/Index/Push.php +++ b/Controller/Index/Push.php @@ -11,6 +11,7 @@ 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 @@ -132,78 +133,87 @@ public function execute() ); } - $this->_logger->debug('Push Response: ' . print_r($this->heidelpayPush->getResponse(), true)); + $pushResponse = $this->heidelpayPush->getResponse(); + $this->_logger->debug('Push Response: ' . print_r($pushResponse, true)); list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( - $this->heidelpayPush->getResponse()->getPayment()->getCode() + $pushResponse->getPayment()->getCode() ); // in case of receipts, we process the push message for receipts. - if ($this->_paymentHelper->isReceiptAble($paymentMethod, $paymentType)) { - // only when the Response is ACK. - if ($this->heidelpayPush->getResponse()->isSuccess()) { - // load the referenced order to receive the order information. - $criteria = $this->searchCriteriaBuilder - ->addFilter( - 'quote_id', - $this->heidelpayPush->getResponse()->getIdentification()->getTransactionId() - )->create(); - - /** @var Collection $orderList */ - $orderList = $this->orderRepository->getList($criteria); - - /** @var Order $order */ - $order = $orderList->getFirstItem(); - - $paidAmount = (float)$this->heidelpayPush->getResponse()->getPresentation()->getAmount(); - $dueLeft = $order->getTotalDue() - $paidAmount; - - $state = Order::STATE_PROCESSING; - $comment = 'heidelpay - Purchase Complete'; - - // if payment is not complete - if ($dueLeft > 0.00) { - $state = Order::STATE_PAYMENT_REVIEW; - $comment = 'heidelpay - Partly Paid (' - . $this->_paymentHelper->format( - $this->heidelpayPush->getResponse()->getPresentation()->getAmount() - ) - . ' ' . $this->heidelpayPush->getResponse()->getPresentation()->getCurrency() . ')'; - } + 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; + } - // 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(); - } - } + $paidAmount = (float)$pushResponse->getPresentation()->getAmount(); + $dueLeft = $order->getTotalDue() - $paidAmount; - $order->setTotalPaid($order->getTotalPaid() + $paidAmount) - ->setBaseTotalPaid($order->getBaseTotalPaid() + $paidAmount) - ->setState($state) - ->addStatusHistoryComment($comment, $state); - - // create a heidelpay Transaction. - $order->getPayment()->getMethodInstance()->saveHeidelpayTransaction( - $this->heidelpayPush->getResponse(), - $paymentMethod, - $paymentType, - 'PUSH', - [] - ); - - // create a child transaction. - $order->getPayment()->setTransactionId($this->heidelpayPush->getResponse()->getPaymentReferenceId()); - $order->getPayment()->setParentTransactionId( - $this->heidelpayPush->getResponse()->getIdentification()->getReferenceId() - ); - $order->getPayment()->setIsTransactionClosed(true); - - $order->getPayment()->addTransaction(Transaction::TYPE_CAPTURE, null, true); - - $order->save(); + $state = Order::STATE_PROCESSING; + $comment = 'heidelpay - Purchase Complete'; + + // 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); + + // create a heidelpay Transaction. + $methodInstance->saveHeidelpayTransaction( + $pushResponse, + $paymentMethod, + $paymentType, + 'PUSH', + [] + ); + + // create a child transaction. + $payment->setTransactionId($transactionID) + ->setParentTransactionId($pushResponse->getIdentification()->getReferenceId()) + ->setIsTransactionClosed(true) + ->addTransaction(Transaction::TYPE_CAPTURE, null, true); + + $this->orderRepository->save($order); } } } diff --git a/Controller/Index/Redirect.php b/Controller/Index/Redirect.php index fe78fa149ca..c08c4227145 100755 --- a/Controller/Index/Redirect.php +++ b/Controller/Index/Redirect.php @@ -109,8 +109,7 @@ public function execute() $quoteId = $session->getQuoteId(); if (empty($quoteId)) { - $this->_logger->warning('Heidelpay - Redirect: Called with empty quoteId'); - + $this->_logger->error('Heidelpay - Redirect: Called with empty quoteId'); return $this->_redirect('checkout/cart/', ['_secure' => true]); } @@ -144,9 +143,6 @@ public function execute() // set Parameters for success page if ($this->heidelpayResponse->isSuccess()) { - // lock the quote - $session->getQuote()->setIsActive(false)->save(); - /** @var Order $order */ $order = null; try { @@ -156,7 +152,6 @@ public function execute() 'Heidelpay - Redirect: Cannot receive order.' . $e->getMessage() ); } - $session->clearHelperData(); // set QuoteIds @@ -173,42 +168,11 @@ public function execute() ->additionalPaymentInformation($data); $this->_checkoutSession->setHeidelpayInfo($additionalPaymentInformation); - $this->_logger->debug('Heidelpay - Redirect: Redirecting customer to success page.'); - // set response - $response = $this->_redirect('checkout/onepage/success', ['_secure' => true]); - - try { - // send order confirmation to the customer - if ($order && $order->getId()) { - $this->_orderSender->send($order); - } - } catch (\Exception $e) { - $this->_logger->error( - 'Heidelpay - Redirect: Cannot send order confirmation E-Mail. ' . $e->getMessage() - ); - } - - // Check send Invoice Mail enabled - if ($this->salesHelper->canSendNewInvoiceEmail($session->getQuote()->getStore()->getId())) { - // send invoice(s) to the customer - if (!$order->canInvoice()) { - $invoices = $order->getInvoiceCollection(); - - foreach ($invoices as $invoice) { - $this->_invoiceSender->send($invoice); - } - } - } - - // return response - return $response; + return $this->_redirect('checkout/onepage/success', ['_secure' => true]); } - // unlock the quote in case of error - $session->getQuote()->setIsActive(true)->save(); - $this->_logger->error( 'Heidelpay - Redirect: Redirect with error to cart: ' . $this->heidelpayResponse->getError()['message'] ); diff --git a/Controller/Index/Response.php b/Controller/Index/Response.php index 18ba2a8c18c..568dddc49d8 100755 --- a/Controller/Index/Response.php +++ b/Controller/Index/Response.php @@ -2,18 +2,36 @@ namespace Heidelpay\Gateway\Controller\Index; +use Exception; +use Heidelpay\Gateway\Controller\HgwAbstract; use Heidelpay\Gateway\Helper\Payment as HeidelpayHelper; -use Heidelpay\Gateway\Model\ResourceModel\PaymentInformation\CollectionFactory as PaymentInformationCollectionFactory; +use Heidelpay\Gateway\Model\PaymentInformation; use Heidelpay\Gateway\Model\ResourceModel\PaymentInformation\CollectionFactory; -use Heidelpay\Gateway\Model\TransactionFactory; +use Heidelpay\Gateway\Model\ResourceModel\PaymentInformation\CollectionFactory as PaymentInformationCollectionFactory; +use Magento\Framework\Controller\Result\RawFactory; +use Heidelpay\PhpPaymentApi\Constants\PaymentMethod; use Heidelpay\PhpPaymentApi\Exceptions\HashVerificationException; use Heidelpay\PhpPaymentApi\Response as HeidelpayResponse; +use Heidelpay\PhpPaymentApi\Constants\TransactionType; +use Magento\Checkout\Model\Session as CheckoutSession; +use Magento\Customer\Model\Session; +use Magento\Customer\Model\Url; +use Magento\Framework\App\Action\Context; +use Magento\Framework\Encryption\Encryptor; +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\Quote; use Magento\Quote\Model\QuoteRepository; +use Magento\Sales\Helper\Data as SalesHelper; +use Magento\Sales\Model\OrderFactory; use Magento\Sales\Model\Order; +use Magento\Sales\Model\OrderRepository; 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 Psr\Log\LoggerInterface; /** * Notification handler for the payment response @@ -35,7 +53,7 @@ * * @package heidelpay\magento2\controllers */ -class Response extends \Heidelpay\Gateway\Controller\HgwAbstract +class Response extends HgwAbstract { /** @var QuoteRepository */ private $quoteRepository; @@ -43,55 +61,60 @@ class Response extends \Heidelpay\Gateway\Controller\HgwAbstract /** @var HeidelpayResponse The heidelpay response object */ private $heidelpayResponse; - /** @var TransactionFactory */ - private $transactionFactory; - /** @var CollectionFactory */ private $paymentInformationCollectionFactory; + /** @var SalesHelper */ + private $salesHelper; + + /** @var OrderRepository */ + private $orderRepository; + /** * heidelpay Response constructor. * - * @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 Session $customerSession + * @param CheckoutSession $checkoutSession + * @param OrderFactory $orderFactory + * @param Data $urlHelper + * @param LoggerInterface $logger + * @param CartManagementInterface $cartManagement + * @param CartRepositoryInterface $quoteObject + * @param PageFactory $resultPageFactory * @param HeidelpayHelper $paymentHelper * @param OrderSender $orderSender * @param InvoiceSender $invoiceSender * @param OrderCommentSender $orderCommentSender - * @param \Magento\Framework\Encryption\Encryptor $encryptor - * @param \Magento\Customer\Model\Url $customerUrl - * @param \Magento\Framework\Controller\Result\RawFactory $rawResultFactory + * @param Encryptor $encryptor + * @param Url $customerUrl + * @param RawFactory $rawResultFactory * @param QuoteRepository $quoteRepository - * @param PaymentInformationCollectionFactory $paymentInformationCollectionFactory, - * @param TransactionFactory $transactionFactory + * @param PaymentInformationCollectionFactory $paymentInformationCollectionFactory , + * @param SalesHelper $salesHelper + * @param OrderRepository $orderRepository */ 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, + Session $customerSession, + CheckoutSession $checkoutSession, + OrderFactory $orderFactory, + Data $urlHelper, + LoggerInterface $logger, + CartManagementInterface $cartManagement, + CartRepositoryInterface $quoteObject, + PageFactory $resultPageFactory, HeidelpayHelper $paymentHelper, OrderSender $orderSender, InvoiceSender $invoiceSender, OrderCommentSender $orderCommentSender, - \Magento\Framework\Encryption\Encryptor $encryptor, - \Magento\Customer\Model\Url $customerUrl, - \Magento\Framework\Controller\Result\RawFactory $rawResultFactory, + Encryptor $encryptor, + Url $customerUrl, + RawFactory $rawResultFactory, QuoteRepository $quoteRepository, PaymentInformationCollectionFactory $paymentInformationCollectionFactory, - TransactionFactory $transactionFactory + SalesHelper $salesHelper, + OrderRepository $orderRepository ) { parent::__construct( $context, @@ -114,21 +137,16 @@ public function __construct( $this->resultFactory = $rawResultFactory; $this->quoteRepository = $quoteRepository; $this->paymentInformationCollectionFactory = $paymentInformationCollectionFactory; - $this->transactionFactory = $transactionFactory; + $this->salesHelper = $salesHelper; + $this->orderRepository = $orderRepository; } /** * @inheritdoc - * @throws \Exception + * @throws Exception */ public function execute() { - // initialize the Raw Response object from the factory. - $result = $this->resultFactory->create(); - - // we just want the response to return a plain url, so we set the header to text/plain. - $result->setHeader('Content-Type', 'text/plain'); - // the url where the payment will redirect the customer to. $redirectUrl = $this->_url->getUrl('hgw/index/redirect', [ '_forced_secure' => true, @@ -136,7 +154,11 @@ public function execute() '_nosid' => true ]); - // the payment just wants a url as result, so we set the content to the redirectUrl. + // initialize the Raw Response object from the factory. + $result = $this->resultFactory->create(); + // we just want the response to return a plain url, so we set the header to text/plain. + $result->setHeader('Content-Type', 'text/plain'); + // the payment just wants an url as result, so we set the content to the redirectUrl. $result->setContents($redirectUrl); // if there is no post request, just redirect to the cart instantly and show an error message to the customer. @@ -158,7 +180,7 @@ public function execute() // initialize the Response object with data from the request. try { $this->heidelpayResponse = HeidelpayResponse::fromPost($this->getRequest()->getParams()); - } catch (\Exception $e) { + } catch (Exception $e) { $this->_logger->error( 'Heidelpay - Response: Cannot initialize response object from Post Request. ' . $e->getMessage() ); @@ -167,34 +189,11 @@ public function execute() return $result; } - $secret = $this->_encryptor->exportKeys(); - $identificationTransactionId = $this->heidelpayResponse->getIdentification()->getTransactionId(); - - $this->_logger->debug('Heidelpay secret: ' . $secret); - $this->_logger->debug('Heidelpay identificationTransactionId: ' . $identificationTransactionId); - - // validate Hash to prevent manipulation - try { - $this->heidelpayResponse->verifySecurityHash($secret, $identificationTransactionId); - } catch (HashVerificationException $e) { - $this->_logger->critical('Heidelpay Response - HashVerification Exception: ' . $e->getMessage()); - $this->_logger->critical( - 'Heidelpay Response - Received request form server ' - . $this->getRequest()->getServer('REMOTE_ADDR') - . ' with an invalid hash. This could be some kind of manipulation.' - ); - $this->_logger->critical( - 'Heidelpay Response - Reference secret hash: ' - . $this->heidelpayResponse->getCriterion()->getSecretHash() - ); - + if(!$this->validateSecurityHash($this->heidelpayResponse)) { return $result; } - $this->_logger->debug( - 'Heidelpay - Response: Response object: ' - . print_r($this->heidelpayResponse, true) - ); + $this->_logger->debug('Heidelpay - Response: Response object: ' . print_r($this->heidelpayResponse, true)); /** @var Order $order */ $order = null; @@ -203,30 +202,7 @@ public function execute() $quote = null; $data = $this->getRequest()->getParams(); - - // save the heidelpay transaction data - list($paymentMethod, $paymentType) = $this->_paymentHelper->splitPaymentCode( - $this->heidelpayResponse->getPayment()->getCode() - ); - - try { - // save the response details into the heidelpay Transactions table. - $transaction = $this->transactionFactory->create(); - $transaction->setPaymentMethod($paymentMethod) - ->setPaymentType($paymentType) - ->setTransactionId($this->heidelpayResponse->getIdentification()->getTransactionId()) - ->setUniqueId($this->heidelpayResponse->getIdentification()->getUniqueId()) - ->setShortId($this->heidelpayResponse->getIdentification()->getShortId()) - ->setStatusCode($this->heidelpayResponse->getProcessing()->getStatusCode()) - ->setResult($this->heidelpayResponse->getProcessing()->getResult()) - ->setReturnMessage($this->heidelpayResponse->getProcessing()->getReturn()) - ->setReturnCode($this->heidelpayResponse->getProcessing()->getReturnCode()) - ->setJsonResponse(json_encode($data)) - ->setSource('RESPONSE') - ->save(); - } catch (\Exception $e) { - $this->_logger->error('Heidelpay - Response: Save transaction error. ' . $e->getMessage()); - } + $this->_paymentHelper->saveHeidelpayTransaction($this->heidelpayResponse, $data, 'RESPONSE'); // if something went wrong, return the redirect url without processing the order. if ($this->heidelpayResponse->isError()) { @@ -242,53 +218,105 @@ public function execute() $this->_logger->debug($message); + // return the heidelpay response url as raw response instead of echoing it out. + return $result; + } + + // Redirect to installment plan if response is an initialization. + list($paymentMethod, $paymentType) = $this->_paymentHelper->getPaymentMethodAndType($this->heidelpayResponse); + if ($paymentType === TransactionType::INITIALIZE && $paymentMethod === PaymentMethod::HIRE_PURCHASE) { + if ($this->heidelpayResponse->isSuccess()) { + $redirectUrl = $this->_url->getUrl('hgw/index/installmentplan', [ + '_forced_secure' => true, + '_scope_to_url' => true, + '_nosid' => true + ]); + } + // return the heidelpay response url as raw response instead of echoing it out. $result->setContents($redirectUrl); return $result; } + // Create order if transaction is successful if ($this->heidelpayResponse->isSuccess()) { try { + $identificationTransactionId = $this->heidelpayResponse->getIdentification()->getTransactionId(); // get the quote by transactionid from the heidelpay response /** @var Quote $quote */ - $quote = $this->quoteRepository->get($this->heidelpayResponse->getIdentification()->getTransactionId()); - - $quote->getStore()->setCurrentCurrencyCode($quote->getQuoteCurrencyCode()); - $quote->collectTotals(); - // in case of guest checkout, set some customer related data. - if ($this->getRequest()->getPost('CRITERION_GUEST') === 'true') { - $quote->setCustomerId(null) - ->setCustomerEmail($quote->getBillingAddress()->getEmail()) - ->setCustomerIsGuest(true) - ->setCustomerGroupId(\Magento\Customer\Model\Group::NOT_LOGGED_IN_ID); - } - - // create an order by submitting the quote. - $order = $this->_cartManagement->submit($quote); - } catch (\Exception $e) { - $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); + $quote = $this->quoteRepository->get($identificationTransactionId); + /** @var Order $order */ + $order = $this->_paymentHelper->createOrderFromQuote($quote); + } catch (Exception $e) { + $this->_logger->error('Heidelpay - Response: Cannot submit the Quote. ' . $e->getMessage()); return $result; } $data['ORDER_ID'] = $order->getIncrementId(); - $this->_paymentHelper->mapStatus( - $data, - $order + $this->_paymentHelper->mapStatus($data, $order); + $this->handleOrderMail($order); + $this->handleInvoiceMails($order); + + $this->orderRepository->save($order); + } + + $this->handleAdditionalPaymentInformation($quote); + $this->_logger->debug('Heidelpay - Response: redirectUrl is ' . $redirectUrl); + + // return the heidelpay response url as raw response instead of echoing it out. + return $result; + } + + // + + /** + * Send order confirmation to the customer + * @param $order + */ + protected function handleOrderMail($order) + { + try { + if ($order && $order->getId()) { + $this->_orderSender->send($order); + } + } catch (Exception $e) { + $this->_logger->error( + 'Heidelpay - Response: Cannot send order confirmation E-Mail. ' . $e->getMessage() ); + } + } + + /** + * Send invoice mails to the customer + * @param Order $order + */ + protected function handleInvoiceMails(Order $order) + { + if (!$order->canInvoice() && $this->salesHelper->canSendNewInvoiceEmail($order->getStore()->getId())) { + $invoices = $order->getInvoiceCollection(); - $order->save(); + foreach ($invoices as $invoice) { + $this->_invoiceSender->send($invoice); + } } + } - // if the customer is a guest, we'll delete the additional payment information, which - // is only used for customer recognition. - if (isset($quote) && $quote->getCustomerIsGuest()) { + /** + * 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 */ + /** @var PaymentInformation $paymentInfo */ $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $quote->getBillingAddress()->getEmail(), @@ -299,11 +327,38 @@ public function execute() $paymentInfo->delete(); } } + } - $this->_logger->debug('Heidelpay - Response: redirectUrl is ' . $redirectUrl); + /** + * Validate Hash to prevent manipulation + * @param HeidelpayResponse $response + * @return bool + */ + protected function validateSecurityHash($response) + { + $secret = $this->_encryptor->exportKeys(); + $identificationTransactionId = $response->getIdentification()->getTransactionId(); - // return the heidelpay response url as raw response instead of echoing it out. - $result->setContents($redirectUrl); - return $result; + $this->_logger->debug('Heidelpay secret: ' . $secret); + $this->_logger->debug('Heidelpay identificationTransactionId: ' . $identificationTransactionId); + + try { + $response->verifySecurityHash($secret, $identificationTransactionId); + return true; + } catch (HashVerificationException $e) { + $this->_logger->critical('Heidelpay Response - HashVerification Exception: ' . $e->getMessage()); + $this->_logger->critical( + 'Heidelpay Response - Received request form server ' + . $this->getRequest()->getServer('REMOTE_ADDR') + . ' with an invalid hash. This could be some kind of manipulation.' + ); + $this->_logger->critical( + 'Heidelpay Response - Reference secret hash: ' + . $response->getCriterion()->getSecretHash() + ); + return false; + } } + + // } diff --git a/Gateway/Config/HgwBasePaymentConfig.php b/Gateway/Config/HgwBasePaymentConfig.php index 95d64de3a6e..9b76607a3ae 100755 --- a/Gateway/Config/HgwBasePaymentConfig.php +++ b/Gateway/Config/HgwBasePaymentConfig.php @@ -77,7 +77,6 @@ public function getSpecificCountries() return explode(',', $this->getValue(self::KEY_SPECIFIC)); } - /** todo-simon: is this int or float? */ /** * Get the minimum amount the total has to be in order to make this payment method available. * @@ -88,7 +87,6 @@ public function getMinOrderTotal() return (int) $this->getValue(self::KEY_MIN_ORDER_TOTAL); } - /* todo-simon: is this int or float? */ /** * Get the maximum amount the total has to be in order to make this payment method available. * diff --git a/Gateway/Config/HgwCreditCardPaymentConfig.php b/Gateway/Config/HgwCreditCardPaymentConfig.php deleted file mode 100755 index a045812b8aa..00000000000 --- a/Gateway/Config/HgwCreditCardPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwCreditCardPaymentConfig extends HgwBasePaymentConfig implements HgwCreditCardPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwCreditCardPaymentConfigInterface.php b/Gateway/Config/HgwCreditCardPaymentConfigInterface.php deleted file mode 100755 index 0b12dc4899a..00000000000 --- a/Gateway/Config/HgwCreditCardPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwCreditCardPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDebitCardPaymentConfig.php b/Gateway/Config/HgwDebitCardPaymentConfig.php deleted file mode 100755 index 4fe65129c1f..00000000000 --- a/Gateway/Config/HgwDebitCardPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwDebitCardPaymentConfig extends HgwBasePaymentConfig implements HgwDebitCardPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDebitCardPaymentConfigInterface.php b/Gateway/Config/HgwDebitCardPaymentConfigInterface.php deleted file mode 100755 index 8b5a03ba54b..00000000000 --- a/Gateway/Config/HgwDebitCardPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwDebitCardPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDirectDebitPaymentConfig.php b/Gateway/Config/HgwDirectDebitPaymentConfig.php deleted file mode 100755 index d119edc0699..00000000000 --- a/Gateway/Config/HgwDirectDebitPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwDirectDebitPaymentConfig extends HgwBasePaymentConfig implements HgwDirectDebitPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDirectDebitPaymentConfigInterface.php b/Gateway/Config/HgwDirectDebitPaymentConfigInterface.php deleted file mode 100755 index 28e6a60a1b8..00000000000 --- a/Gateway/Config/HgwDirectDebitPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwDirectDebitPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDirectDebitSecPaymentConfig.php b/Gateway/Config/HgwDirectDebitSecPaymentConfig.php deleted file mode 100755 index f2081a2e791..00000000000 --- a/Gateway/Config/HgwDirectDebitSecPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwDirectDebitSecPaymentConfig extends HgwBasePaymentConfig implements HgwDirectDebitSecPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwDirectDebitSecPaymentConfigInterface.php b/Gateway/Config/HgwDirectDebitSecPaymentConfigInterface.php deleted file mode 100755 index b91f479af32..00000000000 --- a/Gateway/Config/HgwDirectDebitSecPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwDirectDebitSecPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwGiropayPaymentConfig.php b/Gateway/Config/HgwGiropayPaymentConfig.php deleted file mode 100755 index 564e7b50f45..00000000000 --- a/Gateway/Config/HgwGiropayPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwGiropayPaymentConfig extends HgwBasePaymentConfig implements HgwGiropayPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwGiropayPaymentConfigInterface.php b/Gateway/Config/HgwGiropayPaymentConfigInterface.php deleted file mode 100755 index b8b64be8bd8..00000000000 --- a/Gateway/Config/HgwGiropayPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwGiropayPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} \ No newline at end of file diff --git a/Gateway/Config/HgwIDealPaymentConfig.php b/Gateway/Config/HgwIDealPaymentConfig.php deleted file mode 100644 index bea0a70dc84..00000000000 --- a/Gateway/Config/HgwIDealPaymentConfig.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * @package heidelpay/magento2 - */ - -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwIDealPaymentConfig extends HgwBasePaymentConfig implements HgwIDealPaymentConfigInterface -{ -} \ No newline at end of file diff --git a/Gateway/Config/HgwIDealPaymentConfigInterface.php b/Gateway/Config/HgwIDealPaymentConfigInterface.php deleted file mode 100644 index 189a2fccccd..00000000000 --- a/Gateway/Config/HgwIDealPaymentConfigInterface.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * @package heidelpay/magento2 - */ - -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwIDealPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} \ No newline at end of file diff --git a/Gateway/Config/HgwInvoicePaymentConfig.php b/Gateway/Config/HgwInvoicePaymentConfig.php deleted file mode 100755 index 432070f37b2..00000000000 --- a/Gateway/Config/HgwInvoicePaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwInvoicePaymentConfig extends HgwBasePaymentConfig implements HgwInvoicePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwInvoicePaymentConfigInterface.php b/Gateway/Config/HgwInvoicePaymentConfigInterface.php deleted file mode 100755 index b78d2eb2b92..00000000000 --- a/Gateway/Config/HgwInvoicePaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwInvoicePaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwInvoiceSecuredPaymentConfig.php b/Gateway/Config/HgwInvoiceSecuredPaymentConfig.php deleted file mode 100755 index 7a6297ffb31..00000000000 --- a/Gateway/Config/HgwInvoiceSecuredPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwInvoiceSecuredPaymentConfig extends HgwBasePaymentConfig implements HgwInvoiceSecuredPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwInvoiceSecuredPaymentConfigInterface.php b/Gateway/Config/HgwInvoiceSecuredPaymentConfigInterface.php deleted file mode 100755 index 1ec8b8e67c4..00000000000 --- a/Gateway/Config/HgwInvoiceSecuredPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwInvoiceSecuredPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwPayPalPaymentConfig.php b/Gateway/Config/HgwPayPalPaymentConfig.php deleted file mode 100755 index 07ce3810066..00000000000 --- a/Gateway/Config/HgwPayPalPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwPayPalPaymentConfig extends HgwBasePaymentConfig implements HgwPayPalPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwPayPalPaymentConfigInterface.php b/Gateway/Config/HgwPayPalPaymentConfigInterface.php deleted file mode 100755 index 9495807aaaf..00000000000 --- a/Gateway/Config/HgwPayPalPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwPayPalPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwPrepaymentPaymentConfig.php b/Gateway/Config/HgwPrepaymentPaymentConfig.php deleted file mode 100755 index 29f6e2c4720..00000000000 --- a/Gateway/Config/HgwPrepaymentPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwPrepaymentPaymentConfig extends HgwBasePaymentConfig implements HgwPrepaymentPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwPrepaymentPaymentConfigInterface.php b/Gateway/Config/HgwPrepaymentPaymentConfigInterface.php deleted file mode 100755 index f9b93c7f815..00000000000 --- a/Gateway/Config/HgwPrepaymentPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwPrepaymentPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwSofortPaymentConfig.php b/Gateway/Config/HgwSofortPaymentConfig.php deleted file mode 100755 index 424fd027c2c..00000000000 --- a/Gateway/Config/HgwSofortPaymentConfig.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -class HgwSofortPaymentConfig extends HgwBasePaymentConfig implements HgwSofortPaymentConfigInterface -{ -} diff --git a/Gateway/Config/HgwSofortPaymentConfigInterface.php b/Gateway/Config/HgwSofortPaymentConfigInterface.php deleted file mode 100755 index 1804f6e6251..00000000000 --- a/Gateway/Config/HgwSofortPaymentConfigInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * @package heidelpay/magento2 - */ -namespace Heidelpay\Gateway\Gateway\Config; - -interface HgwSofortPaymentConfigInterface extends HgwBasePaymentConfigInterface -{ -} diff --git a/Helper/BasketHelper.php b/Helper/BasketHelper.php index 909ac5326a4..f30d3dacaae 100755 --- a/Helper/BasketHelper.php +++ b/Helper/BasketHelper.php @@ -69,8 +69,8 @@ public function convertQuoteToBasket(Quote $quote) // initialize the basket request $basketRequest = new Request(); $basketReferenceId = $basketTotals->getBasketReferenceId(); - $basketRequest->getBasket() - ->setCurrencyCode($basketTotals->getCurrencyCode()) + $basket = $basketRequest->getBasket(); + $basket->setCurrencyCode($basketTotals->getCurrencyCode()) ->setAmountTotalNet($basketTotals->getSubtotalWithDiscountAndShipping()) ->setAmountTotalVat($basketTotals->getActualTaxAmount()) ->setAmountTotalDiscount($basketTotals->getTotalDiscountAmount()) @@ -95,7 +95,7 @@ public function convertQuoteToBasket(Quote $quote) ->setArticleId($item->getSku()) ->setBasketItemReferenceId($itemTotals->getReferenceId($basketReferenceId)); - $basketRequest->getBasket()->addBasketItem($basketItem); + $basket->addBasketItem($basketItem); } /** @var BasketItem $shippingPos */ @@ -110,7 +110,7 @@ public function convertQuoteToBasket(Quote $quote) ->setAmountNet($basketTotals->getShippingAmount()) ->setAmountGross($basketTotals->getShippingInclTax()) ->setBasketItemReferenceId($itemCount); - $basketRequest->getBasket()->addBasketItem($shippingPos); + $basket->addBasketItem($shippingPos); if ($basketTotals->getTotalDiscountAmount() > 0) { /** @var BasketItem $discountPosition */ @@ -122,9 +122,8 @@ public function convertQuoteToBasket(Quote $quote) ->setAmountNet(0) ->setAmountDiscount($basketTotals->getTotalDiscountAmount()) ->setBasketItemReferenceId($itemCount); - $basketRequest->getBasket()->addBasketItem($discountPosition); + $basket->addBasketItem($discountPosition); } - return $basketRequest; } diff --git a/Helper/Payment.php b/Helper/Payment.php index 693c9b8d1f6..5ab3199c0ef 100755 --- a/Helper/Payment.php +++ b/Helper/Payment.php @@ -1,12 +1,29 @@ httpClientFactory = $httpClientFactory; $this->transactionFactory = $transactionFactory; $this->localeResolver = $localeResolver; parent::__construct($context); + $this->_cartManagement = $cartManagement; + $this->heidelpayTransactionFactory = $heidelpayTransactionFactory; } - public function splitPaymentCode($PAYMENT_CODE) + /** + * Returns an array containing the payment method code and the transaction type code. + * + * @param $paymentCode + * + * @return array + * + * @see PaymentMethod + * @see TransactionType + */ + public function splitPaymentCode($paymentCode) { - return preg_split('/\./', $PAYMENT_CODE); + return explode('.', $paymentCode); } /** - * @param array $data - * @param \Magento\Sales\Model\Order $order - * @param bool $message + * @param array $data + * @param Order $order + * @param bool $message */ public function mapStatus($data, $order, $message = false) { $paymentCode = $this->splitPaymentCode($data['PAYMENT_CODE']); - $message = !empty($message) ? $message : $data['PROCESSING_RETURN']; - $quoteID = ($order->getLastQuoteId() === false) - ? $order->getQuoteId() - : $order->getLastQuoteId(); // last_quote_id workaround for trusted shop buyerprotection - // If an order has been canceled, closed or complete -> do not change order status. - if ($order->getStatus() == Order::STATE_CANCELED - || $order->getStatus() == Order::STATE_CLOSED - || $order->getStatus() == Order::STATE_COMPLETE - ) { + if (in_array($order->getStatus(), [Order::STATE_CANCELED, Order::STATE_CLOSED, Order::STATE_COMPLETE], true)) { // you can use this event for example to get a notification when a canceled order has been paid return; } - if ($data['PROCESSING_RESULT'] == 'NOK') { - $order->getPayment()->getMethodInstance()->cancelledTransactionProcessing($order, $message); + $payment = $order->getPayment(); + if ($data['PROCESSING_RESULT'] === ProcessingResult::NOK) { + $payment->getMethodInstance()->cancelledTransactionProcessing($order, $message); } elseif ($this->isProcessing($paymentCode[1], $data)) { - $order->getPayment()->getMethodInstance()->processingTransactionProcessing($data, $order); + $payment->getMethodInstance()->processingTransactionProcessing($data, $order); } else { - $order->getPayment()->getMethodInstance()->pendingTransactionProcessing($data, $order, $message); + $payment->getMethodInstance()->pendingTransactionProcessing($data, $order, $message); } } @@ -113,7 +145,7 @@ public function format($number) * @param string|null $errorCode * * @return string - * @throws \Heidelpay\MessageCodeMapper\Exceptions\MissingLocaleFileException + * @throws MissingLocaleFileException */ public function handleError($errorCode = null) { @@ -152,7 +184,7 @@ public function isMatchingCurrency(Order $order, $data) return false; } - return $order->getOrderCurrencyCode() == $data['PRESENTATION_CURRENCY']; + return $order->getOrderCurrencyCode() === $data['PRESENTATION_CURRENCY']; } /** @@ -169,9 +201,15 @@ public function isProcessing($paymentCode, $data) return false; } - return in_array($paymentCode, ['CP', 'DB', 'FI', 'RC']) - && $data['PROCESSING_RESULT'] == 'ACK' - && $data['PROCESSING_STATUS_CODE'] != 80; + $processingTransactions = [ + TransactionType::CAPTURE, + TransactionType::DEBIT, + TransactionType::FINALIZE, + TransactionType::RECEIPT + ]; + return in_array($paymentCode, $processingTransactions, true) + && $data['PROCESSING_RESULT'] === ProcessingResult::ACK + && $data['PROCESSING_STATUS_CODE'] !== StatusCode::WAITING; } /** @@ -184,14 +222,8 @@ public function isPreAuthorization(array $data) if (!isset($data['PAYMENT_CODE'])) { return false; } - - $paymentCode = $this->splitPaymentCode($data['PAYMENT_CODE']); - - if ($paymentCode[1] == 'PA') { - return true; - } - - return false; + list(, $paymentCode) = $this->splitPaymentCode($data['PAYMENT_CODE']); + return $paymentCode === TransactionType::RESERVATION; } /** @@ -204,21 +236,20 @@ public function isPreAuthorization(array $data) */ public function isReceiptAble($paymentMethod, $paymentType) { - if ($paymentType !== 'RC') { + if ($paymentType !== TransactionType::RECEIPT) { return false; } switch ($paymentMethod) { - case 'DD': - case 'PP': - case 'IV': - case 'OT': - case 'PC': - case 'MP': - case 'HP': + case PaymentMethod::DIRECT_DEBIT: + case PaymentMethod::PREPAYMENT: + case PaymentMethod::INVOICE: + case PaymentMethod::ONLINE_TRANSFER: + case PaymentMethod::PAYMENT_CARD: + case PaymentMethod::MOBILE_PAYMENT: + case PaymentMethod::HIRE_PURCHASE: $return = true; break; - default: $return = false; break; @@ -228,31 +259,97 @@ public function isReceiptAble($paymentMethod, $paymentType) } /** - * Checks if the given paymentcode is viable for a refund transaction. + * Checks if the given payment code is viable for a refund transaction. * - * @param string $paymentcode + * @param string $paymentCode * * @return bool */ - public function isRefundable($paymentcode) + public function isRefundable($paymentCode) { - if ($paymentcode === 'DB' || $paymentcode === 'CP' || $paymentcode === 'RC') { - return true; - } - - return false; + $refundableTransactions = [TransactionType::DEBIT, TransactionType::CAPTURE, TransactionType::RECEIPT]; + return in_array($paymentCode, $refundableTransactions, true); } /** * Saves a transaction by the given invoice. * * @param Invoice $invoice + * + * @throws Exception */ public function saveTransaction(Invoice $invoice) { $transaction = $this->transactionFactory->create(); - $transaction->addObject($invoice) - ->addObject($invoice->getOrder()) - ->save(); + $transaction->addObject($invoice)->addObject($invoice->getOrder())->save(); + } + + /** + * Save the heidelpay transaction data + * + * @param Response $response + * @param array $data + * @param string $source + * + * @return void + * + * @throws Exception + */ + public function saveHeidelpayTransaction(Response $response, array $data, $source) + { + list($paymentMethod, $paymentType) = $this->getPaymentMethodAndType($response); + + try { + // save the response details into the heidelpay Transactions table. + /** @var Transaction $transaction */ + $transaction = $this->heidelpayTransactionFactory->create(); + $transaction->setPaymentMethod($paymentMethod) + ->setPaymentType($paymentType) + ->setTransactionId($response->getIdentification()->getTransactionId()) + ->setUniqueId($response->getIdentification()->getUniqueId()) + ->setShortId($response->getIdentification()->getShortId()) + ->setStatusCode($response->getProcessing()->getStatusCode()) + ->setResult($response->getProcessing()->getResult()) + ->setReturnMessage($response->getProcessing()->getReturn()) + ->setReturnCode($response->getProcessing()->getReturnCode()) + ->setJsonResponse(json_encode($data)) + ->setSource($source) + ->save(); + } catch (Exception $e) { + $this->_logger->error('Heidelpay - ' . $source . ': Save transaction error. ' . $e->getMessage()); + } + } + + /** + * Create an order by submitting the quote. + * @param Quote $quote + * @return AbstractExtensibleModel|OrderInterface|null|object + * @throws LocalizedException + */ + public function createOrderFromQuote($quote) + { + // Ensure to use the currency of the quote. + $quote->getStore()->setCurrentCurrencyCode($quote->getQuoteCurrencyCode()); + $quote->collectTotals(); + // in case of guest checkout, set some customer related data. + if ($quote->getCustomerId() === null) { + $quote->setCustomerId(null) + ->setCustomerEmail($quote->getBillingAddress()->getEmail()) + ->setCustomerIsGuest(true) + ->setCustomerGroupId(Group::NOT_LOGGED_IN_ID); + } + + return $this->_cartManagement->submit($quote); + } + + /** + * Returns an array containing the payment method and payment type of the given Response object. + * + * @param $response + * @return array + */ + public function getPaymentMethodAndType(Response $response) + { + return $this->splitPaymentCode($response->getPayment()->getCode()); } } diff --git a/Model/Transaction.php b/Model/Transaction.php index b5f99db0544..8e9991cff21 100755 --- a/Model/Transaction.php +++ b/Model/Transaction.php @@ -2,6 +2,9 @@ namespace Heidelpay\Gateway\Model; +use Heidelpay\Gateway\Api\Data\TransactionInterface; +use Magento\Framework\Model\AbstractModel; + /** * Transaction resource model * @@ -16,22 +19,27 @@ * @subpackage magento2 * @category magento2 */ -class Transaction extends \Magento\Framework\Model\AbstractModel +class Transaction extends AbstractModel implements TransactionInterface { - public function __construct( - \Magento\Framework\Model\Context $context, - \Magento\Framework\Registry $registry, - \Magento\Payment\Helper\Data $paymentData, - \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, - \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] - ) { - parent::__construct($context, $registry, $resource, $resourceCollection, $data); - } - + const ID = 'id'; + const PAYMENT_METHOD = 'payment_methode'; + const PAYMENT_TYPE = 'payment_type'; + const TRANSACTION_ID = 'transactionid'; + const QUOTE_ID = self::TRANSACTION_ID; + const UNIQUE_ID = 'uniqeid'; + const SHORT_ID = 'shortid'; + const RESULT = 'result'; + const STATUS_CODE = 'statuscode'; + const RETURN_MSG = 'return'; + const RETURN_CODE = 'returncode'; + const JSON_RESPONSE = 'jsonresponse'; + const DATE_TIME = 'datatime'; + const SOURCE = 'source'; + + /** @noinspection MagicMethodsValidityInspection */ public function _construct() { - $this->_init('Heidelpay\Gateway\Model\ResourceModel\Transaction'); + $this->_init(ResourceModel\Transaction::class); } /** @@ -39,7 +47,7 @@ public function _construct() */ public function getPaymentMethod() { - return $this->getData('payment_methode'); + return $this->getData(self::PAYMENT_METHOD); } /** @@ -48,7 +56,7 @@ public function getPaymentMethod() */ public function setPaymentMethod($paymentMethod) { - $this->setData('payment_methode', $paymentMethod); + $this->setData(self::PAYMENT_METHOD, $paymentMethod); return $this; } @@ -57,7 +65,7 @@ public function setPaymentMethod($paymentMethod) */ public function getPaymentType() { - return $this->getData('payment_type'); + return $this->getData(self::PAYMENT_TYPE); } /** @@ -66,7 +74,7 @@ public function getPaymentType() */ public function setPaymentType($paymentType) { - $this->setData('payment_type', $paymentType); + $this->setData(self::PAYMENT_TYPE, $paymentType); return $this; } @@ -75,7 +83,7 @@ public function setPaymentType($paymentType) */ public function getTransactionId() { - return $this->getData('transactionid'); + return $this->getData(self::TRANSACTION_ID); } /** @@ -84,7 +92,7 @@ public function getTransactionId() */ public function setTransactionId($transactionId) { - $this->setData('transactionid', $transactionId); + $this->setData(self::TRANSACTION_ID, $transactionId); return $this; } @@ -93,7 +101,7 @@ public function setTransactionId($transactionId) */ public function getUniqueId() { - return $this->getData('uniqeid'); + return $this->getData(self::UNIQUE_ID); } /** @@ -102,7 +110,7 @@ public function getUniqueId() */ public function setUniqueId($uniqueId) { - $this->setData('uniqeid', $uniqueId); + $this->setData(self::UNIQUE_ID, $uniqueId); return $this; } @@ -111,7 +119,7 @@ public function setUniqueId($uniqueId) */ public function getShortId() { - return $this->getData('shortid'); + return $this->getData(self::SHORT_ID); } /** @@ -120,7 +128,7 @@ public function getShortId() */ public function setShortId($shortId) { - $this->setData('shortid', $shortId); + $this->setData(self::SHORT_ID, $shortId); return $this; } @@ -129,7 +137,7 @@ public function setShortId($shortId) */ public function getResult() { - return $this->getData('result'); + return $this->getData(self::RESULT); } /** @@ -138,7 +146,7 @@ public function getResult() */ public function setResult($result) { - $this->setData('result', $result); + $this->setData(self::RESULT, $result); return $this; } @@ -147,7 +155,7 @@ public function setResult($result) */ public function getStatusCode() { - return $this->getData('statuscode'); + return $this->getData(self::STATUS_CODE); } /** @@ -156,7 +164,7 @@ public function getStatusCode() */ public function setStatusCode($statusCode) { - $this->setData('statuscode', $statusCode); + $this->setData(self::STATUS_CODE, $statusCode); return $this; } @@ -165,7 +173,7 @@ public function setStatusCode($statusCode) */ public function getReturnMessage() { - return $this->getData('return'); + return $this->getData(self::RETURN_MSG); } /** @@ -174,7 +182,7 @@ public function getReturnMessage() */ public function setReturnMessage($returnMessage) { - $this->setData('return', $returnMessage); + $this->setData(self::RETURN_MSG, $returnMessage); return $this; } @@ -183,7 +191,7 @@ public function setReturnMessage($returnMessage) */ public function getReturnCode() { - return $this->getData('returncode'); + return $this->getData(self::RETURN_CODE); } /** @@ -192,7 +200,7 @@ public function getReturnCode() */ public function setReturnCode($returnCode) { - $this->setData('returncode', $returnCode); + $this->setData(self::RETURN_CODE, $returnCode); return $this; } @@ -201,7 +209,7 @@ public function setReturnCode($returnCode) */ public function getJsonResponse() { - return json_decode($this->getData('jsonresponse'), true); + return json_decode($this->getData(self::JSON_RESPONSE), true); } /** @@ -210,7 +218,7 @@ public function getJsonResponse() */ public function setJsonResponse($jsonResponse) { - $this->setData('jsonresponse', $jsonResponse); + $this->setData(self::JSON_RESPONSE, $jsonResponse); return $this; } @@ -219,7 +227,7 @@ public function setJsonResponse($jsonResponse) */ public function getDatetime() { - return $this->getData('datatime'); + return $this->getData(self::DATE_TIME); } /** @@ -227,7 +235,7 @@ public function getDatetime() */ public function getSource() { - return $this->getData('source'); + return $this->getData(self::SOURCE); } /** @@ -236,7 +244,7 @@ public function getSource() */ public function setSource($source) { - $this->setData('source', $source); + $this->setData(self::SOURCE, $source); return $this; } } diff --git a/Model/TransactionRepository.php b/Model/TransactionRepository.php old mode 100755 new mode 100644 index d453ecfcde8..18b13c48f84 --- a/Model/TransactionRepository.php +++ b/Model/TransactionRepository.php @@ -1,105 +1,173 @@ transactionFactory = $transactionFactory; + $this->transactionCollectionFactory = $transactionCollectionFactory; + $this->searchResultFactory = $transactionSearchResultInterfaceFactory; + $this->resource = $resource; + } /** - * @var Transaction[] + * {@inheritDoc} */ - protected $instancesByQuoteId = []; + public function save(Transaction $transaction) + { + $this->resource->save($transaction); + return $transaction; + } /** - * @var \Heidelpay\Gateway\Model\ResourceModel\Transaction + * {@inheritDoc} */ - protected $resourceModel; + public function getById($id) + { + /** @var Transaction $transaction */ + $transaction = $this->transactionFactory->create(); + $this->resource->load($transaction, $id); + if (! $transaction->getId()) { + throw new NoSuchEntityException(__('Unable to find transaction with ID "%1"', $id)); + } + return $transaction; + } /** - * @var TransactionFactory + * {@inheritDoc} */ - protected $transactionFactory; + public function delete(Transaction $transaction) + { + try { + $this->resource->delete($transaction); + } catch (Exception $e) { + throw new CouldNotDeleteException(__('Could not delete the transaction: %1', $e->getMessage())); + } + } + /** + * {@inheritDoc} + */ + public function getList(SearchCriteriaInterface $searchCriteria) + { + $collection = $this->transactionCollectionFactory->create(); - public function __construct( - TransactionFactory $transactionFactory, - ResourceModel\Transaction $resourceModel - ) { - $this->transactionFactory = $transactionFactory; - $this->resourceModel = $resourceModel; + $this->addFiltersToCollection($searchCriteria, $collection); + $this->addSortOrdersToCollection($searchCriteria, $collection); + $this->addPagingToCollection($searchCriteria, $collection); + + $collection->load(); + + return $this->buildSearchResult($searchCriteria, $collection); } + // - public function get($id, $forceReload = false) + /** + * @param SearchCriteriaInterface $searchCriteria + * @param Collection $collection + */ + private function addFiltersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection) { - $cacheKey = $this->getCacheKey([$id]); - if (!isset($this->instances[$id][$cacheKey]) || $forceReload) { - $transaction = $this->transactionFactory->create(); - - if (!$id) { - throw new NoSuchEntityException(__('Requested product doesn\'t exist')); + foreach ($searchCriteria->getFilterGroups() as $filterGroup) { + $conditions = []; + $fields = []; + foreach ($filterGroup->getFilters() as $filter) { + $fields[] = $filter->getField(); + $conditions[] = [$filter->getConditionType() => $filter->getValue()]; } - - $transaction->load($id); - $this->instances[$id][$cacheKey] = $transaction; - $this->instancesByQuoteId[$transaction->getTransactionId()][$cacheKey] = $transaction; + $collection->addFieldToFilter($fields, $conditions); } - - return $this->instances[$id][$cacheKey]; } - public function getByQuoteId($quoteId, $forceReload = false) + /** + * @param SearchCriteriaInterface $searchCriteria + * @param Collection $collection + */ + private function addSortOrdersToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection) { - $cacheKey = $this->getCacheKey([$quoteId]); - if (!isset($this->instancesByQuoteId[$quoteId][$cacheKey]) || $forceReload) { - $transaction = $this->transactionFactory->create(); - - $transactionId = $this->resourceModel; + foreach ((array) $searchCriteria->getSortOrders() as $sortOrder) { + $direction = $sortOrder->getDirection() === SortOrder::SORT_ASC ? 'asc' : 'desc'; + $collection->addOrder($sortOrder->getField(), $direction); } } /** - * Get key for cache + * @param SearchCriteriaInterface $searchCriteria + * @param Collection $collection + */ + private function addPagingToCollection(SearchCriteriaInterface $searchCriteria, Collection $collection) + { + $collection->setPageSize($searchCriteria->getPageSize()); + $collection->setCurPage($searchCriteria->getCurrentPage()); + } + + /** + * @param SearchCriteriaInterface $searchCriteria + * @param Collection $collection * - * @param array $data - * @return string + * @return TransactionSearchResultInterface */ - private function getCacheKey($data) + private function buildSearchResult(SearchCriteriaInterface $searchCriteria, Collection $collection) { - $serializeData = []; - foreach ($data as $key => $value) { - if (is_object($value)) { - $serializeData[$key] = $value->getId(); - } else { - $serializeData[$key] = $value; - } - } + /** @var TransactionSearchResultInterface $searchResults */ + $searchResults = $this->searchResultFactory->create(); + + $searchResults->setSearchCriteria($searchCriteria); + $searchResults->setItems($collection->getItems()); + $searchResults->setTotalCount($collection->getSize()); - return md5(serialize($serializeData)); + return $searchResults; } + + // } diff --git a/Model/TransactionSearchResult.php b/Model/TransactionSearchResult.php new file mode 100644 index 00000000000..5061e8f09ce --- /dev/null +++ b/Model/TransactionSearchResult.php @@ -0,0 +1,22 @@ +urlBuilder = $urlinterface; - $this->logger = $logger; $this->_requestHttp = $request; $this->_paymentHelper = $paymentHelper; $this->salesHelper = $salesHelper; @@ -258,6 +214,51 @@ public function __construct( $this->transactionCollectionFactory = $transactionCollectionFactory; $this->mainConfig = $mainConfig; $this->paymentConfig = $paymentConfig; + + $this->_heidelpayPaymentMethod = $paymentMethod; + $this->setup(); + } + + /** + * Performs setup steps to initialize the payment method. + * Override to perform additional tasks in constructor. + */ + protected function setup() + { + $this->_code = static::CODE; // set the payment code + $this->_isGateway = true; + $this->_canCapture = false; + $this->_canAuthorize = false; + $this->_canCapturePartial = false; + $this->_canRefund = false; + $this->_canRefundInvoicePartial = false; + $this->_canUseInternal = false; + $this->_usingBasket = false; + $this->_usingActiveRedirect = true; + $this->_formBlockType = HgwAbstract::class; + $this->useShippingAddressAsBillingAddress = false; + } + + /** + * @return $this|HeidelpayAbstractPaymentMethod + * @throws CheckoutValidationException + * @throws LocalizedException + */ + public function validate() + { + parent::validate(); + $paymentInfo = $this->getInfoInstance(); + /** @var Quote $quote */ + $quote = $paymentInfo->getQuote(); + + if($quote === null || $quote->isEmpty()) { + return $this; + } + + if($this->useShippingAddressAsBillingAddress) { + $this->validateEqualAddress($quote); + } + return $this; } /** @@ -267,10 +268,9 @@ public function __construct( * customer payment data to pursue. * @return boolean */ - public function activeRedirect() { - return true; + return $this->_usingActiveRedirect; } /** @@ -280,7 +280,7 @@ public function activeRedirect() * @param integer $storeId * * @return string config value - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function getConfigData($field, $storeId = null) { @@ -292,19 +292,19 @@ public function getConfigData($field, $storeId = null) $path = 'payment/' . $this->getCode() . '/' . $field; - return $this->_scopeConfig->getValue($path, StoreScopeInterface::SCOPE_STORE, $storeId); + return $this->_scopeConfig->getValue($path, ScopeInterface::SCOPE_STORE, $storeId); } /** * @inheritdoc * - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ - public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) + public function capture(InfoInterface $payment, $amount) { - /** @var \Magento\Sales\Model\Order\Payment $payment */ + /** @var Payment $payment */ if (!$this->canCapture()) { - throw new \Magento\Framework\Exception\LocalizedException(__('The capture action is not available.')); + throw new LocalizedException(__('The capture action is not available.')); } // skip the bottom part, if the booking mode is not authorization. @@ -312,25 +312,25 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) return $this; } - // create the transactioncollection factory to get the parent authorization. + // create the transaction collection factory to get the parent authorization. $factory = $this->transactionCollectionFactory->create(); - /** @var \Heidelpay\Gateway\Model\Transaction $transactionInfo */ + /** @var Transaction $transactionInfo */ $transactionInfo = $factory->loadByTransactionId($payment->getParentTransactionId()); // if there is no heidelpay transaction, something went wrong. if ($transactionInfo === null || $transactionInfo->isEmpty()) { - throw new \Magento\Framework\Exception\LocalizedException(__('heidelpay - No transaction data available')); + throw new LocalizedException(__('heidelpay - No transaction data available')); } // we can only Capture on Pre-Authorization payment types. // so is the payment type of this Transaction is no PA, we won't capture anything. if ($transactionInfo->getPaymentType() !== 'PA') { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('heidelpay - Cannot capture this transaction.') ); } - // set authentification data + // set authentication data $this->performAuthentication(); // set basket data @@ -350,7 +350,7 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) // if the heidelpay Request wasn't successful, throw an Exception with the heidelpay message if (!$this->_heidelpayPaymentMethod->getResponse()->isSuccess()) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('heidelpay - ' . $this->_heidelpayPaymentMethod->getResponse()->getProcessing()->getReturn()) ); } @@ -384,28 +384,28 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) /** * @inheritdoc */ - public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) + public function refund(InfoInterface $payment, $amount) { - /** @var \Magento\Sales\Model\Order\Payment\Interceptor $payment */ - if (!$this->canRefund()) { - throw new \Magento\Framework\Exception\LocalizedException(__('The refund action is not available.')); + /** @var Payment $payment */ + if (!$this->_canRefund) { + throw new LocalizedException(__('The refund action is not available.')); } - // create the transactioncollection to get the parent authorization. + // create the transaction collection to get the parent authorization. $collection = $this->transactionCollectionFactory->create(); - /** @var \Heidelpay\Gateway\Model\Transaction $transactionInfo */ + /** @var Transaction $transactionInfo */ $transactionInfo = $collection->loadByTransactionId($payment->getParentTransactionId()); // if there is no heidelpay transaction, something went wrong. if ($transactionInfo === null || $transactionInfo->isEmpty()) { - throw new \Magento\Framework\Exception\LocalizedException(__('heidelpay - No transaction data available')); + throw new LocalizedException(__('heidelpay - No transaction data available')); } // we can only refund on transaction where money has been credited/debited // so is the payment type of this Transaction none of them, we won't refund anything. if (!$this->_paymentHelper->isRefundable($transactionInfo->getPaymentType())) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('heidelpay - Cannot refund this transaction.') ); } @@ -430,7 +430,7 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) // if the heidelpay Request wasn't successful, throw an Exception with the heidelpay message if (!$this->_heidelpayPaymentMethod->getResponse()->isSuccess()) { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __('heidelpay - ' . $this->_heidelpayPaymentMethod->getResponse()->getProcessing()->getReturn()) ); } @@ -462,15 +462,14 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) } /** - * @param \Magento\Quote\Model\Quote $quote - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException - * @throws \Magento\Framework\Exception\LocalizedException - * @throws \Exception + * @param Quote $quote + * @param array $data + * @throws InvalidBasketitemPositionException + * @throws LocalizedException */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { $this->setupInitialRequest(); - $user = $this->getUser($quote); $this->_heidelpayPaymentMethod->getRequest()->customerAddress( $user['NAME.GIVEN'], // Given name @@ -522,11 +521,11 @@ public function getHeidelpayUrl($quote) ); // submit the Quote to the Basket API if the payment method needs one. - if ($this->isUsingBasketApi()) { + if ($this->_usingBasket) { $basketId = $this->basketHelper->submitQuoteToBasketApi($quote); if ($basketId === null) { - throw new \Magento\Framework\Exception\LocalizedException(__('Error!')); + throw new LocalizedException(__('Error!')); } $this->_logger->debug('Heidelpay: New basket id is ' . $basketId); @@ -543,9 +542,11 @@ public function getHeidelpayUrl($quote) * @param $paymentType * @param string $source * @param array $data + * @throws Exception */ public function saveHeidelpayTransaction(Response $response, $paymentMethod, $paymentType, $source, array $data) { + /** @var Transaction $transaction */ $transaction = $this->transactionFactory->create(); $transaction->setPaymentMethod($paymentMethod) ->setPaymentType($paymentType) @@ -562,9 +563,9 @@ public function saveHeidelpayTransaction(Response $response, $paymentMethod, $pa } /** - * Returns the heidelpay PhpPaymentApi Paymentmethod Instance. + * Returns the heidelpay PhpPaymentApi payment method instance. * - * @return AbstractPaymentMethod|PaymentMethodInterface + * @return PaymentMethodInterface */ public function getHeidelpayPaymentMethodInstance() { @@ -587,14 +588,14 @@ public function getFrontend() '_forced_secure' => true, '_scope_to_url' => true, '_nosid' => true - ]), + ]) ]; } /** * extract customer information from magento order object * - * @param \Magento\Quote\Api\Data\CartInterface $order object + * @param CartInterface $order object * * @return array customer information */ @@ -602,31 +603,31 @@ public function getUser($order) { $user = []; $billing = $order->getBillingAddress(); - $email = $order->getBillingAddress()->getEmail(); + if (!$billing instanceof AddressInterface) { + throw new RuntimeException('heidelpay - Error billing address is not set!'); + } $billingStreet = ''; - foreach ($billing->getStreet() as $street) { $billingStreet .= $street . ' '; } - $user['CRITERION.GUEST'] = $order->getCustomer()->getId() == 0 ? 'true' : 'false'; + $user['CRITERION.GUEST'] = $order->getCustomer()->getId() === null ? 'true' : 'false'; - $user['NAME.COMPANY'] = ($billing->getCompany() === false) ? null : trim($billing->getCompany()); - $user['NAME.GIVEN'] = trim($billing->getFirstname()); - $user['NAME.FAMILY'] = trim($billing->getLastname()); - $user['ADDRESS.STREET'] = trim($billingStreet); - $user['ADDRESS.ZIP'] = trim($billing->getPostcode()); - $user['ADDRESS.CITY'] = trim($billing->getCity()); + $user['NAME.COMPANY'] = ($billing->getCompany() === false) ? null : trim($billing->getCompany()); + $user['NAME.GIVEN'] = trim($billing->getFirstname()); + $user['NAME.FAMILY'] = trim($billing->getLastname()); + $user['ADDRESS.STREET'] = trim($billingStreet); + $user['ADDRESS.ZIP'] = trim($billing->getPostcode()); + $user['ADDRESS.CITY'] = trim($billing->getCity()); $user['ADDRESS.COUNTRY'] = trim($billing->getCountryId()); - $user['CONTACT.EMAIL'] = trim($email); + $user['CONTACT.EMAIL'] = trim($billing->getEmail()); return $user; } /** - * - * @param \Magento\Sales\Model\Order $order + * @param Order $order * @param string|null $message */ public function cancelledTransactionProcessing(&$order, $message = null) @@ -641,15 +642,20 @@ public function cancelledTransactionProcessing(&$order, $message = null) /** * - * @param array $data - * @param \Magento\Sales\Model\Order $order - * @param string|null $message + * @param array $data + * @param Order $order + * @param string|null $message */ public function pendingTransactionProcessing($data, &$order, $message = null) { - $order->getPayment()->setTransactionId($data['IDENTIFICATION_UNIQUEID']); - $order->getPayment()->setIsTransactionClosed(false); - $order->getPayment()->addTransaction(TransactionInterface::TYPE_AUTH, null, true); + $orderPayment = $order->getPayment(); + if (!$orderPayment instanceof OrderPaymentInterface) { + throw new RuntimeException('heidelpay - Error: Payment is not set.'); + } + + $orderPayment->setTransactionId($data['IDENTIFICATION_UNIQUEID']); + $orderPayment->setIsTransactionClosed(false); + $orderPayment->addTransaction(TransactionInterface::TYPE_AUTH, null, true); $order->setState(Order::STATE_PENDING_PAYMENT) ->addStatusHistoryComment('heidelpay - ' . $message, Order::STATE_PENDING_PAYMENT) @@ -658,17 +664,17 @@ public function pendingTransactionProcessing($data, &$order, $message = null) /** * @param array $data - * @param \Magento\Sales\Model\Order $order - * @throws \Magento\Framework\Exception\LocalizedException + * @param Order $order + * @throws LocalizedException */ public function processingTransactionProcessing($data, &$order) { $message = __('ShortId : %1', $data['IDENTIFICATION_SHORTID']); - $order->getPayment() - ->setTransactionId($data['IDENTIFICATION_UNIQUEID']) - ->setParentTransactionId($order->getPayment()->getLastTransId()) - ->setIsTransactionClosed(true); + $payment = $order->getPayment(); + $payment->setTransactionId($data['IDENTIFICATION_UNIQUEID']) + ->setParentTransactionId($payment->getLastTransId()) + ->setIsTransactionClosed(true); // if the total sum of the order matches the presentation amount of the heidelpay response... if ($this->_paymentHelper->isMatchingAmount($order, $data) @@ -678,9 +684,9 @@ public function processingTransactionProcessing($data, &$order) ->addStatusHistoryComment('heidelpay - ' . $message, Order::STATE_PROCESSING) ->setIsCustomerNotified(true); } else { - // in case rc is ack and amount is to low/heigh or curreny missmatch + // In case receipt is successful (ACK) and amount is to low/high or currency mismatch. $message = __( - 'Amount or currency missmatch : %1', + 'Amount or currency mismatch : %1', $data['PRESENTATION_AMOUNT'] . ' ' . $data['PRESENTATION_CURRENCY'] ); @@ -689,8 +695,7 @@ public function processingTransactionProcessing($data, &$order) ->setIsCustomerNotified(true); } - // if the order can be invoiced and is no Pre-Authorization, - // create one and save it into a transaction. + // if the order can be invoiced and is no Pre-Authorization, create one and save it into a transaction. if ($order->canInvoice() && !$this->_paymentHelper->isPreAuthorization($data)) { $invoice = $order->prepareInvoice(); @@ -701,7 +706,7 @@ public function processingTransactionProcessing($data, &$order) $this->_paymentHelper->saveTransaction($invoice); } - $order->getPayment()->addTransaction(TransactionInterface::TYPE_CAPTURE, null, true); + $payment->addTransaction(TransactionInterface::TYPE_CAPTURE, null, true); } /** @@ -711,7 +716,7 @@ public function processingTransactionProcessing($data, &$order) * @param int $storeId * * @return string|null - * @throws \Magento\Framework\Exception\LocalizedException + * @throws LocalizedException */ public function getBookingMode($storeId = null) { @@ -725,36 +730,18 @@ public function getBookingMode($storeId = null) } /** - * Additional payment information - * * This function will return a text message used to show payment information * to your customer on the checkout success page * * @param array $response * - * @return \Magento\Framework\Phrase|null + * @return Phrase|null */ public function additionalPaymentInformation($response) { return null; } - /** - * @return bool - */ - public function isUsingBasketApi() - { - return $this->usingBasketApi; - } - - /** - * @param bool $usingBasketApi - */ - public function setUsingBasketApi($usingBasketApi) - { - $this->usingBasketApi = $usingBasketApi; - } - /** * Set request authentication */ @@ -781,7 +768,7 @@ public function prepareAdditionalFormData(Response $response) } /* - * Setup initialreques without customer data. + * Setup initial request without customer data. */ public function setupInitialRequest() { @@ -810,7 +797,7 @@ public function getConfig() } /** - * Set the parameter for async modus. + * Set the parameter for async mode. */ public function setAsync() { @@ -821,4 +808,87 @@ public function setAsync() $frontend['RESPONSE_URL'] // Response url from your application ); } + + /** + * @param $transactionID string + * @return bool + */ + public function heidelpayTransactionExists($transactionID) + { + /** @var TransactionCollection $collection */ + $collection = $this->transactionCollectionFactory->create(); + + /** @var Transaction $heidelpayTransaction */ + $heidelpayTransaction = $collection->loadByTransactionId($transactionID); + + return $heidelpayTransaction !== null && !$heidelpayTransaction->isEmpty(); + } + + /** + * @param Quote $quote + * @return bool + */ + protected function billingAddressEqualsShippingAddress($quote) + { + $shippingAddress = $quote->getShippingAddress(); + $billingAddress = $quote->getBillingAddress(); + + $billingCompany = $billingAddress->getCompany(); + $shippingCompany = $shippingAddress->getCompany(); + + //Address should also be valid if both companies are empty + $equalCompany = ($billingCompany === $shippingCompany + || (empty($billingCompany)&& empty($shippingCompany)) + ); + + return ($billingAddress->getFirstname() === $shippingAddress->getFirstname() + && $billingAddress->getLastname() === $shippingAddress->getLastname() + && $billingAddress->getStreet() === $shippingAddress->getStreet() + && $billingAddress->getPostcode() === $shippingAddress->getPostcode() + && $billingAddress->getCity() === $shippingAddress->getCity() + && $billingAddress->getCountryId() === $shippingAddress->getCountryId() + && $equalCompany + && $billingAddress->getTelephone() === $shippingAddress->getTelephone() + ); + } + + /** + * @param Quote $quote + * @throws LocalizedException + */ + public function validateEqualAddress($quote) + { + $isEqualAddress = $this->billingAddressEqualsShippingAddress($quote); + $this->_logger->debug('isEqualAddress: ' . ($isEqualAddress ? 'Yes' : 'NO')); + + if (!$isEqualAddress) { + throw new LocalizedException( + __('Billing address should be same as shipping address.') + ); + } + } + + public function getUseShippingAddressAsBillingAddress() + { + return $this->useShippingAddressAsBillingAddress; + } + + /** + * Load the payment information by store id, customer email address and payment method of the quote. + * @param Quote $quote + * @return PaymentInformation + */ + protected function getPaymentInfo(Quote $quote) + { + // create the collection + $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); + + /** @var PaymentInformation $paymentInfo */ + $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( + $quote->getStoreId(), + $quote->getBillingAddress()->getEmail(), + $quote->getPayment()->getMethod() + ); + return $paymentInfo; + } } diff --git a/PaymentMethods/HeidelpayCreditCardPaymentMethod.php b/PaymentMethods/HeidelpayCreditCardPaymentMethod.php index 46d3953654c..e269ff422d0 100755 --- a/PaymentMethods/HeidelpayCreditCardPaymentMethod.php +++ b/PaymentMethods/HeidelpayCreditCardPaymentMethod.php @@ -1,16 +1,5 @@ _heidelpayPaymentMethod = $creditCardPaymentMethod; - } - - /** - * Active redirect - * - * This function will return false, if the used payment method needs additional - * customer payment data to pursue. - * - * @return boolean + * {@inheritDoc} */ - public function activeRedirect() + protected function setup() { - return false; + parent::setup(); + $this->_canCapture = true; + $this->_canAuthorize = true; + $this->_canCapturePartial = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->_usingActiveRedirect = false; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} * + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); @@ -179,14 +56,15 @@ public function getHeidelpayUrl($quote) $paymentFrameOrigin = $url[0] . '//' . $url[2]; $preventAsyncRedirect = 'FALSE'; $cssPath = $this->mainConfig->getDefaultCss(); + $bookingMode = $this->getBookingMode(); // make an authorize request, if set... - if ($this->getBookingMode() === BookingMode::AUTHORIZATION) { + if ($bookingMode === BookingMode::AUTHORIZATION) { $this->_heidelpayPaymentMethod->authorize($paymentFrameOrigin, $preventAsyncRedirect, $cssPath); } // ... else if no booking mode is set or bookingmode is set to 'debit', make a debit request. - if ($this->getBookingMode() === null || $this->getBookingMode() === BookingMode::DEBIT) { + if ($bookingMode === null || $bookingMode === BookingMode::DEBIT) { $this->_heidelpayPaymentMethod->debit($paymentFrameOrigin, $preventAsyncRedirect, $cssPath); } diff --git a/PaymentMethods/HeidelpayDebitCardPaymentMethod.php b/PaymentMethods/HeidelpayDebitCardPaymentMethod.php index b16db95bc90..eaf68d1569b 100755 --- a/PaymentMethods/HeidelpayDebitCardPaymentMethod.php +++ b/PaymentMethods/HeidelpayDebitCardPaymentMethod.php @@ -1,16 +1,5 @@ _heidelpayPaymentMethod = $debitCardPaymentMethod; - } - - /** - * Active redirect - * - * This function will return false, if the used payment method needs additional - * customer payment data to pursue. - * - * @return boolean + * {@inheritDoc} */ - public function activeRedirect() + protected function setup() { - return false; + parent::setup(); + $this->_canCapture = true; + $this->_canAuthorize = true; + $this->_canCapturePartial = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->_usingActiveRedirect = false; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} * + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); @@ -179,14 +56,15 @@ public function getHeidelpayUrl($quote) $paymentFrameOrigin = $url[0] . '//' . $url[2]; $preventAsyncRedirect = 'FALSE'; $cssPath = $this->mainConfig->getDefaultCss(); + $bookingMode = $this->getBookingMode(); // make an authorize request, if set... - if ($this->getBookingMode() === BookingMode::AUTHORIZATION) { + if ($bookingMode === BookingMode::AUTHORIZATION) { $this->_heidelpayPaymentMethod->authorize($paymentFrameOrigin, $preventAsyncRedirect, $cssPath); } // ... else if no booking mode is set or bookingmode is set to 'debit', make a debit request. - if ($this->getBookingMode() === null || $this->getBookingMode() === BookingMode::DEBIT) { + if ($bookingMode === null || $bookingMode === BookingMode::DEBIT) { $this->_heidelpayPaymentMethod->debit($paymentFrameOrigin, $preventAsyncRedirect, $cssPath); } diff --git a/PaymentMethods/HeidelpayDirectDebitPaymentMethod.php b/PaymentMethods/HeidelpayDirectDebitPaymentMethod.php index de87986b280..f0d28f85bd8 100755 --- a/PaymentMethods/HeidelpayDirectDebitPaymentMethod.php +++ b/PaymentMethods/HeidelpayDirectDebitPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $directDebitPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; } /** - * Fires the initial request to the heidelpay payment provider. - * - * @param \Magento\Quote\Model\Quote $quote - * @return \Heidelpay\PhpPaymentApi\Response - * @throws \Exception - * @throws \Heidelpay\PhpBasketApi\Exception\InvalidBasketitemPositionException - * @throws \Heidelpay\PhpPaymentApi\Exceptions\UndefinedTransactionModeException - * @throws \Magento\Framework\Exception\LocalizedException + * {@inheritDoc} + * @throws UndefinedTransactionModeException */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { - // create the collection factory $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); // load the payment information by store id, customer email address and payment method - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + /** @var PaymentInformation $paymentInfo */ $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $quote->getBillingAddress()->getEmail(), diff --git a/PaymentMethods/HeidelpayDirectDebitSecuredPaymentMethod.php b/PaymentMethods/HeidelpayDirectDebitSecuredPaymentMethod.php index 331f5181663..86dd90b85fd 100755 --- a/PaymentMethods/HeidelpayDirectDebitSecuredPaymentMethod.php +++ b/PaymentMethods/HeidelpayDirectDebitSecuredPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $directDebitB2CSecuredPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->useShippingAddressAsBillingAddress = true; } /** * @inheritdoc + * + * @throws UndefinedTransactionModeException */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { - // create the collection factory $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); // load the payment information by store id, customer email address and payment method - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + /** @var PaymentInformation $paymentInfo */ $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $quote->getBillingAddress()->getEmail(), @@ -164,7 +71,7 @@ public function getHeidelpayUrl($quote) ->set('holder', $paymentInfo->getAdditionalData()->hgw_holder); } - // add salutation and birthdate to the request + // add salutation and date of birth to the request if (isset($paymentInfo->getAdditionalData()->hgw_salutation)) { $this->_heidelpayPaymentMethod->getRequest()->getName() ->set('salutation', $paymentInfo->getAdditionalData()->hgw_salutation); @@ -207,7 +114,7 @@ public function additionalPaymentInformation($response) * * @inheritdoc */ - public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) + public function isAvailable(CartInterface $quote = null) { // in B2C payment methods, we don't want companies to be involved. // so, if the address contains a company, return false. diff --git a/PaymentMethods/HeidelpayGiropayPaymentMethod.php b/PaymentMethods/HeidelpayGiropayPaymentMethod.php index 49a90563494..e430490b81f 100755 --- a/PaymentMethods/HeidelpayGiropayPaymentMethod.php +++ b/PaymentMethods/HeidelpayGiropayPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $giropayPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; } /** * @inheritdoc + * + * @throws UndefinedTransactionModeException */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); diff --git a/PaymentMethods/HeidelpayIDealPaymentMethod.php b/PaymentMethods/HeidelpayIDealPaymentMethod.php index 1ac63533dce..86365b353a6 100644 --- a/PaymentMethods/HeidelpayIDealPaymentMethod.php +++ b/PaymentMethods/HeidelpayIDealPaymentMethod.php @@ -1,16 +1,5 @@ _heidelpayPaymentMethod = $iDealPaymentMethod; + parent::setup(); + $this->_canAuthorize = true; } /** @@ -116,13 +63,17 @@ public function prepareAdditionalFormData(Response $response) return $bankList; } - public function getHeidelpayUrl($quote) + /** + * {@inheritDoc} + * @throws UndefinedTransactionModeException + */ + public function getHeidelpayUrl($quote, array $data = []) { // create the collection factory $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); // load the payment information by store id, customer email address and payment method - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ + /** @var PaymentInformation $paymentInfo */ $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( $quote->getStoreId(), $quote->getBillingAddress()->getEmail(), @@ -153,13 +104,12 @@ public function getHeidelpayUrl($quote) return $this->_heidelpayPaymentMethod->getResponse(); } - public function activeRedirect() - { - return true; - } - - /* + /** * Send an authorize request to get a response which contains list of available banks. + * + * @return Response + * + * @throws UndefinedTransactionModeException */ public function initMethod() { diff --git a/PaymentMethods/HeidelpayInvoicePaymentMethod.php b/PaymentMethods/HeidelpayInvoicePaymentMethod.php index 3e21821633c..227cfd850b9 100755 --- a/PaymentMethods/HeidelpayInvoicePaymentMethod.php +++ b/PaymentMethods/HeidelpayInvoicePaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $invoicePaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->_formBlockType = InvoiceBlock::class; + $this->_infoBlockType = InvoiceBlock::class; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); @@ -183,15 +81,17 @@ public function additionalPaymentInformation($response) /** * @inheritdoc + * @throws Exception */ public function pendingTransactionProcessing($data, &$order, $message = null) { - $order->getPayment()->setTransactionId($data['IDENTIFICATION_UNIQUEID']); - $order->getPayment()->setIsTransactionClosed(false); - $order->getPayment()->addTransaction(\Magento\Sales\Model\Order\Payment\Transaction::TYPE_AUTH, null, true); + $payment = $order->getPayment(); + $payment->setTransactionId($data['IDENTIFICATION_UNIQUEID']); + $payment->setIsTransactionClosed(false); + $payment->addTransaction(Transaction::TYPE_AUTH, null, true); - $order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING) - ->addStatusHistoryComment($message, \Magento\Sales\Model\Order::STATE_PROCESSING) + $order->setState(Order::STATE_PROCESSING) + ->addStatusHistoryComment($message, Order::STATE_PROCESSING) ->setIsCustomerNotified(true); // payment is pending at the beginning, so we set the total paid sum to 0. @@ -200,7 +100,7 @@ public function pendingTransactionProcessing($data, &$order, $message = null) // if the order can be invoiced, create one and save it into a transaction. if ($order->canInvoice()) { $invoice = $order->prepareInvoice(); - $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::CAPTURE_ONLINE) + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE) ->setTransactionId($data['IDENTIFICATION_UNIQUEID']) ->setIsPaid(false) ->register(); diff --git a/PaymentMethods/HeidelpayInvoiceSecuredPaymentMethod.php b/PaymentMethods/HeidelpayInvoiceSecuredPaymentMethod.php index 0e3033d5edd..962a631c490 100755 --- a/PaymentMethods/HeidelpayInvoiceSecuredPaymentMethod.php +++ b/PaymentMethods/HeidelpayInvoiceSecuredPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $invoiceB2CSecuredPaymentMethod; - $this->setUsingBasketApi(true); + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->_usingBasket = true; + $this->_formBlockType = InvoiceSecuredBlock::class; + $this->_infoBlockType = InvoiceSecuredBlock::class; + $this->useShippingAddressAsBillingAddress = true; } /** - * Initial Request to heidelpay payment server to get the form / iframe url - * {@inheritDoc} + * @inheritDoc + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { - // create the collection factory - $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); - - // load the payment information by store id, customer email address and payment method - /** @var \Heidelpay\Gateway\Model\PaymentInformation $paymentInfo */ - $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( - $quote->getStoreId(), - $quote->getBillingAddress()->getEmail(), - $quote->getPayment()->getMethod() - ); + $paymentInfo = $this->getPaymentInfo($quote); // set initial data for the request parent::getHeidelpayUrl($quote); @@ -212,7 +102,7 @@ public function additionalPaymentInformation($response) * * @inheritdoc */ - public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) + public function isAvailable(CartInterface $quote = null) { // in B2C payment methods, we don't want companies to be involved. // so, if the address contains a company, return false. @@ -226,15 +116,17 @@ public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null) /** * @inheritdoc + * @throws \Exception */ public function pendingTransactionProcessing($data, &$order, $message = null) { - $order->getPayment()->setTransactionId($data['IDENTIFICATION_UNIQUEID']); - $order->getPayment()->setIsTransactionClosed(false); - $order->getPayment()->addTransaction(\Magento\Sales\Model\Order\Payment\Transaction::TYPE_AUTH, null, true); + $payment = $order->getPayment(); + $payment->setTransactionId($data['IDENTIFICATION_UNIQUEID']); + $payment->setIsTransactionClosed(false); + $payment->addTransaction(Transaction::TYPE_AUTH, null, true); - $order->setState(\Magento\Sales\Model\Order::STATE_PROCESSING) - ->addStatusHistoryComment($message, \Magento\Sales\Model\Order::STATE_PROCESSING) + $order->setState(Order::STATE_PROCESSING) + ->addStatusHistoryComment($message, Order::STATE_PROCESSING) ->setIsCustomerNotified(true); // payment is pending at the beginning, so we set the total paid sum to 0. @@ -243,7 +135,7 @@ public function pendingTransactionProcessing($data, &$order, $message = null) // if the order can be invoiced, create one and save it into a transaction. if ($order->canInvoice()) { $invoice = $order->prepareInvoice(); - $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::CAPTURE_ONLINE) + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE) ->setTransactionId($data['IDENTIFICATION_UNIQUEID']) ->setIsPaid(false) ->register(); diff --git a/PaymentMethods/HeidelpayPayPalPaymentMethod.php b/PaymentMethods/HeidelpayPayPalPaymentMethod.php index 27cc91b16f3..9e032c65f46 100755 --- a/PaymentMethods/HeidelpayPayPalPaymentMethod.php +++ b/PaymentMethods/HeidelpayPayPalPaymentMethod.php @@ -1,17 +1,6 @@ _heidelpayPaymentMethod = $payPalPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canCapture = true; + $this->_canAuthorize = true; + $this->_canCapturePartial = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->useShippingAddressAsBillingAddress = true; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); + $bookingMode = $this->getBookingMode(); // make an authorize request, if set... - if ($this->getBookingMode() === BookingMode::AUTHORIZATION) { + if ($bookingMode === BookingMode::AUTHORIZATION) { $this->_heidelpayPaymentMethod->authorize(); } // ... else if no booking mode is set or bookingmode is set to 'debit', make a debit request. - if ($this->getBookingMode() === null || $this->getBookingMode() === BookingMode::DEBIT) { + if ($bookingMode === null || $bookingMode === BookingMode::DEBIT) { $this->_heidelpayPaymentMethod->debit(); } diff --git a/PaymentMethods/HeidelpayPrepaymentPaymentMethod.php b/PaymentMethods/HeidelpayPrepaymentPaymentMethod.php index 8b16d4860d1..f4cd959ee7a 100755 --- a/PaymentMethods/HeidelpayPrepaymentPaymentMethod.php +++ b/PaymentMethods/HeidelpayPrepaymentPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $prepaymentPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; + $this->_formBlockType = PrepaymentBlock::class; + $this->_infoBlockType = PrepaymentBlock::class; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { parent::getHeidelpayUrl($quote); @@ -181,15 +79,17 @@ public function additionalPaymentInformation($response) /** * @inheritdoc + * @throws Exception */ public function pendingTransactionProcessing($data, &$order, $message = null) { - $order->getPayment()->setTransactionId($data['IDENTIFICATION_UNIQUEID']); - $order->getPayment()->setIsTransactionClosed(false); - $order->getPayment()->addTransaction(\Magento\Sales\Model\Order\Payment\Transaction::TYPE_AUTH, null, true); + $payment = $order->getPayment(); + $payment->setTransactionId($data['IDENTIFICATION_UNIQUEID']); + $payment->setIsTransactionClosed(false); + $payment->addTransaction(Transaction::TYPE_AUTH, null, true); - $order->setState(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT) - ->addStatusHistoryComment($message, \Magento\Sales\Model\Order::STATE_PENDING_PAYMENT) + $order->setState(Order::STATE_PENDING_PAYMENT) + ->addStatusHistoryComment($message, Order::STATE_PENDING_PAYMENT) ->setIsCustomerNotified(true); // payment is pending at the beginning, so we set the total paid sum to 0. @@ -198,7 +98,7 @@ public function pendingTransactionProcessing($data, &$order, $message = null) // if the order can be invoiced, create one and save it into a transaction. if ($order->canInvoice()) { $invoice = $order->prepareInvoice(); - $invoice->setRequestedCaptureCase(\Magento\Sales\Model\Order\Invoice::CAPTURE_ONLINE) + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE) ->setTransactionId($data['IDENTIFICATION_UNIQUEID']) ->setIsPaid(false) ->register(); diff --git a/PaymentMethods/HeidelpaySantanderHirePurchasePaymentMethod.php b/PaymentMethods/HeidelpaySantanderHirePurchasePaymentMethod.php new file mode 100755 index 00000000000..92eee7e7371 --- /dev/null +++ b/PaymentMethods/HeidelpaySantanderHirePurchasePaymentMethod.php @@ -0,0 +1,152 @@ +_canAuthorize = true; + $this->_usingBasket = true; + $this->useShippingAddressAsBillingAddress = true; + } + + /** + * Determines if the payment method will be displayed at the checkout. + * For B2C methods, the payment method should not be displayed. + * + * Else, refer to the parent isActive method. + * + * @inheritdoc + */ + public function isAvailable(CartInterface $quote = null) + { + // in B2C payment methods, we don't want companies to be involved. + // so, if the address contains a company, return false. + if ($quote !== null && $quote->getBillingAddress() !== null && !empty($quote->getBillingAddress()->getCompany())) { + return false; + } + + // process the parent isAvailable method + return parent::isAvailable($quote); + } + + /** + * Initial Request to heidelpay payment server to get the form url + * {@inheritDoc} + * + * @throws UndefinedTransactionModeException + * @throws Exception + * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() + */ + public function getHeidelpayUrl($quote, array $data = []) + { + // create the collection factory + $paymentInfoCollection = $this->paymentInformationCollectionFactory->create(); + + // load the payment information by store id, customer email address and payment method + /** @var PaymentInformation $paymentInfo */ + $paymentInfo = $paymentInfoCollection->loadByCustomerInformation( + $quote->getStoreId(), + $quote->getBillingAddress()->getEmail(), + $quote->getPayment()->getMethod() + ); + + // set initial data for the request + parent::getHeidelpayUrl($quote); + + // add salutation and birthdate to the request + $request = $this->_heidelpayPaymentMethod->getRequest(); + if (isset($paymentInfo->getAdditionalData()->hgw_salutation)) { + $request->getName()->set('salutation', $paymentInfo->getAdditionalData()->hgw_salutation); + } + + if (isset($paymentInfo->getAdditionalData()->hgw_birthdate)) { + $request->getName()->set('birthdate', $paymentInfo->getAdditionalData()->hgw_birthdate); + } + + // set risk information + $objectManager = ObjectManager::getInstance(); + /** @var CustomerWrapper $customer */ + $customer = $objectManager->create(CustomerWrapper::class)->setCustomer($quote->getCustomer()); + $request->getRiskInformation() + ->setCustomerGuestCheckout($customer->isGuest() ? 'TRUE' : 'FALSE') + ->setCustomerOrderCount($customer->numberOfOrders()) + ->setCustomerSince($customer->customerSince()); + + if (isset($data['referenceId']) && !empty($data['referenceId'])) { + $this->_heidelpayPaymentMethod->authorizeOnRegistration($data['referenceId']); + } else { + $this->_heidelpayPaymentMethod->initialize(); + } + + return $this->_heidelpayPaymentMethod->getResponse(); + } + + /** + * @inheritdoc + * @throws Exception + */ + public function pendingTransactionProcessing($data, &$order, $message = null) + { + $payment = $order->getPayment(); + $payment->setTransactionId($data['IDENTIFICATION_UNIQUEID']); + $payment->setIsTransactionClosed(false); + $payment->addTransaction(Transaction::TYPE_AUTH, null, true); + + $order->setState(Order::STATE_PROCESSING) + ->addStatusHistoryComment($message, Order::STATE_PROCESSING) + ->setIsCustomerNotified(true); + + // payment is pending at the beginning, so we set the total paid sum to 0. + $order->setTotalPaid(0.00)->setBaseTotalPaid(0.00); + + // if the order can be invoiced, create one and save it into a transaction. + if ($order->canInvoice()) { + $invoice = $order->prepareInvoice(); + $invoice->setRequestedCaptureCase(Invoice::CAPTURE_ONLINE) + ->setTransactionId($data['IDENTIFICATION_UNIQUEID']) + ->setIsPaid(false) + ->register(); + + $this->_paymentHelper->saveTransaction($invoice); + } + } +} diff --git a/PaymentMethods/HeidelpaySofortPaymentMethod.php b/PaymentMethods/HeidelpaySofortPaymentMethod.php index 891211b3f4d..9126b29f716 100755 --- a/PaymentMethods/HeidelpaySofortPaymentMethod.php +++ b/PaymentMethods/HeidelpaySofortPaymentMethod.php @@ -1,15 +1,5 @@ _heidelpayPaymentMethod = $sofortPaymentMethod; + protected function setup() + { + parent::setup(); + $this->_canAuthorize = true; + $this->_canRefund = true; + $this->_canRefundInvoicePartial = true; } /** * Initial Request to heidelpay payment server to get the form / iframe url * {@inheritDoc} + * @throws UndefinedTransactionModeException * @see \Heidelpay\Gateway\PaymentMethods\HeidelpayAbstractPaymentMethod::getHeidelpayUrl() */ - public function getHeidelpayUrl($quote) + public function getHeidelpayUrl($quote, array $data = []) { // set initial data for the request parent::getHeidelpayUrl($quote); diff --git a/README.md b/README.md index 1a991e27751..8122d147afb 100755 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Currently supported payment methods are: * Invoice (Secured) (B2C) * giropay * iDeal +* Santander Hire Purchase For more information please visit -http://dev.heidelpay.com/magento2/ diff --git a/Wrapper/BaseWrapper.php b/Wrapper/BaseWrapper.php index bfaa933f1f8..7c1950f7919 100755 --- a/Wrapper/BaseWrapper.php +++ b/Wrapper/BaseWrapper.php @@ -13,7 +13,18 @@ use Heidelpay\Gateway\Traits\DumpGetterReturnsTrait; + class BaseWrapper { use DumpGetterReturnsTrait; + + /** + * Convert an euro amount to cent. + * @param $value + * @return int + */ + public function normalizeValue($value) + { + return (int)round(bcmul($value, 100, 10)); + } } diff --git a/Wrapper/CustomerWrapper.php b/Wrapper/CustomerWrapper.php new file mode 100644 index 00000000000..b9aaf75c75c --- /dev/null +++ b/Wrapper/CustomerWrapper.php @@ -0,0 +1,113 @@ + + * + * @package magento2 + */ +namespace Heidelpay\Gateway\Wrapper; + +use Exception; +use Magento\Customer\Api\Data\CustomerInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\Stdlib\DateTime; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\ResourceModel\Order\Collection; +use Magento\Sales\Model\Order; + +class CustomerWrapper +{ + /** @var CustomerInterface */ + private $customer; + + /** @var OrderRepositoryInterface */ + private $orderRepository; + + /** @var SearchCriteriaBuilder */ + private $searchCriteriaBuilder; + + /** @var DateTime */ + private $dateTime; + + /** + * CustomerWrapper constructor. + * + * @param OrderRepositoryInterface $orderRepository + * @param SearchCriteriaBuilder $searchCriteriaBuilder + * @param DateTime $dateTime + */ + public function __construct( + OrderRepositoryInterface $orderRepository, + SearchCriteriaBuilder $searchCriteriaBuilder, + DateTime $dateTime + ) { + $this->orderRepository = $orderRepository; + $this->searchCriteriaBuilder = $searchCriteriaBuilder; + $this->dateTime = $dateTime; + } + + /** + * @param CustomerInterface $customer + * @return CustomerWrapper + */ + public function setCustomer($customer) + { + $this->customer = $customer; + + return $this; + } + + /** + * Returns true if the customer is a guest. + * + * @return bool + */ + public function isGuest() + { + return empty($this->customer->getId()); + } + + /** + * Returns the day the customer entity has been created or the current date if it is a guest. + * The date is returned as string in the following format 'yyyy-mm-dd'. + * + * @return string + * @throws Exception + */ + public function customerSince() + { + $date = $this->customer->getCreatedAt(); + if ($this->isGuest()) { + $date = true; + } + return $this->dateTime->formatDate($date, false); + } + + /** + * Returns the number of orders the given customer has created over time. + * + * @return int + */ + public function numberOfOrders() + { + if ($this->isGuest()) { + return 0; + } + + /** @var SearchCriteriaInterface $searchCriteria */ + $searchCriteria = $this->searchCriteriaBuilder + ->addFilter('customer_id', $this->customer->getId()) + ->addFilter('state', Order::STATE_COMPLETE) + ->create(); + + /** @var Collection $orderList */ + $orderList = $this->orderRepository->getList($searchCriteria); + + return $orderList->count(); + } +} diff --git a/Wrapper/ItemWrapper.php b/Wrapper/ItemWrapper.php index 8d098a0ca78..1008a11587e 100755 --- a/Wrapper/ItemWrapper.php +++ b/Wrapper/ItemWrapper.php @@ -66,7 +66,8 @@ public function getDiscountAmount() */ public function getTaxAmount() { - return (int)floor(bcmul($this->item->getTaxAmount(), 100, 10)); + return $this->normalizeValue($this->item->getTaxAmount()) + + $this->getDiscountTaxCompensationAmount(); } /** @@ -85,6 +86,16 @@ public function getRowTotal() return (int)floor(bcmul($this->item->getRowTotal(), 100, 10)); } + public function getDiscountTaxCompensationAmount () + { + $discountContainsTax = $this->item->getStore()->getConfig('tax/calculation/discount_tax'); + + if ($discountContainsTax === '0') { + return bcmul($this->item->getDiscountAmount(), $this->item->getTaxPercent()); + } + return $this->normalizeValue($this->item->getDiscountTaxCompensationAmount()); + } + /** * @param string $prefix * @return string diff --git a/Wrapper/QuoteWrapper.php b/Wrapper/QuoteWrapper.php index 33d11ca8b97..4118aef1e0e 100755 --- a/Wrapper/QuoteWrapper.php +++ b/Wrapper/QuoteWrapper.php @@ -12,6 +12,7 @@ namespace Heidelpay\Gateway\Wrapper; use Magento\Quote\Model\Quote; +use Magento\Framework\App\ObjectManager; class QuoteWrapper extends BaseWrapper { @@ -85,7 +86,9 @@ public function getCurrencyCode() public function getSubtotalWithDiscountAndShipping() { // SubtotalWithDiscount already contains the ShippingDiscount but not the shipping itself. - return $this->getSubtotalWithDiscount() + $this->getShippingAmount(); + return $this->getSubtotalWithDiscount() + + $this->getShippingAmount() + + $this->getDiscountTaxCompensationAmount(); } /** @@ -104,7 +107,18 @@ public function getActualTaxAmount() */ public function getTotalDiscountAmount() { - return (int)round(bcmul($this->getTotalDiscountAmountRaw(), 100)); + /** @var string $discountContainsTax */ + $discountContainsTax = $this->quote->getStore()->getConfig('tax/calculation/discount_tax'); + $totalDiscountTaxCompensation = 0; + if ($discountContainsTax === '0') { + foreach ($this->quote->getAllVisibleItems() as $item) { + /** @var ItemWrapper $itemTotals */ + $itemTotals = ObjectManager::getInstance()->create(ItemWrapper::class, ['item' => $item]); + $totalDiscountTaxCompensation += $itemTotals->getDiscountTaxCompensationAmount(); + } + } + + return $this->normalizeValue($this->getTotalDiscountAmountRaw()) + $totalDiscountTaxCompensation; } /** @@ -268,6 +282,14 @@ public function getTaxAmountRaw() return $this->fetchNormalizeValue(self::FIELD_TAX_AMOUNT, true); } + /** + * @return int + */ + public function getDiscountTaxCompensationAmount() + { + return $this->normalizeValue($this->quote->getShippingAddress()->getDiscountTaxCompensationAmount()); + } + // /** @@ -280,7 +302,7 @@ private function fetchNormalizeValue($field, $raw = false) $value = $this->totals[$field]; if (!$raw) { - $value = (int)round(bcmul($value, 100)); + $value = $this->normalizeValue($value); } return $value; diff --git a/composer.json b/composer.json index 4ef80c039ff..d9aad8c76f3 100755 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "magento/framework": "^100.0.0 | ^101.0.0", "heidelpay/php-message-code-mapper": "~1.0", "heidelpay/php-basket-api": "~1.0", - "heidelpay/php-payment-api": "~1.4" + "heidelpay/php-payment-api": "~1.7", + "ext-json": "*" }, "require-dev": { "magento/marketplace-eqp": "~1.0.5", diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml old mode 100644 new mode 100755 index 093dc0ef43c..9324a7bdc70 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -497,6 +497,35 @@ Insert 0 to disable limit. + + + + + Magento\Config\Model\Config\Source\Yesno + payment/hgwsanhp/active + + + + payment/hgwsanhp/title + + + + payment/hgwsanhp/channel + + + + payment/hgwsanhp/sort_order + + + + payment/hgwsanhp/min_order_total + + + + payment/hgwsanhp/max_order_total + Insert 0 to disable limit. + + diff --git a/etc/config.xml b/etc/config.xml old mode 100644 new mode 100755 index 8260fc7131f..c533541c934 --- a/etc/config.xml +++ b/etc/config.xml @@ -132,6 +132,18 @@ 0 Heidelpay\Gateway\PaymentMethods\HeidelpayIDealPaymentMethod + + 0 + authorize + <![CDATA[Santander Hire Purchase]]> + 31HA07BC81302E8725994B52D85F062E + 1 + never + DE + 0 + 0 + Heidelpay\Gateway\PaymentMethods\HeidelpaySantanderHirePurchasePaymentMethod + \ No newline at end of file diff --git a/etc/di.xml b/etc/di.xml index 904e6db6169..7994ef456b5 100755 --- a/etc/di.xml +++ b/etc/di.xml @@ -13,77 +13,148 @@ + + + + HgwCreditCardConfig + Heidelpay\PhpPaymentApi\PaymentMethods\CreditCardPaymentMethod + + + + + HgwDebitCardConfig + Heidelpay\PhpPaymentApi\PaymentMethods\DebitCardPaymentMethod + + + + + HgwDirectDebitConfig + Heidelpay\PhpPaymentApi\PaymentMethods\DirectDebitPaymentMethod + + + + + HgwDirectDebitSecuredConfig + Heidelpay\PhpPaymentApi\PaymentMethods\DirectDebitB2CSecuredPaymentMethod + + + + + HgwGiropayConfig + Heidelpay\PhpPaymentApi\PaymentMethods\GiropayPaymentMethod + + + + + HgwIDealConfig + Heidelpay\PhpPaymentApi\PaymentMethods\IDealPaymentMethod + + + + + HgwInvoiceConfig + Heidelpay\PhpPaymentApi\PaymentMethods\InvoicePaymentMethod + + + + + HgwInvoiceSecuredConfig + Heidelpay\PhpPaymentApi\PaymentMethods\InvoiceB2CSecuredPaymentMethod + + + + + HgwPayPalConfig + Heidelpay\PhpPaymentApi\PaymentMethods\PayPalPaymentMethod + + + + + HgwPrepaymentConfig + Heidelpay\PhpPaymentApi\PaymentMethods\PrepaymentPaymentMethod + + + + + HgwSofortConfig + Heidelpay\PhpPaymentApi\PaymentMethods\SofortPaymentMethod + + + + + HgwSantanderHirePurchaseConfig + Heidelpay\PhpPaymentApi\PaymentMethods\SantanderHirePurchasePaymentMethod + + + - + Heidelpay\Gateway\PaymentMethods\HeidelpayInvoiceSecuredPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayCreditCardPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayDebitCardPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayGiropayPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayPrepaymentPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpaySofortPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayDirectDebitPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayDirectDebitSecuredPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayInvoicePaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayPayPalPaymentMethod::CODE - + Heidelpay\Gateway\PaymentMethods\HeidelpayIDealPaymentMethod::CODE + + + Heidelpay\Gateway\PaymentMethods\HeidelpaySantanderHirePurchasePaymentMethod::CODE + + + + + - - - - - - - - - - - \ No newline at end of file diff --git a/etc/module.xml b/etc/module.xml index af07672a047..7f66e537471 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,5 +1,5 @@ - + diff --git a/i18n/de_DE.csv b/i18n/de_DE.csv index 1d11f9b8bdc..5a3431d3ded 100755 --- a/i18n/de_DE.csv +++ b/i18n/de_DE.csv @@ -11,6 +11,7 @@ "HGWIV","Rechnungskauf" "HGWIVS","Gesicherter Rechnungskauf (B2C)" "HGWIDL","iDeal" +"HGWSANHP","Ratenkauf von Santander" "HGW_ABOUT_US","Die heidelpay GmbH, kurz: heidelpay, ist ein führendes, von der BaFin zugelassenes und beaufsichtigtes Zahlungsinstitut für Online-Paymentverfahren, welches das komplette Leistungsspektrum in Sachen elektronische Zahlungsabwicklung abdeckt: vom Processing der Transaktionen über die Vergabe der Akzeptanzstellenverträge bis hin zum Monitoring und Risk Management.

Mehr Informationen finden Sie auf www.heidelpay.de" @@ -24,14 +25,12 @@ "Insert 0 to disable limit.","Tragen Sie 0 ein um das Limit zu deaktivieren." "If 'Debit' is enabled the card will be charged immediately. Otherwise the amount will first be authorised and charged at order creation.","Wenn diese Einstellung auf Ja steht, wird die Karte sofort belastet. Ansonsten wird der Betrag nur reserviert und bei erstellter Bestellung abgebucht." "An unexpected error occurred. Please contact us to get further information.","Es ist ein Fehler aufgetreten. Bitte kontaktieren Sie uns für weitere Informationen." +"Billing address should be same as shipping address.","Bitte wählen Sie die selbe Rechnungsadresse wie Lieferadresse." "Never","Nie" "Same Shipping Address","Selbe Lieferadresse" "Always","Immer" -"Please confirm your payment:","Bitte führen Sie nun die Zahlung durch:" -"pay now","Jetzt bezahlen" - "Credit Card","Kreditkarte" "Debit Card","Debitkarte" "Direct Debit","Lastschrift" @@ -44,6 +43,7 @@ "Mangirkart","MangirKart" "MasterPass","MasterPass" "Sofort.","Sofort." +"Santander Hire Purchase","Ratenkauf von Santander" "IBAN", "IBAN" "BIC","BIC" @@ -59,6 +59,8 @@ "Year","Jahr" "The given IBAN is invalid.","Die angegebene IBAN ist ungültig." +"The given date is invalid.","Das angegebene Datum ist ungültig" +"You have to be at least 18 years old.","Die Verwendung der Zahlart ist erst ab 18 Jahren möglich" "January","Januar" "February","Februar" @@ -73,15 +75,22 @@ "November","November" "December","Dezember" -"This is a required field.","Dieses Feld ist erforderlich." - "ShortId : %1","ShortId : %1" -"Amount or currency missmatch : %1","Abweichender Betrag oder Währung : %1" +"Amount or currency missmatch : %1","Abweichender Betrag oder Währung : %1" + +"Please confirm your payment:","Bitte führen Sie nun die Zahlung durch:" +"pay now","Jetzt bezahlen" +"Select installment plan","Ratenplan auswählen" +"This is a required field.","Dieses Feld ist erforderlich." "Payment information","Zahlungsinformationen" "Reference","Verwendungszweck" +"Place Order","Bestellung anlegen" "Please transfer the amount of %1 %2 to the following account

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6","Bitte überweisen Sie uns den Betrag von %1 %2 auf folgendes Konto:

Inhaber: %3
IBAN: %4
BIC: %5

Geben Sie als Verwendungszweck bitte ausschließlich diese Identifikationsnummer an:
%6" "Please transfer the amount of %1 %2 to the following account after your order has arrived:

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6","Bitte überweisen Sie uns den Betrag von %1 %2 nach Erhalt der Ware auf folgendes Konto:

Inhaber: %3
IBAN: %4
BIC: %5

Geben Sie als Verwendungszweck bitte ausschließlich diese Identifikationsnummer an:
%6" "The amount of %1 %2 will be debited from this account within the next days:

IBAN: %3

The booking contains the mandate reference ID: %4
and the creditor identifier: %5


Please ensure that there will be sufficient funds on the corresponding account.","Der Betrag von %1 %2 wird in den nächsten Tagen von folgendem Konto abgebucht:

IBAN: %3

Die Abbuchung enthält die Mandatsreferenz-ID: %4
und die Gläubiger ID: %5


Bitte sorgen Sie für ausreichende Deckung auf dem entsprechenden Konto." "Heidelpay Error at sending Finalize Request. The Shipment was not created.","Heidelpay Fehler beim Senden des Finalize Requests. Der Versand wurde nicht erstellt." "Shipping Notification has been sent to Heidelpay.","Versandbenachrichtigung wurde an Heidelpay gesendet." + +"Hire Purchase Precontract","Vorvertragliche Informationen:" +"Hire Purchase Precontract download","Vorvertragliche Informationen zum Ratenkauf hier abrufen" diff --git a/i18n/en_US.csv b/i18n/en_US.csv index 30e5af84645..574a17b1b5b 100755 --- a/i18n/en_US.csv +++ b/i18n/en_US.csv @@ -11,11 +11,21 @@ "HGWIV","Invoice" "HGWIVS","Invoice Secured (B2C)" "HGWIDL","iDeal" +"HGWSANHP","Santander Hire Purchase" "HGW_ABOUT_US","heidelpay GmbH, shortly: heidelpay, is a leading payment institution for online payment methods authorized and regulated by BaFin, which offers the full range of services for an electronic payment processing from one single source: from processing of transactions and providing of acceptance contracts to monitoring and risk management.

For more information please visit www.heidelpay.de" +"Security Sender","Sender-ID" +"User Login","Login" +"User Password","Password" +"Sandbox Mode","Sandbox" "If this is enabled the heidelpay sandbox will be used. Otherwise the real payment system will be used.","If this is enabled the heidelpay sandbox will be used. Otherwise the real payment system will be used." +"Enabled","Enabled" +"Channel","Channel-ID" +"Insert 0 to disable limit.","Insert 0 to disable limit." +"If 'Debit' is enabled the card will be charged immediately. Otherwise the amount will first be authorised and charged at order creation.","If 'Debit' is enabled the card will be charged immediately. Otherwise the amount will first be authorised and charged at order creation." "An unexpected error occurred. Please contact us to get further information.","An unexpected error occurred. Please contact us to get further information." +"Billing address should be same as shipping address.","Billing address should be same as shipping address." "Never","Never" "Same Shipping Address","Same Shipping Address" @@ -33,6 +43,7 @@ "Mangirkart","MangirKart" "MasterPass","MasterPass" "Sofort.","Sofort." +"Santander Hire Purchase","Santander Hire Purchase" "IBAN","IBAN" "BIC","BIC" @@ -48,6 +59,8 @@ "Year","Year" "The given IBAN is invalid.","The given IBAN is invalid." +"The given date is invalid.","The given date is invalid." +"You have to be at least 18 years old.","You have to be at least 18 years old." "January","January" "February","February" @@ -67,12 +80,17 @@ "Please confirm your payment:","Please confirm your payment:" "pay now","pay now" -"Place Order","Place Order" +"Select installment plan","Select installment plan" +"This is a required field.","This is a required field." "Payment information","Payment information" "Reference","Reference" +"Place Order","Place Order" "Please transfer the amount of %1 %2 to the following account

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6","Please transfer the amount of %1 %2 to the following account

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6" "Please transfer the amount of %1 %2 to the following account after your order has arrived:

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6","Please transfer the amount of %1 %2 to the following account after your order has arrived:

Holder: %3
IBAN: %4
BIC: %5

Please use only this identification number as the descriptor :
%6" "The amount of %1 %2 will be debited from this account within the next days:

IBAN: %3

The booking contains the mandate reference ID: %4
and the creditor identifier: %5


Please ensure that there will be sufficient funds on the corresponding account.", "The amount of %1 %2 will be debited from this account within the next days:

IBAN: %3

The booking contains the mandate reference ID: %4
and the creditor identifier: %5


Please ensure that there will be sufficient funds on the corresponding account." "Heidelpay Error at sending Finalize Request. The Shipment was not created.","Heidelpay Error at sending Finalize Request. The Shipment was not created." "Shipping Notification has been sent to Heidelpay.","Shipping Notification has been sent to Heidelpay." + +"Hire Purchase Precontract","Precontract:" +"Hire Purchase Precontract download","Download precontract here" diff --git a/view/frontend/layout/checkout_index_index.xml b/view/frontend/layout/checkout_index_index.xml old mode 100644 new mode 100755 index e0c74392d53..5e64451122b --- a/view/frontend/layout/checkout_index_index.xml +++ b/view/frontend/layout/checkout_index_index.xml @@ -36,7 +36,7 @@ true - false + true true @@ -48,16 +48,19 @@ true - false + true - false + true - false + true - false + true + + + true diff --git a/view/frontend/layout/hgw_index_installmentplan.xml b/view/frontend/layout/hgw_index_installmentplan.xml new file mode 100644 index 00000000000..0bfdcbf3daa --- /dev/null +++ b/view/frontend/layout/hgw_index_installmentplan.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/view/frontend/templates/installment_plan.phtml b/view/frontend/templates/installment_plan.phtml new file mode 100644 index 00000000000..a3f107e581f --- /dev/null +++ b/view/frontend/templates/installment_plan.phtml @@ -0,0 +1,34 @@ + + +
+
+ Santander Logo +
+
+ +
+

+ +
+ + +
+
+
diff --git a/view/frontend/web/js/view/payment/hgw-payments.js b/view/frontend/web/js/view/payment/hgw-payments.js old mode 100644 new mode 100755 index 27a49694994..6aaceeb0dc4 --- a/view/frontend/web/js/view/payment/hgw-payments.js +++ b/view/frontend/web/js/view/payment/hgw-payments.js @@ -23,7 +23,7 @@ define( }, { type: 'hgwpal', - component: 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-abstract' + component: 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-paypal' }, { type: 'hgwpp', @@ -52,6 +52,10 @@ define( { type: 'hgwidl', component: 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-ideal' + }, + { + type: 'hgwsanhp', + component: 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-santander-hire-purchase' } ); return Component.extend({}); 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 5d9615ac4a9..6fa269b01f1 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 @@ -7,9 +7,10 @@ define( '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) { + function ($, Component, placeOrderAction, additionalValidators, selectPaymentMethodAction, checkoutData, quote, selectBillingAddress, moment) { 'use strict'; // add IBAN validator @@ -20,6 +21,25 @@ define( }, $.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({ /** @@ -29,11 +49,16 @@ define( savesAdditionalData: false, defaults: { - template: 'Heidelpay_Gateway/payment/heidelpay-form' + template: 'Heidelpay_Gateway/payment/heidelpay-form', + useShippingAddressAsBillingAddress: false, + hgwDobYear: '', + hgwDobMonth: '', + hgwDobDay: '', + hgwSalutation: '' }, /** - * Indicates if the payment method is storing addtional + * Indicates if the payment method is storing additional * information for the payment. * * @returns {boolean} @@ -55,27 +80,21 @@ define( * * This method needs to be overloaded by the payment renderer component, if needed. */ - getBirthdate: function() {}, + 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 name = '', billingAddress = quote.billingAddress(); - - if (billingAddress !== null) { - if (typeof billingAddress.firstname !== 'undefined' && billingAddress.firstname !== null) { - name += billingAddress.firstname; - } - - if (typeof billingAddress.middlename !== 'undefined' && billingAddress.middlename !== null) { - name += ' ' + billingAddress.middlename; - } - - if (typeof billingAddress.lastname !== 'undefined' && billingAddress.lastname !== null) { - name += ' ' + billingAddress.lastname; - } - } + var billingAddress = quote.billingAddress(); + var name = this.getNameFromAddress(billingAddress); // fallback, if name isn't set yet. if (name === '') { @@ -99,6 +118,25 @@ define( 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 @@ -142,6 +180,10 @@ define( selectPaymentMethodAction(this.getData()); checkoutData.setSelectedPaymentMethod(this.item.method); + if(this.useShippingAddressAsBillingAddress) { + selectBillingAddress(quote.shippingAddress()); + } + return true; } }); diff --git a/view/frontend/web/js/view/payment/method-renderer/hgw-directdebitsecured.js b/view/frontend/web/js/view/payment/method-renderer/hgw-directdebitsecured.js index 14abd5df1ba..804f745b015 100644 --- a/view/frontend/web/js/view/payment/method-renderer/hgw-directdebitsecured.js +++ b/view/frontend/web/js/view/payment/method-renderer/hgw-directdebitsecured.js @@ -25,11 +25,8 @@ define( template: 'Heidelpay_Gateway/payment/heidelpay-directdebit-secured-form', hgwIban: '', hgwHolder: '', - hgwSalutation: '', - hgwDobYear: '', - hgwDobMonth: '', - hgwDobDay: '', - years: [null] + years: [null], + useShippingAddressAsBillingAddress: true }, initialize: function () { @@ -124,17 +121,6 @@ define( }; }, - /** - * Returns the birthdate in ISO 8601 format. - * - * @returns {string} - */ - getBirthdate: function () { - return moment( - new Date(this.hgwDobYear(), this.hgwDobMonth(), this.hgwDobDay()) - ).format('YYYY-MM-DD'); - }, - validate: function () { var form = $('#hgw-directdebit-secured-form'); diff --git a/view/frontend/web/js/view/payment/method-renderer/hgw-invoicesecured.js b/view/frontend/web/js/view/payment/method-renderer/hgw-invoicesecured.js index 910186ff541..e72c1b02f3e 100644 --- a/view/frontend/web/js/view/payment/method-renderer/hgw-invoicesecured.js +++ b/view/frontend/web/js/view/payment/method-renderer/hgw-invoicesecured.js @@ -23,11 +23,8 @@ define( defaults: { template: 'Heidelpay_Gateway/payment/heidelpay-invoice-secured-form', - hgwDobYear: '', - hgwDobMonth: '', - hgwDobDay: '', - hgwSalutation: '', - years: [null] + years: [null], + useShippingAddressAsBillingAddress: true }, initialize: function () { @@ -106,17 +103,6 @@ define( }; }, - /** - * Returns the birthdate in ISO 8601 format. - * - * @returns {string} - */ - getBirthdate: function () { - return moment( - new Date(this.hgwDobYear(), this.hgwDobMonth(), this.hgwDobDay()) - ).format('YYYY-MM-DD'); - }, - validate: function() { var form = $('#hgw-invoice-secured-form'); diff --git a/view/frontend/web/js/view/payment/method-renderer/hgw-paypal.js b/view/frontend/web/js/view/payment/method-renderer/hgw-paypal.js new file mode 100644 index 00000000000..c2a8497aaa4 --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/hgw-paypal.js @@ -0,0 +1,22 @@ +define( + [ + 'jquery', + 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-abstract', + 'Heidelpay_Gateway/js/action/place-order', + 'Magento_Checkout/js/model/url-builder', + 'mage/storage', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/quote' + ], + function ($, Component, placeOrderAction, urlBuilder, storage, additionalValidators, customer, quote) { + 'use strict'; + + return Component.extend({ + defaults: { + useShippingAddressAsBillingAddress: true + } + + }); + } +); \ No newline at end of file diff --git a/view/frontend/web/js/view/payment/method-renderer/hgw-santander-hire-purchase.js b/view/frontend/web/js/view/payment/method-renderer/hgw-santander-hire-purchase.js new file mode 100644 index 00000000000..495712b66af --- /dev/null +++ b/view/frontend/web/js/view/payment/method-renderer/hgw-santander-hire-purchase.js @@ -0,0 +1,116 @@ +define( + [ + 'jquery', + 'Heidelpay_Gateway/js/view/payment/method-renderer/hgw-abstract', + 'Heidelpay_Gateway/js/action/place-order', + 'Magento_Checkout/js/model/url-builder', + 'mage/storage', + 'Magento_Checkout/js/model/payment/additional-validators', + 'Magento_Customer/js/model/customer', + 'Magento_Checkout/js/model/quote', + 'moment' + ], + function ($, Component, placeOrderAction, urlBuilder, storage, additionalValidators, customer, quote, moment) { + 'use strict'; + + return Component.extend({ + + /** + * Property that indicates, if the payment method is storing + * additional data. + */ + savesAdditionalData: true, + + defaults: { + template: 'Heidelpay_Gateway/payment/heidelpay-santander-hire-purchase', + years: [null], + useShippingAddressAsBillingAddress: true + }, + + initialize: function () { + this._super(); + this.getAdditionalPaymentInformation(); + + // init years select menu + for (let i = (new Date().getFullYear() - 17); i >= new Date().getFullYear() - 120; i--) { + this.years.push(i); + } + + return this; + }, + + initObservable: function() { + this._super() + .observe(['hgwSalutation', 'hgwDobYear', 'hgwDobMonth', 'hgwDobDay', 'years', 'hgwInstallmentPlanUrl', 'hgwInstallmentPlanVisible']); + return this; + }, + + getAdditionalPaymentInformation: function() { + // recognition: only when there is a logged in customer + if (customer.isLoggedIn()) { + // if we have a shipping address, go on + if( quote.shippingAddress() !== null ) { + var parent = this; + var serviceUrl = urlBuilder.createUrl('/hgw/get-payment-info', {}); + var hgwPayload = { + quoteId: quote.getQuoteId(), + paymentMethod: this.item.method + }; + + storage.post( + serviceUrl, JSON.stringify(hgwPayload) + ).done( + function(data) { + var info = JSON.parse(data); + + // set salutation and birthdate, if set. + if( info !== null ) { + if (info.hasOwnProperty('hgw_salutation')) + parent.hgwSalutation(info.hgw_salutation); + + if (info.hasOwnProperty('hgw_birthdate') && info.hgw_birthdate !== null) { + var date = moment(info.hgw_birthdate, 'YYYY-MM-DD'); + + parent.hgwDobDay(date.date()); + parent.hgwDobMonth(date.month()); + parent.hgwDobYear(date.year()); + + // workaround: if month is 'january', the month isn't selected. + if (date.month() === 0) { + $("#hgwivs_birthdate_month option:eq(1)").prop('selected', true); + } + } + } + } + ); + } + } + }, + + getCode: function () { + return 'hgwsanhp'; + }, + + getData: function () { + return { + 'method': this.item.method, + 'additional_data': { + 'hgw_birthdate': this.getBirthdate(), + 'hgw_salutation': this.hgwSalutation() + } + }; + }, + + /** + * Returns true if validation succeeded + * + * @returns {*} + */ + validate: function() { + var form = $('#hgw-santander-hire-purchase'); + + return form.validation() && form.validation('isValid'); + } + }); + } +); \ No newline at end of file diff --git a/view/frontend/web/template/payment/heidelpay-directdebit-form.html b/view/frontend/web/template/payment/heidelpay-directdebit-form.html index 6e4d0418de2..685f471e30a 100644 --- a/view/frontend/web/template/payment/heidelpay-directdebit-form.html +++ b/view/frontend/web/template/payment/heidelpay-directdebit-form.html @@ -1,7 +1,13 @@
diff --git a/view/frontend/web/template/payment/heidelpay-directdebit-secured-form.html b/view/frontend/web/template/payment/heidelpay-directdebit-secured-form.html index 98f129b889f..f2180aa2d17 100644 --- a/view/frontend/web/template/payment/heidelpay-directdebit-secured-form.html +++ b/view/frontend/web/template/payment/heidelpay-directdebit-secured-form.html @@ -1,7 +1,13 @@
@@ -160,7 +166,8 @@
diff --git a/view/frontend/web/template/payment/heidelpay-form.html b/view/frontend/web/template/payment/heidelpay-form.html index e0b4e5099ba..b2107691a27 100644 --- a/view/frontend/web/template/payment/heidelpay-form.html +++ b/view/frontend/web/template/payment/heidelpay-form.html @@ -1,10 +1,15 @@ -
diff --git a/view/frontend/web/template/payment/heidelpay-ideal-form.html b/view/frontend/web/template/payment/heidelpay-ideal-form.html index c9b8bfc4993..2e9bf0b0f64 100644 --- a/view/frontend/web/template/payment/heidelpay-ideal-form.html +++ b/view/frontend/web/template/payment/heidelpay-ideal-form.html @@ -1,7 +1,13 @@
diff --git a/view/frontend/web/template/payment/heidelpay-invoice-secured-form.html b/view/frontend/web/template/payment/heidelpay-invoice-secured-form.html index a964eab8963..9811661c363 100644 --- a/view/frontend/web/template/payment/heidelpay-invoice-secured-form.html +++ b/view/frontend/web/template/payment/heidelpay-invoice-secured-form.html @@ -1,7 +1,13 @@
@@ -19,11 +25,6 @@ -
- - - -
@@ -143,12 +144,19 @@
+
+ + + + +
diff --git a/view/frontend/web/template/payment/heidelpay-santander-hire-purchase.html b/view/frontend/web/template/payment/heidelpay-santander-hire-purchase.html new file mode 100644 index 00000000000..43abc1b5f65 --- /dev/null +++ b/view/frontend/web/template/payment/heidelpay-santander-hire-purchase.html @@ -0,0 +1,181 @@ + +
+
+ + +
+ +
+ + + + +
+
+
+ +
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ + + + +
+
+ + + +
+
+
+ +
+
+
+