Commit f5762a5e authored by Daniel Kazior's avatar Daniel Kazior 💰
Browse files

Merge branch 'develop' into 'master'

Develop into master

See merge request !5
parents 8b8be0f2 61cfe25d
......@@ -6,8 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Known issues]
## [Unreleased]
### Fixed
- EXPIRED notifications now increase stock of products when they are cancelling an order
## [0.9.4] - 2019-05-28
## [0.9.4] - 2019-06-04
### Added
- Added a setting to do an automatic capture based on categories
......
## Installation
1. Copy the `app` folder into your magento installation folder.
2. Run `bin/magento setup:upgrade`
3. Run `rm -rf generated/* var/cache/* var/page_cache/* var/view_preprocessed/*`
4. Run `bin/magento setup:static-content:deploy`
5. Run `bin/magento setup:di:compile`
## Known Issues
Please refer to the section in the [Changelog](CHANGELOG.md#known-issues)
## Dependencies
PHP 7.0 and higher
Magento 2.2.x and 2.3.1+ (not 2.3.0)
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.
This can be done by running `composer require crefopay/php-clientlibrary:1.1.4` 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
You can also manually add the line `"crefopay/php-clientlibrary": "1.1.4"` in the composer.json file under the require section.
## Installation
1. Make sure that your system provides all required dependencies (see above)
2. Copy the `app` folder into your magento installation folder.
3. Run `bin/magento setup:upgrade`
4. Run `rm -rf generated/* var/cache/* var/page_cache/* var/view_preprocessed/*`
5. Run `bin/magento setup:static-content:deploy`
6. Run `bin/magento setup:di:compile`
## Known Issues
Please refer to the section in the [Changelog](CHANGELOG.md#known-issues)
<?php
declare(strict_types=1);
namespace Trilix\CrefoPay\Client\Request;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\Quote\Address;
use Magento\Quote\Model\Quote;
use Magento\Customer\Model\Session;
use Magento\Framework\Locale\ResolverInterface as Locale;
use Magento\Customer\Model\Session;
use Upg\Library\Request\CreateTransaction as CreateTransactionRequest;
use Trilix\CrefoPay\Gateway\Request\CompanyBuilder;
use Trilix\CrefoPay\Gateway\Request\AddressBuilder;
......@@ -15,7 +17,6 @@ use Trilix\CrefoPay\Gateway\Request\BasketBuilder;
use Trilix\CrefoPay\Gateway\Request\PersonBuilder;
use Trilix\CrefoPay\Client\ConfigFactory;
use Trilix\CrefoPay\Client\Constants;
use Trilix\CrefoPay\Gateway\Config\Config;
use Trilix\CrefoPay\Gateway\Request\User\CrefoPayUserFactory;
class CreateTransactionRequestFactory extends AbstractRequestFactory
......@@ -26,9 +27,6 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
/** @var CrefoPayUserFactory */
private $crefoPayUserFactory;
/** @var Config */
private $config;
/** @var Locale */
private $locale;
......@@ -47,59 +45,61 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
/** @var CompanyBuilder */
private $companyBuilder;
/** @var UserRiskManager */
private $userRiskManager;
/** @var Session */
private $customerSession;
/**
* CreateTransactionRequestFactory constructor.
*
* @param CartRepositoryInterface $quoteRepository
* @param CrefoPayUserFactory $crefoPayUserFactory
* @param ConfigFactory $configFactory
* @param Config $config
* @param Locale $locale
* @param PersonBuilder $personBuilder
* @param AddressBuilder $addressBuilder
* @param BasketBuilder $basketBuilder
* @param AmountBuilder $amountBuilder
* @param CompanyBuilder $companyBuilder
* @param Session $customerSession
* @param CrefoPayUserFactory $crefoPayUserFactory
* @param ConfigFactory $configFactory
* @param Locale $locale
* @param PersonBuilder $personBuilder
* @param AddressBuilder $addressBuilder
* @param BasketBuilder $basketBuilder
* @param AmountBuilder $amountBuilder
* @param CompanyBuilder $companyBuilder
* @param UserRiskManager $userRiskManager
* @param Session $customerSession
*/
public function __construct(
CartRepositoryInterface $quoteRepository,
CrefoPayUserFactory $crefoPayUserFactory,
ConfigFactory $configFactory,
Config $config,
Locale $locale,
PersonBuilder $personBuilder,
AddressBuilder $addressBuilder,
BasketBuilder $basketBuilder,
AmountBuilder $amountBuilder,
CompanyBuilder $companyBuilder,
UserRiskManager $userRiskManager,
Session $customerSession
) {
parent::__construct($configFactory);
$this->quoteRepository = $quoteRepository;
$this->crefoPayUserFactory = $crefoPayUserFactory;
$this->config = $config;
$this->locale = $locale;
$this->personBuilder = $personBuilder;
$this->addressBuilder = $addressBuilder;
$this->basketBuilder = $basketBuilder;
$this->amountBuilder = $amountBuilder;
$this->companyBuilder = $companyBuilder;
$this->userRiskManager = $userRiskManager;
$this->customerSession = $customerSession;
}
/**
* @param string $quoteId
* @param int $quoteId
* @return CreateTransactionRequest
* @throws \Magento\Framework\Exception\LocalizedException
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
*/
public function create(string $quoteId): CreateTransactionRequest
public function create(int $quoteId): CreateTransactionRequest
{
/** @var Quote $quote */
$quote = $this->quoteRepository->getActive($quoteId);
......@@ -138,7 +138,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
$createTransactionRequest->setLocale($this->getLanguageCode());
$createTransactionRequest->setOrderID($quote->getReservedOrderId());
$createTransactionRequest->setUserRiskClass($this->config->getRiskClass());
$createTransactionRequest->setUserRiskClass($this->userRiskManager->getUserRiskClass());
$this->setMac($createTransactionRequest);
......
......@@ -6,7 +6,6 @@ use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
use Upg\Library\Request\Reserve as ReserveRequest;
use Trilix\CrefoPay\Client\ConfigFactory;
use Trilix\CrefoPay\Gateway\Request\AmountBuilder;
use Trilix\CrefoPay\Client\Request\Structure\AdditionalInfo as AdditionalInfoStructure;
class ReserveRequestFactory extends AbstractRequestFactory
......@@ -28,7 +27,12 @@ class ReserveRequestFactory extends AbstractRequestFactory
$this->amountBuilder = $amountBuilder;
}
/**
* @param string $paymentMethod
* @param PaymentDataObjectInterface $paymentDO
* @return ReserveRequest
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
*/
public function create(string $paymentMethod, PaymentDataObjectInterface $paymentDO): ReserveRequest
{
$reserveRequest = new ReserveRequest($this->getConfig());
......
<?php
declare(strict_types=1);
namespace Trilix\CrefoPay\Client\Request;
use Magento\Customer\Model\Session;
use Trilix\CrefoPay\Gateway\Config\Config;
class UserRiskManager
{
/** @var Session */
private $customerSession;
/** @var Config */
private $config;
/**
* UserRiskManager constructor.
* @param Session $customerSession
* @param Config $config
*/
public function __construct(Session $customerSession, Config $config)
{
$this->customerSession = $customerSession;
$this->config = $config;
}
/**
* @return int
*/
public function getUserRiskClass(): int
{
$result = $this->config->getRiskClass();
$customerUserRiskClass = $this->customerSession->getUserRiskClass();
if ($customerUserRiskClass) {
$result = $customerUserRiskClass['value'];
}
return $result;
}
}
......@@ -70,6 +70,14 @@ class MnsEmitCommand extends Command
protected function configure()
{
/**
* All commands are always instantiated, no matter what command has been actually required. Here we
* use this feature to load the Magento 2.3 interface within Magento 2.2. Otherwise
* 'setup:di:compile' would throw an exception, as it does not include() class files, but reads them
* and processes tokens.
*/
\Trilix\CrefoPay\Polyfill\Polyfill::polyfill();
$this
->setName('crefopay:mns:emit')
->setDescription('Emit CrefoPay MNS event')
......
<?php
namespace Trilix\CrefoPay\Controller\Mns;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\ResultFactory;
use Trilix\CrefoPay\Model\Mns\MnsService;
class Sink extends Action
{
/**
* @var MnsService
*/
private $mnsService;
/**
* Consume constructor.
* @param Context $context
* @param MnsService $mnsService
*/
public function __construct(Context $context, MnsService $mnsService)
{
$this->mnsService = $mnsService;
return parent::__construct($context);
}
namespace {
Trilix\CrefoPay\Polyfill\Polyfill::polyfill();
}
namespace Trilix\CrefoPay\Controller\Mns {
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Request\InvalidRequestException;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Controller\ResultFactory;
use Trilix\CrefoPay\Model\Mns\MnsService;
/**
* @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
*/
public function execute()
class Sink extends Action implements CsrfAwareActionInterface
{
/** @var \Magento\Framework\Controller\Result\Raw $result */
$result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
/**
* @var MnsService
*/
private $mnsService;
$this->mnsService->acknowledge($_POST);
/**
* Consume constructor.
* @param Context $context
* @param MnsService $mnsService
*/
public function __construct(Context $context, MnsService $mnsService)
{
$this->mnsService = $mnsService;
return parent::__construct($context);
}
return $result;
/**
* @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
*/
public function execute()
{
/** @var \Magento\Framework\Controller\Result\Raw $result */
$result = $this->resultFactory->create(ResultFactory::TYPE_RAW);
$this->mnsService->acknowledge($_POST);
return $result;
}
/**
* Validation exception is not thrown in this action.
*
* @param RequestInterface $request
*
* @return InvalidRequestException|null
*/
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
{
return null;
}
/**
* CrefoPay server sends POST requests without Magento formkey, we allow it here.
*
* @param RequestInterface $request
*
* @return true
*/
public function validateForCsrf(RequestInterface $request): ?bool
{
return true;
}
}
}
}
\ No newline at end of file
<?php
namespace Trilix\CrefoPay\Gateway\Command;
use Magento\Customer\Model\Session;
use Magento\Payment\Gateway\Command\CommandException;
use Magento\Payment\Gateway\CommandInterface;
use Magento\Payment\Gateway\Helper\SubjectReader;
use Magento\Payment\Gateway\Response\HandlerInterface;
use Magento\Payment\Gateway\Validator\ValidatorInterface;
use Trilix\CrefoPay\Client\Request\ReserveRequestFactory;
use Trilix\CrefoPay\Client\Transport;
use Trilix\CrefoPay\Model\TransactionService;
use Trilix\CrefoPay\Gateway\SubjectReader;
use Upg\Library\Risk\RiskClass;
use Upg\Library\Api\Exception\ApiError;
class Reserve implements CommandInterface
{
const CREFOPAY_RESERVE_ERROR = 'crefopay_reserve_error';
/** @var Session */
private $customerSession;
/**
* @var Transport
*/
......@@ -26,11 +36,21 @@ class Reserve implements CommandInterface
*/
private $transactionService;
/**
* @var SubjectReader
*/
private $subjectReader;
/**
* @var HandlerInterface
*/
private $handler;
/**
* @var ValidatorInterface|null
*/
private $validator;
/**
* @var string
*/
......@@ -38,57 +58,89 @@ class Reserve implements CommandInterface
/**
* Reserve constructor.
* @param Session $customerSession
* @param Transport $transport
* @param ReserveRequestFactory $reserveRequestFactory
* @param TransactionService $transactionService
* @param SubjectReader $subjectReader
* @param string $methodCode
* @param HandlerInterface|null $handler\
* @param HandlerInterface|null $handler
* @param ValidatorInterface|null $validator
*/
public function __construct(
Session $customerSession,
Transport $transport,
ReserveRequestFactory $reserveRequestFactory,
TransactionService $transactionService,
SubjectReader $subjectReader,
string $methodCode,
HandlerInterface $handler = null
HandlerInterface $handler = null,
ValidatorInterface $validator = null
) {
$this->transport = $transport;
$this->customerSession = $customerSession;
$this->transport = $transport;
$this->reserveRequestFactory = $reserveRequestFactory;
$this->transactionService = $transactionService;
$this->methodCode = $methodCode;
$this->handler = $handler;
$this->transactionService = $transactionService;
$this->subjectReader = $subjectReader;
$this->methodCode = $methodCode;
$this->handler = $handler;
$this->validator = $validator;
}
/**
* @param array $commandSubject
*
* @return void
* @throws CommandException
*/
public function execute(array $commandSubject)
{
try {
$paymentDO = SubjectReader::readPayment($commandSubject);
$paymentDO = $this->subjectReader->readPayment($commandSubject);
$request = $this->reserveRequestFactory->create(
$this->methodCode,
$paymentDO
);
$response = $this->transport->sendRequest($request);
$this->transactionService->addTransaction($paymentDO, $request, $response);
} catch (\Exception $e) {
$this->processErrors($commandSubject, $e);
}
if ($this->handler) {
$this->handler->handle(
$commandSubject,
[]
);
}
// move to handler
$this->transactionService->addTransaction($paymentDO, $request, $response);
} catch (\Exception $e) {
throw new CommandException(
!empty($e->getMessage())
? __($e->getMessage())
: __('Transaction has been declined. Please try again later.')
if ($this->handler) {
$this->handler->handle(
$commandSubject,
[]
);
}
}
/**
* @param array $commandSubject
* @param \Exception $e
* @throws CommandException
*/
private function processErrors(array $commandSubject, \Exception $e)
{
$exception = new CommandException(
!empty($e->getMessage())
? __($e->getMessage())
: __('Transaction has been declined. Please try again later.')
);
if ($e instanceof ApiError && ($this->validator !== null)) {
$result = $this->validator->validate(
array_merge($commandSubject, ['response' => $e->getParsedResponse()])
);
if (!$result->isValid()) {
$this->customerSession->setUserRiskClass(['value' => RiskClass::RISK_CLASS_HIGH]);
$exception = new CommandException(__(self::CREFOPAY_RESERVE_ERROR));
}
}
throw $exception;
}
}
......@@ -5,6 +5,7 @@ namespace Trilix\CrefoPay\Gateway\Config;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Config\Storage\WriterInterface as ConfigWriter;
use Magento\Framework\UrlInterface;
use Magento\Payment\Model\CcConfig;
use Trilix\CrefoPay\Model\Adminhtml\Source\Environment;
......@@ -49,26 +50,33 @@ class Config extends \Magento\Payment\Gateway\Config\Config
* @var CategoryCollectionFactory
*/
private $categoryCollectionFactory;
/**
* @var ConfigWriter
*/
private $configWriter;
/**
* @var UrlInterface
*/
private $urlBuilder;
/**
* Config constructor.
*
* @param ScopeConfigInterface $scopeConfig
* @param CcConfig $ccConfig
* @param ScopeConfigInterface $scopeConfig
* @param CcConfig $ccConfig
* @param CategoryCollectionFactory $categoryCollectionFactory
* @param ConfigWriter $configWriter
* @param null $methodCode
* @param string $pathPattern
* @param ConfigWriter $configWriter
* @param UrlInterface $urlBuilder
* @param null $methodCode
* @param string $pathPattern
*/
public function __construct(
ScopeConfigInterface $scopeConfig,
CcConfig $ccConfig,
CategoryCollectionFactory $categoryCollectionFactory,
ConfigWriter $configWriter,
UrlInterface $urlBuilder,
$methodCode = null,
$pathPattern = self::DEFAULT_PATH_PATTERN
) {
......@@ -76,6 +84,7 @@ class Config extends \Magento\Payment\Gateway\Config\Config
$this->ccConfig = $ccConfig;
$this->categoryCollectionFactory = $categoryCollectionFactory;
$this->configWriter = $configWriter;
$this->urlBuilder = $urlBuilder;
$this->methodCode = $methodCode;
$this->pathPattern = $pathPattern;
}
......@@ -175,8 +184,11 @@ class Config extends \Magento\Payment\Gateway\Config\Config
$environment = self::KEY_ENVIRONMENT;
switch ($this->getValue($environment)) {
case Environment::ENVIRONMENT_PRODUCTION: $subDomain = 'api'; break;
case Environment::ENVIRONMENT_SANDBOX: $subDomain = 'sandbox'; break;
case Environment::ENVIRONMENT_PRODUCTION:
$subDomain = 'api';
break;
case Environment::ENVIRONMENT_SANDBOX:
$subDomain = 'sandbox'; break;
default:
throw new \InvalidArgumentException(sprintf('Invalid value for CrefoPay environment: %s', $environment));
}
......@@ -214,16 +226,21 @@ class Config extends \Magento\Payment\Gateway\Config\Config
}
/**
* Return auto capture category collection.
*
* @return \Magento\Catalog\Model\ResourceModel\Category\Collection
* @param string $method
* @return string
*/
public function getAutoCaptureCategories(): \Magento\Catalog\Model\ResourceModel\Category\Collection
public function getLogoUrl(string $method): string
{
$categories = $this->categoryCollectionFactory->create();
$categories->addIdFilter($this->getAutoCaptureCategoryIds());
$logo = $this->getValue($method . '_logo');
$result = '';
if ($logo) {
$uploadDir = 'crefopay' . DIRECTORY_SEPARATOR . $method . DIRECTORY_SEPARATOR . 'logo';
$url = $uploadDir . DIRECTORY_SEPARATOR . $logo;
$result = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]) . $url;
}
return $categories;
return $result;
}
/**
......