Commit 0912d4f4 authored by Vincent Mrose's avatar Vincent Mrose 💬
Browse files

Merge branch 'develop' into 'master'

Merging version 0.9.2

Closes #4 and #3

See merge request !1
parents a2731d24 0438e47e
......@@ -4,16 +4,24 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Known issues]
- Guest transactions don't reflect the actual input data in the CrefoPay Backend
- Transactions that couldn't be reserved still create an order.
- You can check a successful authorization by selecting the order in the magento backend and visiting the "Transactions" view for this order. If no authorization is visible, the reservation failed.
- EXPIRED Notifications cancel orders that were not paid with CrefoPay methods
- Some notifications don't set an order status due to a failed processing function.
- Terms and Conditions can not be confirmed due to a checkbox not being displayed. See [#1](https://repo.crefopay.de/crefopay/magento2/issues/1)
- Reloading the payment selection does not display the credit card inputs again (#5)
## [Unreleased]
## [0.9.2] - 2019-03-22
### Fixed
- Reserve now displays an error message if it fails and no longer creates an order.
- The module now works with PHP 7.0 as well
- The module now works with Magento 2.2.0 as well
- Reserve now displays an error message if it fails and no longer creates an order
- Terms and Conditions can now be confirmed (#1)
- Notifications are now processing correctly and add order status history comments
- Notifications are only processed if the orders are paid via CrefoPay
- Guest checkout uses the input data by the customer and no longer some hard-coded data
- The basket content is now correctly sent to CrefoPay
- Notifications can now process EXPIRED status when another payment method was used(#3)
- JavaScript functionality now works when using the production environment setting (#4)
### Added
- Cancellation on a third party site will cancel the Magento 2 order and display a link to re-order immediately
## [0.9.1] - 2019-02-11
### Added
......
......@@ -12,12 +12,11 @@ This version is currently in BETA status and is not released for any productive
Please refer to the section in the [Changelog](CHANGELOG.md#known-issues)
## Dependencies
PHP 7.1 and higher.
Magento 2.2.4 and higher.
We are currently working on making the module available for PHP 7.0 and Magento 2.2.0 - 2.2.3 as well.
PHP 7.0 and higher.
Magento 2.2.0 and higher.
This module depends on the CrefoPay PHP Library
To install that library you will need to add the dependency to the magento composer.json.
This module depends on the CrefoPay PHP Library.
To install that library you will need to add the dependency to the magento composer.json.
This can be done by running `composer require crefopay/php-clientlibrary:1.*` in the magento installation folder.
You can also manually add the line `"crefopay/php-clientlibrary": "1.*"` in the composer.json file under the require section.
\ No newline at end of file
......@@ -23,15 +23,15 @@ interface CrefoPayTransactionInterface
* @param $quoteId
* @return void
*/
public function setQuoteId($quoteId): void;
public function setQuoteId($quoteId);
/**
* @param string $paymentMethods
*/
public function setPaymentMethods(string $paymentMethods): void;
public function setPaymentMethods(string $paymentMethods);
/**
* @param string $crefoPayOrderId
*/
public function setCrefoPayOrderId(string $crefoPayOrderId): void;
public function setCrefoPayOrderId(string $crefoPayOrderId);
}
<?php
namespace Trilix\CrefoPay\Block\Callback;
class Failure extends \Magento\Checkout\Block\Onepage\Failure
{
/**
* @return string
*/
public function getReorderUrl(): string
{
$orderId = $this->_checkoutSession->getLastRealOrder()->getId();
return $this->getUrl('sales/order/reorder', ['order_id' => $orderId]);
}
}
\ No newline at end of file
......@@ -31,7 +31,7 @@ abstract class AbstractRequestFactory
* @param AbstractRequest $request
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
*/
protected function setMac(AbstractRequest $request): void
protected function setMac(AbstractRequest $request)
{
$macCalculator = new MacCalculator();
$macCalculator->setConfig($this->getConfig());
......
......@@ -12,7 +12,7 @@ use Upg\Library\Request\CreateTransaction as CreateTransactionRequest;
use Trilix\CrefoPay\Gateway\Request\CompanyBuilder;
use Trilix\CrefoPay\Gateway\Request\AddressBuilder;
use Trilix\CrefoPay\Gateway\Request\AmountBuilder;
use Trilix\CrefoPay\Gateway\Request\BasketItemBuilder;
use Trilix\CrefoPay\Gateway\Request\BasketBuilder;
use Trilix\CrefoPay\Gateway\Request\PersonBuilder;
use Trilix\CrefoPay\Client\ConfigFactory;
use Trilix\CrefoPay\Client\Constants;
......@@ -39,8 +39,8 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
/** @var AddressBuilder */
private $addressBuilder;
/** @var BasketItemBuilder */
private $basketItemBuilder;
/** @var BasketBuilder */
private $basketBuilder;
/** @var AmountBuilder */
private $amountBuilder;
......@@ -61,7 +61,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
* @param Locale $locale
* @param PersonBuilder $personBuilder
* @param AddressBuilder $addressBuilder
* @param BasketItemBuilder $basketItemBuilder
* @param BasketBuilder $basketBuilder
* @param AmountBuilder $amountBuilder
* @param CompanyBuilder $companyBuilder
* @param Session $customerSession
......@@ -74,7 +74,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
Locale $locale,
PersonBuilder $personBuilder,
AddressBuilder $addressBuilder,
BasketItemBuilder $basketItemBuilder,
BasketBuilder $basketBuilder,
AmountBuilder $amountBuilder,
CompanyBuilder $companyBuilder,
Session $customerSession
......@@ -87,7 +87,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
$this->locale = $locale;
$this->personBuilder = $personBuilder;
$this->addressBuilder = $addressBuilder;
$this->basketItemBuilder = $basketItemBuilder;
$this->basketBuilder = $basketBuilder;
$this->amountBuilder = $amountBuilder;
$this->companyBuilder = $companyBuilder;
$this->customerSession = $customerSession;
......@@ -132,11 +132,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
$createTransactionRequest->setAmount($this->amountBuilder->build($quote));
foreach ($quote->getAllItems() as $item) {
/** @var $item QuoteItem */
$basketItem = $this->basketItemBuilder->build($item);
$createTransactionRequest->addBasketItem($basketItem);
}
$this->basketBuilder->build($quote, $createTransactionRequest);
$createTransactionRequest->setAutoCapture($this->config->isAutoCaptureEnabled());
$createTransactionRequest->setLocale($this->getLanguageCode());
......@@ -174,7 +170,8 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
*/
private function getAddress(Address $address): Address
{
if (!$this->customerSession->isLoggedIn()) {
// On reorder there is email, but no other data, as customer hasn't picked up an address yet
if (!$address->getEmail() || !$address->getFirstname()) {
$address->setCountryId('DE');
$address->setCity('Unknown');
$address->setPostcode('00000');
......
......@@ -28,6 +28,7 @@ class UpgFactory
public function createCallbackMacCalculator(array $request): CallbackMacCalculator
{
$config = $this->configFactory->create();
return new CallbackMacCalculator($config, $request);
}
}
\ No newline at end of file
......@@ -97,7 +97,7 @@ class MnsEmitCommand extends Command
$this->printReport($client, $input, $output, $request);
}
private function validateArguments(InputInterface $input): void
private function validateArguments(InputInterface $input)
{
$transactionStatus = $input->getOption(self::OPT_TRX_STATUS);
$orderStatus = $input->getOption(self::OPT_ORDER_STATUS);
......
......@@ -15,7 +15,7 @@ class CliSupervisor implements SupervisorInterface
/**
* {@inheritdoc}
*/
public function setTotalCount(int $itemsCount): void
public function setTotalCount(int $itemsCount)
{
if (!$itemsCount) {
$this->output->writeln('Nothing to do');
......@@ -27,7 +27,7 @@ class CliSupervisor implements SupervisorInterface
/**
* {@inheritdoc}
*/
public function ok(MnsEvent $mns): void
public function ok(MnsEvent $mns)
{
$this->output->writeln(sprintf('[OK] Event for order %d', $mns->getIncrementOrderId()));
}
......@@ -35,14 +35,14 @@ class CliSupervisor implements SupervisorInterface
/**
* {@inheritdoc}
*/
public function fail(MnsEvent $mns): void
public function fail(MnsEvent $mns)
{
$this->output->writeln(
sprintf('[FAIL] Event for order %d, details: %s', $mns->getIncrementOrderId(), $mns->getErrorDetails())
);
}
public function setOutput(OutputInterface $output): void
public function setOutput(OutputInterface $output)
{
$this->output = $output;
}
......
......@@ -79,7 +79,7 @@ class Settle extends \Magento\Backend\App\Action
/**
* @param Order $order
*/
private function updateOrder(Order $order): void
private function updateOrder(Order $order)
{
$order->setStatus(Order::STATE_CLOSED);
$order->setState(Order::STATE_CLOSED);
......
......@@ -4,6 +4,9 @@ namespace Trilix\CrefoPay\Controller\Callback;
use Magento\Checkout\Model\Session;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Sales\Model\OrderRepository;
use Magento\Sales\Model\Order;
use Magento\Framework\View\Result\PageFactory as ResultPageFactory;
class Failure extends Action
{
......@@ -12,23 +15,67 @@ class Failure extends Action
*/
private $checkoutSession;
/**
* @var OrderRepository
*/
private $orderRepository;
/**
* @var ResultPageFactory
*/
protected $resultPageFactory;
/** @var Order */
private $order;
/**
* Failure constructor.
*
* @param Context $context
* @param Session $checkoutSession
* @param Context $context
* @param Session $checkoutSession
* @param OrderRepository $orderRepository
* @param ResultPageFactory $resultPageFactory
*/
public function __construct(Context $context, Session $checkoutSession)
{
public function __construct(
Context $context,
Session $checkoutSession,
OrderRepository $orderRepository,
ResultPageFactory $resultPageFactory
) {
parent::__construct($context);
$this->checkoutSession = $checkoutSession;
$this->orderRepository = $orderRepository;
$this->resultPageFactory = $resultPageFactory;
}
/**
* @return \Magento\Framework\View\Result\Page|\Magento\Framework\Controller\Result\Redirect
*/
public function execute()
{
$this->checkoutSession->setErrorMessage(__('Something went wrong during the payment process.'));
$redirect = $this->resultRedirectFactory->create();
if (!$this->getOrder()->getId()) {
return $this->resultRedirectFactory->create()->setPath('checkout/cart');
}
$this->_cancelOrder();
return $this->resultPageFactory->create();
}
private function _cancelOrder()
{
$order = $this->getOrder();
$order->setState(Order::STATE_CANCELED);
$order->setStatus($order->getConfig()->getStateDefaultStatus(Order::STATE_CANCELED));
$this->orderRepository->save($order);
}
private function getOrder(): Order
{
if (!$this->order) {
$this->order = $this->checkoutSession->getLastRealOrder();
}
return $redirect->setPath('checkout/onepage/failure');
return $this->order;
}
}
\ No newline at end of file
<?php
namespace Trilix\CrefoPay\Gateway\Command;
use Magento\Payment\Gateway\Command\Result\BoolResult;
use Magento\Payment\Gateway\Command\CommandException;
use Magento\Payment\Gateway\CommandInterface;
use Magento\Payment\Gateway\Helper\SubjectReader;
use Trilix\CrefoPay\Client\Request\ReserveRequestFactory;
......@@ -52,24 +52,27 @@ class Reserve implements CommandInterface
/**
* @param array $commandSubject
* @return BoolResult|\Magento\Payment\Gateway\Command\ResultInterface|null
*
* @return void
* @throws CommandException
*/
public function execute(array $commandSubject)
{
try {
$paymentDO = SubjectReader::readPayment($commandSubject);
$request = $this->reserveRequestFactory->create(
$this->methodCode,
$paymentDO
);
$response = $this->transport->sendRequest($request);
$this->transactionService->addTransaction($paymentDO, $request, $response);
return new BoolResult(true);
} catch (\Exception $e) {
return new BoolResult(false);
throw new CommandException(
!empty($e->getMessage())
? __($e->getMessage())
: __('Transaction has been declined. Please try again later.')
);
}
}
}
......@@ -28,6 +28,11 @@ class Config extends \Magento\Payment\Gateway\Config\Config
*/
private $baseUrl;
/**
* @var string
*/
private $secureFieldsUrl;
/**
* Initialize dependencies.
*
......@@ -109,7 +114,32 @@ class Config extends \Magento\Payment\Gateway\Config\Config
*/
public function getPublicToken(): string
{
return (string)$this->getValue(self::KEY_PUBLIC_TOKEN);
return (string) $this->getValue(self::KEY_PUBLIC_TOKEN);
}
/**
* @return string
*/
public function getSecureFieldsUrl(): string
{
if ($this->secureFieldsUrl) {
return $this->secureFieldsUrl;
}
$environment = self::KEY_ENVIRONMENT;
switch ($this->getValue($environment)) {
case Environment::ENVIRONMENT_PRODUCTION:
$this->secureFieldsUrl = 'https://api.crefopay.de/secureFields/';
break;
case Environment::ENVIRONMENT_SANDBOX:
$this->secureFieldsUrl = 'https://sandbox.crefopay.de/secureFields/';
break;
default:
throw new \InvalidArgumentException(sprintf('Invalid value for CrefoPay environment: %s', $environment));
}
return $this->secureFieldsUrl;
}
/**
......
<?php
namespace Trilix\CrefoPay\Gateway\Request;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\Quote\Item as QuoteItem;
use Upg\Library\Request\Objects\BasketItem;
use Upg\Library\Request\Objects\Amount;
use Upg\Library\Request\CreateTransaction as CreateTransactionRequest;
class BasketBuilder
{
/**
* @param Quote $quote
* @param CreateTransactionRequest $createTransactionRequest
*
* @return void
*/
public function build(Quote $quote, CreateTransactionRequest $createTransactionRequest)
{
/** @var $quoteItem QuoteItem */
foreach ($quote->getAllItems() as $quoteItem) {
if ((bool)intval($quoteItem->getRowTotal())) {
$basketItem = $this->buildItem($quoteItem);
$createTransactionRequest->addBasketItem($basketItem);
}
}
}
/**
* @param QuoteItem $quoteItem
*
* @return BasketItem
*/
private function buildItem(QuoteItem $quoteItem): BasketItem
{
$basketItem = new BasketItem();
$basketItemAmount = new Amount();
$basketItemAmount->setAmount(ceil($quoteItem->getRowTotal() * 100));
$basketItem->setBasketItemText($quoteItem->getName());
$basketItem->setBasketItemCount($quoteItem->getQty());
$basketItem->setBasketItemAmount($basketItemAmount);
return $basketItem;
}
}
......@@ -39,7 +39,7 @@ class CrefoPayTransaction extends AbstractModel implements CrefoPayTransactionIn
/**
* {@inheritdoc}
*/
public function setQuoteId($quoteId): void
public function setQuoteId($quoteId)
{
$this->setData('quote_id', $quoteId);
}
......@@ -47,7 +47,7 @@ class CrefoPayTransaction extends AbstractModel implements CrefoPayTransactionIn
/**
* {@inheritdoc}
*/
public function setPaymentMethods(string $paymentMethods): void
public function setPaymentMethods(string $paymentMethods)
{
$this->setData('payment_methods', $paymentMethods);
}
......@@ -55,7 +55,7 @@ class CrefoPayTransaction extends AbstractModel implements CrefoPayTransactionIn
/**
* {@inheritdoc}
*/
public function setCrefoPayOrderId(string $crefoPayOrderId): void
public function setCrefoPayOrderId(string $crefoPayOrderId)
{
$this->setData('crefopay_order_id', $crefoPayOrderId);
}
......
<?php
namespace Trilix\CrefoPay\Model\Mns\Consumers;
use Trilix\CrefoPay\Helper\Order as OrderHelper;
use Magento\Sales\Model\Order as SalesOrder;
use Trilix\CrefoPay\Model\Mns\MnsEvent;
abstract class AbstractConsumer
{
/**
* @var OrderHelper
*/
protected $orderHelper;
/**
* @var SalesOrder
*/
private $order;
/**
* AckPending constructor.
*
* @param OrderHelper $orderHelper
*/
public function __construct(OrderHelper $orderHelper)
{
$this->orderHelper = $orderHelper;
}
/**
* @param MnsEvent $event
*
* @throws MnsConsumerException
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function process(MnsEvent $event)
{
if (substr($this->getOrder($event)->getPayment()->getMethod(), 0, 8) !== 'crefopay') {
throw new MnsConsumerException(
sprintf(
'Can not process MNS event for increment order ID %s. The order has not been paid with CrefoPay.',
$event->getIncrementOrderId()
), MnsConsumerException::NOT_CREFOPAY
);
}
}
/**
* @param MnsEvent $event
*
* @return SalesOrder
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function getOrder(MnsEvent $event): SalesOrder
{
if (!$this->order) {
$this->order = $this->orderHelper->getOrderByIncrementId($event->getIncrementOrderId());
}
return $this->order;
}
/**
* @param SalesOrder $order
* @param string $comment
* @param bool $status
*/
protected function addCommentToStatusHistory(SalesOrder $order, $comment, $status = false)
{
if (method_exists($order, 'addCommentToStatusHistory')) {
$order->addCommentToStatusHistory($comment, $status); // not available in older versions e.g. 2.2.3
} else {
$order->addStatusHistoryComment($comment, $status); // deprecated
}
}
}
\ No newline at end of file
......@@ -3,27 +3,11 @@ namespace Trilix\CrefoPay\Model\Mns\Consumers;
use Magento\Framework\Exception\LocalizedException;
use Trilix\CrefoPay\Client\Constants;
use Trilix\CrefoPay\Helper\Order as OrderHelper;
use Trilix\CrefoPay\Model\Mns\MnsConsumerInterface;
use Trilix\CrefoPay\Model\Mns\MnsEvent;
class AckPending implements MnsConsumerInterface
class AckPending extends AbstractConsumer implements MnsConsumerInterface
{
/**
* @var OrderHelper
*/
private $orderHelper;
/**
* AckPending constructor.
*
* @param OrderHelper $orderHelper
*/
public function __construct(OrderHelper $orderHelper)
{
$this->orderHelper = $orderHelper;
}
/**
* {@inheritdoc}
*/
......@@ -44,11 +28,13 @@ class AckPending implements MnsConsumerInterface
* @param MnsEvent $event
*
* @throws LocalizedException
* @throws \Trilix\CrefoPay\Mns\Consumers\MnsConsumerException
*/
public function process(MnsEvent $event): void
public function process(MnsEvent $event)
{
$order = $this->orderHelper->getOrderByIncrementId($event->getIncrementOrderId());
$order->addCommentToStatusHistory(__('CrefoPay payment reference: %1', $event->getPaymentReference()));
parent::process($event);
$order = $this->getOrder($event);
$this->addCommentToStatusHistory($order, __('CrefoPay payment reference: %1', $event->getPaymentReference()));
$this->orderHelper->getOrderRepository()->save($order);
}
}
\ No newline at end of file