Commit a544fc02 authored by Vincent Mrose's avatar Vincent Mrose 💬
Browse files

QA Release of Version 0.9.3

Fixes #5 and #7

Signed-off-by: Vincent Mrose's avatarVincent Mrose <v.mrose@crefopay.de>
parent 7aac4ac9
......@@ -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)
......
......@@ -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;
}
/**
* @param PaymentInstrument $paymentInstrument
* @return PaymentTokenInterface
*/
private function createCreditCardToken(PaymentInstrument $paymentInstrument): PaymentTokenInterface
{
$paymentToken = $this->paymentTokenFactory->create(PaymentTokenFactoryInterface::TOKEN_TYPE_CREDIT_CARD);
$paymentToken->setGatewayToken($paymentInstrument->getPaymentInstrumentID());
$paymentToken->setExpiresAt($paymentInstrument->getValidity());