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

Merge branch 'develop' into 'master'

Merge Version 0.9.3 into master

Closes #5 und #7

See merge request !2
parents 81dbdaf8 d793440d
......@@ -4,10 +4,20 @@ 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]
- Reloading the payment selection does not display the credit card inputs again (#5)
## [Unreleased]
## [0.9.3] - 2019-04-04
### Fixed
- Reloading the payment selection does not display the credit card inputs again (#5)
- Cancelling an order does not change the products quantity in the stock (#7)
- Customers can now save their credit cards and bank accounts in Magentos Vault
- Order confirmation emails will be held back until a customer returns from the third-party provider
- Guest checkouts don't use some strange address data anymore
- The date of birth will no longer be filled with the current date
- Translations for the most common checkout errors are now provided in German and English
- The notification handler no longer throws fatal errors in some cases
## [0.9.2-paymentInstrumentId] - 2019-03-26
### Fixed
- Customers can now pay with another payment method after getting rejected by solvency checks (#6)
......
......@@ -13,7 +13,7 @@ Please refer to the section in the [Changelog](CHANGELOG.md#known-issues)
## Dependencies
PHP 7.0 and higher.
Magento 2.2.0 and higher.
Magento 2.2.x only.
This module depends on the CrefoPay PHP Library.
To install that library you will need to add the dependency to the magento composer.json.
......
......@@ -19,6 +19,11 @@ interface CrefoPayTransactionInterface
*/
public function getPaymentMethods(): string;
/**
* @return string
*/
public function getCrefoPayUserId(): string;
/**
* @param $quoteId
* @return void
......@@ -30,6 +35,11 @@ interface CrefoPayTransactionInterface
*/
public function setPaymentMethods(string $paymentMethods);
/**
* @param string $crefoPayUserId
*/
public function setCrefoPayUserId(string $crefoPayUserId);
/**
* @param string $crefoPayOrderId
*/
......
<?php
namespace Trilix\CrefoPay\Block\Callback;
class Failure extends \Magento\Checkout\Block\Onepage\Failure
......@@ -12,4 +13,4 @@ class Failure extends \Magento\Checkout\Block\Onepage\Failure
return $this->getUrl('sales/order/reorder', ['order_id' => $orderId]);
}
}
\ No newline at end of file
}
<?php
namespace Trilix\CrefoPay\Block\Customer;
use Magento\Vault\Api\Data\PaymentTokenInterface;
use Magento\Vault\Block\AbstractCardRenderer;
use Trilix\CrefoPay\Model\Ui\CreditCard\ConfigProvider;
use Trilix\CrefoPay\Model\Ui\CreditCard3D\ConfigProvider as CreditCard3DConfigProvider;
class CardRenderer extends AbstractCardRenderer
{
/**
* Can render specified token
*
* @param PaymentTokenInterface $token
* @return boolean
*/
public function canRender(PaymentTokenInterface $token)
{
return $token->getPaymentMethodCode() === ConfigProvider::CODE
|| $token->getPaymentMethodCode() === CreditCard3DConfigProvider::CODE;
}
/**
* @return string
*/
public function getNumberLast4Digits()
{
return $this->getTokenDetails()['maskedCC'];
}
/**
* @return string
*/
public function getExpDate()
{
return $this->getTokenDetails()['expirationDate'];
}
/**
* @return string
*/
public function getIconUrl()
{
return $this->getIconForType($this->getTokenDetails()['type'])['url'];
}
/**
* @return int
*/
public function getIconHeight()
{
return $this->getIconForType($this->getTokenDetails()['type'])['height'];
}
/**
* @return int
*/
public function getIconWidth()
{
return $this->getIconForType($this->getTokenDetails()['type'])['width'];
}
}
<?php
namespace Trilix\CrefoPay\Block\Customer;
use Magento\Vault\Block\AbstractTokenRenderer;
use Trilix\CrefoPay\Model\Ui\DirectDebit\ConfigProvider;
use Magento\Vault\Api\Data\PaymentTokenInterface;
use Magento\Framework\View\Element\Template;
class DirectDebitRenderer extends AbstractTokenRenderer
{
/**
* Initialize dependencies.
*
* @param Template\Context $context
* @param array $data
*/
public function __construct(
Template\Context $context,
array $data = []
) {
parent::__construct($context, $data);
}
/**
* Can render specified token
*
* @param PaymentTokenInterface $token
* @return boolean
*/
public function canRender(PaymentTokenInterface $token)
{
return $token->getPaymentMethodCode() === ConfigProvider::CODE;
}
/**
* @return string
*/
public function getAccountHolder(): string
{
return $this->getTokenDetails()['accountHolder'];
}
/**
* @return string
*/
public function getIban(): string
{
return $this->getTokenDetails()['iban'];
}
/**
* @return string
*/
public function getBic(): string
{
return $this->getTokenDetails()['bic'];
}
/**
* @return string
*/
public function getIconUrl()
{
return '';
}
/**
* @return int
*/
public function getIconHeight()
{
return 0;
}
/**
* @return int
*/
public function getIconWidth()
{
return 0;
}
}
<?php
namespace Trilix\CrefoPay\Block\Customer;
use Magento\Vault\Block\Customer\PaymentTokens;
use Trilix\CrefoPay\Gateway\Response\CrefoPayPaymentTokenFactory;
class DirectDebitTokens extends PaymentTokens
{
/**
* @inheritdoc
*/
public function getType()
{
return CrefoPayPaymentTokenFactory::TOKEN_TYPE_DIRECT_DEBIT;
}
}
......@@ -5,7 +5,6 @@ namespace Trilix\CrefoPay\Client\Request;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Quote\Model\Quote\Address;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\Quote\Item as QuoteItem;
use Magento\Customer\Model\Session;
use Magento\Framework\Locale\ResolverInterface as Locale;
use Upg\Library\Request\CreateTransaction as CreateTransactionRequest;
......@@ -96,6 +95,7 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
/**
* @param string $quoteId
* @return CreateTransactionRequest
* @throws \Magento\Framework\Exception\LocalizedException
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
*/
......@@ -107,8 +107,10 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
$createTransactionRequest = new CreateTransactionRequest($this->getConfig());
$billingAddress = $this->getAddress($quote->getBillingAddress());
$shippingAddress = $this->getAddress($quote->getShippingAddress());
$isQuoteVirtual = $quote->isVirtual();
$billingAddress = $this->getAddress($quote->getBillingAddress(), $isQuoteVirtual);
$shippingAddress = $this->getAddress($quote->getShippingAddress(), $isQuoteVirtual);
$email = $shippingAddress->getEmail();
......@@ -134,7 +136,6 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
$this->basketBuilder->build($quote, $createTransactionRequest);
$createTransactionRequest->setAutoCapture($this->config->isAutoCaptureEnabled());
$createTransactionRequest->setLocale($this->getLanguageCode());
$createTransactionRequest->setOrderID($quote->getReservedOrderId());
$createTransactionRequest->setUserRiskClass($this->config->getRiskClass());
......@@ -165,13 +166,13 @@ class CreateTransactionRequestFactory extends AbstractRequestFactory
* Mock required address attributes in case user is not logged in.
*
* @param Address $address
*
* @param bool $isQuoteVirtual
* @return Address
*/
private function getAddress(Address $address): Address
private function getAddress(Address $address, bool $isQuoteVirtual): Address
{
// On reorder there is email, but no other data, as customer hasn't picked up an address yet
if (!$address->getEmail() || !$address->getFirstname()) {
if ($isQuoteVirtual && (!$address->getEmail() || !$address->getFirstname())) {
$address->setCountryId('DE');
$address->setCity('Unknown');
$address->setPostcode('00000');
......
<?php
namespace Trilix\CrefoPay\Client\Request;
use Upg\Library\Request\DeleteUserPaymentInstrument as CrefoPayDeleteUserPaymentInstrument;
class DeleteUserPaymentInstrumentRequestFactory extends AbstractRequestFactory
{
/**
* @param string $paymentInstrumentId
* @return CrefoPayDeleteUserPaymentInstrument
*/
public function create(string $paymentInstrumentId): CrefoPayDeleteUserPaymentInstrument
{
$deleteUserPaymentInstrumentRequest = new CrefoPayDeleteUserPaymentInstrument($this->getConfig());
$deleteUserPaymentInstrumentRequest->setPaymentInstrumentID($paymentInstrumentId);
return $deleteUserPaymentInstrumentRequest;
}
}
<?php
namespace Trilix\CrefoPay\Client\Request;
use Upg\Library\Request\GetUserPaymentInstrument;
class GetUserPaymentInstrumentRequestFactory extends AbstractRequestFactory
{
/**
* @param string $userId
* @return GetUserPaymentInstrument
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
*/
public function create(string $userId): GetUserPaymentInstrument
{
$getUserPaymentInstrumentRequest = new GetUserPaymentInstrument($this->getConfig());
$getUserPaymentInstrumentRequest->setUserID($userId);
$this->setMac($getUserPaymentInstrumentRequest);
return $getUserPaymentInstrumentRequest;
}
}
<?php
namespace Trilix\CrefoPay\Client\Request;
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
......
......@@ -25,9 +25,16 @@ class Transport
/**
* @param UpgRequest\AbstractRequest $request
*
* @return SuccessResponse
* @throws CrefoPayException
* @throws UpgCall\Exception\ApiError
* @throws UpgCall\Exception\CurlError
* @throws UpgCall\Exception\InvalidHttpResponseCode
* @throws UpgCall\Exception\InvalidUrl
* @throws UpgCall\Exception\JsonDecode
* @throws UpgCall\Exception\MacValidation
* @throws UpgCall\Exception\RequestNotSet
* @throws UpgCall\Exception\Validation
* @throws \Upg\Library\Mac\Exception\MacInvalid
*/
public function sendRequest(UpgRequest\AbstractRequest $request): SuccessResponse
{
......@@ -40,6 +47,8 @@ class Transport
case $request instanceof UpgRequest\Reserve: $call = new UpgCall\Reserve($config, $request); break;
case $request instanceof UpgRequest\Capture: $call = new UpgCall\Capture($config, $request); break;
case $request instanceof UpgRequest\CreateTransaction: $call = new UpgCall\CreateTransaction($config, $request); break;
case $request instanceof UpgRequest\GetUserPaymentInstrument: $call = new UpgCall\GetUserPaymentInstrument($config, $request); break;
case $request instanceof UpgRequest\DeleteUserPaymentInstrument: $call = new UpgCall\DeleteUserPaymentInstrument($config, $request); break;
default:
throw new \InvalidArgumentException(sprintf('Can not instantiate CrefoPay call for "%s"', get_class($request)));
}
......
......@@ -5,12 +5,12 @@ use Magento\Framework\App\State as AppState;
use Magento\Framework\HTTP\ClientFactory;
use Magento\Framework\HTTP\ClientInterface;
use Magento\Framework\UrlInterface;
use Magento\Setup\Console\Style\MagentoStyle;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Trilix\CrefoPay\Client\ConfigFactory;
use Upg\Library\Callback\MacCalculator;
use Trilix\CrefoPay\Client\Constants;
......@@ -183,19 +183,19 @@ class MnsEmitCommand extends Command
private function printReport(ClientInterface $client, InputInterface $input, OutputInterface $output, array $request)
{
$io = new MagentoStyle($input, $output);
$outputStyle = new SymfonyStyle($input, $output);
$text = sprintf("%d POST %s", $client->getStatus(), $this->getUrl($input));
if ($client->getStatus() === 200) {
$io->success($text);
$outputStyle->success($text);
} else {
$io->error($text);
$outputStyle->error($text);
}
$io->comment(http_build_query($request));
$outputStyle->text(http_build_query($request));
if ($client->getBody()) {
$io->error("\n" . $client->getBody());
$outputStyle->error("\n" . $client->getBody());
}
}
}
\ No newline at end of file
......@@ -7,7 +7,6 @@ use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Exception\NoSuchEntityException;
use Trilix\CrefoPay\Model\CrefoPayTransactionRepository;
use Trilix\CrefoPay\Model\Ui;
/**
* Class GetCreateTransaction
......
......@@ -4,6 +4,7 @@ namespace Trilix\CrefoPay\Gateway\Command;
use Magento\Payment\Gateway\Command\CommandException;
use Magento\Payment\Gateway\CommandInterface;
use Magento\Payment\Gateway\Helper\SubjectReader;
use Magento\Payment\Gateway\Response\HandlerInterface;
use Trilix\CrefoPay\Client\Request\ReserveRequestFactory;
use Trilix\CrefoPay\Client\Transport;
use Trilix\CrefoPay\Model\TransactionService;
......@@ -25,6 +26,11 @@ class Reserve implements CommandInterface
*/
private $transactionService;
/**
* @var HandlerInterface
*/
private $handler;
/**
* @var string
*/
......@@ -32,22 +38,24 @@ class Reserve implements CommandInterface
/**
* Reserve constructor.
*
* @param Transport $transport
* @param ReserveRequestFactory $reserveRequestFactory
* @param TransactionService $transactionService
* @param string $methodCode
* @param HandlerInterface|null $handler\
*/
public function __construct(
Transport $transport,
ReserveRequestFactory $reserveRequestFactory,
TransactionService $transactionService,
string $methodCode
string $methodCode,
HandlerInterface $handler = null
) {
$this->transport = $transport;
$this->reserveRequestFactory = $reserveRequestFactory;
$this->transactionService = $transactionService;
$this->methodCode = $methodCode;
$this->handler = $handler;
}
/**
......@@ -58,15 +66,23 @@ class Reserve implements CommandInterface
*/
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);
if ($this->handler) {
$this->handler->handle(
$commandSubject,
[]
);
}
} catch (\Exception $e) {
throw new CommandException(
!empty($e->getMessage())
......
......@@ -15,7 +15,6 @@ class Config extends \Magento\Payment\Gateway\Config\Config
const KEY_ENVIRONMENT = 'environment';
const KEY_PUBLIC_TOKEN = 'public_token';
const KEY_IS_B2B_ENABLED = 'is_b2b_enabled';
const KEY_IS_AUTO_CAPTURE_ENABLED = 'auto_capture';
const KEY_RISK_CLASS = 'risk_class';
/**
......@@ -93,14 +92,6 @@ class Config extends \Magento\Payment\Gateway\Config\Config
return (string) $this->getValue(self::KEY_IS_B2B_ENABLED);
}
/**
* @return string
*/
public function isAutoCaptureEnabled(): bool
{
return (bool) $this->getValue(self::KEY_IS_AUTO_CAPTURE_ENABLED);
}
/**
* @return int
*/
......
......@@ -42,7 +42,7 @@ class PersonBuilder
$person->setEmail($email);
$person->setFaxNumber($address->getFax());
$person->setPhoneNumber($this->getPhone($address));
$person->setDateOfBirth($this->getDob($customer));
$this->setDateOfBirth($person, $customer);
return $person;
}
......@@ -91,16 +91,15 @@ class PersonBuilder
}
/**
* @param Person $person
* @param \Magento\Customer\Api\Data\CustomerInterface|Customer|null $customer
*
* @return \DateTime|null
*/
private function getDob($customer)
private function setDateOfBirth(Person $person, $customer)
{
if (!$customer) {
return new \DateTime();
if (!$customer || !$customer->getDob()) {
return;
}
return new \DateTime($customer->getDob());
$person->setDateOfBirth(new \DateTime($customer->getDob()));
}
}
<?php
namespace Trilix\CrefoPay\Gateway\Response;
use Magento\Vault\Api\Data\PaymentTokenFactoryInterface;
use Magento\Vault\Api\Data\PaymentTokenInterface;
use Magento\Framework\Intl\DateTimeFactory;
use Upg\Library\Request\Objects\PaymentInstrument;
class CrefoPayPaymentTokenFactory
{
const TOKEN_TYPE_DIRECT_DEBIT = 'crefopay_direct_debit';
/**
* @var PaymentTokenFactoryInterface
*/
private $paymentTokenFactory;
/**
* @var DateTimeFactory
*/
private $dateTimeFactory;
/**
* CrefoPayPaymentTokenFactory constructor.
* @param PaymentTokenFactoryInterface $paymentTokenFactory
* @param DateTimeFactory $dateTimeFactory
*/
public function __construct(PaymentTokenFactoryInterface $paymentTokenFactory, DateTimeFactory $dateTimeFactory)
{
$this->paymentTokenFactory = $paymentTokenFactory;
$this->dateTimeFactory = $dateTimeFactory;
}
/**
* @param PaymentInstrument $paymentInstrument
* @return PaymentTokenInterface|null
* @throws \Exception
*/
public function create(PaymentInstrument $paymentInstrument)
{
$paymentToken = null;
switch ($paymentInstrument->getPaymentInstrumentType()) {
case PaymentInstrument::PAYMENT_INSTRUMENT_TYPE_BANK:
$paymentToken = $this->createBankAccountToken($paymentInstrument);
break;
case PaymentInstrument::PAYMENT_INSTRUMENT_TYPE_CARD:
$paymentToken = $this->createCreditCardToken($paymentInstrument);
break;
}
return $paymentToken;
}
/**