Commit 72de71a2 authored by Daniel Kazior's avatar Daniel Kazior 💰
Browse files

Release Version 1.0.3

parent 2747a0fc
# Ignored files
\ No newline at end of file
# Changelog
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]
## [Known issues]
- Default Risk Class is set to Trusted instead of Default after installing
<!-- ## [Unreleased] -->
## [1.0.3] - 2020-01-30
### Changed in [1.0.3]
- Structural adaption to prepare composer installation/update support for unreleased version 1.1.x
- Structural adaption to make changelog following md formatting guide line
### Fixed in [1.0.3]
## [Unreleased]
- Invalid Token bug has been completely fixed
## [1.0.2] - 2020-01-13
### Added in [1.0.2]
- Debugging info for communication between Magento and CrefoPay
### Fixed in [1.0.2]
- Checkout errors: Invalid Token
- An error when uncheck/check "My billing and shipping address are the same" on the Payments Step during Checkout
## [1.0.1] - 2019-12-12
### Added in [1.0.1]
- Partial captures and refunds are now supported
### Changed in [1.0.1]
- If some inputs in our secure fields are invalid, we now display the errors below them
- The secure fields library was updated based on the official version
## Fixed in [1.0.1]
- Internet Explorer 11 now finds the selected payment method again
- Some cases of a one cent difference were fixed
- The error handling for reservation errors was improved to stop sideeffects with other modules
- Phone numbers and fax numbers should be less often denied by the API
- An error after the install of the module was fixed regarding the environment setting
- The module is now compatible with Magento 2.3.3
- Any redirect payment method now sets the payment transaction to pending until the user authorized the payment and returned
## [1.0.1] - 2019-12-12
### Added
......@@ -23,7 +69,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Any redirect payment method now sets the payment transaction to pending until the user authorized the payment and returned
## [1.0.0] - 2019-10-04
### Fixed
### Fixed in [1.0.0]
- EXPIRED notifications now increase stock of products when they are cancelling an order
- Reorder link now works on Magento 2.3.2 again
- Suspected Fraud status is now circumvented when the module captures automatically after a MERCHANTPENDING notification is received
......@@ -36,10 +84,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- IBANs with non-numeric characters after the first 4 are now able to be input
## [0.9.4] - 2019-06-04
### Added
### Added in [0.9.4]
- Added a setting to do an automatic capture based on categories
### Fixed
### Fixed in [0.9.4]
- Error messages in the frontend no longer default to an empty string in some cases
- Translations for all the translatable module strings were added
- Help texts for the module configuration were added
......@@ -48,12 +99,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- AutoCapture per payment method now works with a 0 amount in the notification (#9)
- AutoCapture category setting is now saved under the right config path
## [0.9.3-mnshandling] - 2019-05-02
### Fixed
- The MNS handling no longer throws an error when an order was paid with CrefoPay
## [0.9.3] - 2019-04-04 / 2019-05-02
## [0.9.3] - 2019-04-04
### Fixed
### Fixed in [0.9.3]
- The MNS handling no longer throws an error when an order was paid with CrefoPay
- 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
......@@ -63,12 +113,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- 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)
## [0.9.2] - 2019-03-22 / 2019-03-26
## [0.9.2] - 2019-03-22
### Fixed
### Fixed in [0.9.2]
- Customers can now pay with another payment method after getting rejected by solvency checks (#6)
- 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
......@@ -79,14 +128,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- 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
### Added in [0.9.2]
- 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
### Added in [0.9.1]
- Asynchronous Processing for CrefoPay notifications via Magento Cron
- Gender and date of birth will be asked for when needed
- Added command to specifically process the CrefoPay notifications
## [0.9] - 2018-12-21
- Initial release
\ No newline at end of file
- Initial release
<?php
namespace Trilix\CrefoPay\Client;
use Upg\Library\Config as CrefoPayConfig;
......@@ -26,10 +27,13 @@ class ConfigFactory
public function create(): CrefoPayConfig
{
$crefoPayConfig = new CrefoPayConfig([
'merchantID' => $this->gatewayConfig->getMerchantId(),
'merchantPassword' => $this->gatewayConfig->getMerchantPassword(),
'storeID' => $this->gatewayConfig->getStoreId(),
'baseUrl' => $this->gatewayConfig->getBaseUrl(),
'merchantID' => $this->gatewayConfig->getMerchantId(),
'merchantPassword' => $this->gatewayConfig->getMerchantPassword(),
'storeID' => $this->gatewayConfig->getStoreId(),
'baseUrl' => $this->gatewayConfig->getBaseUrl(),
'logEnabled' => true,
'logLocationRequest' => 'var/log/crefopay.log',
'logLevel' => 100,
]);
return $crefoPayConfig;
......
<?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 Consume 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);
}
/**
* @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->consume($_POST);
return $result;
}
}
......@@ -40,18 +40,20 @@ class GetCreateTransaction extends Action
{
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
$resultJson = $this->resultJsonFactory->create();
$quoteId = $this->getRequest()->getParam('quoteId');
$allowedPaymentMethods = '[]';
try {
$crefoPayTransaction = $this->crefoPayTransactionRepository->getByQuoteId($quoteId);
$crefoPayOrderId = $crefoPayTransaction->getCrefoPayOrderId();
$allowedPaymentMethods = $crefoPayTransaction->getPaymentMethods();
} catch (NoSuchEntityException $e) {
$crefoPayOrderId = null;
}
return $resultJson->setData([
'crefoPayOrderId' => $crefoPayOrderId,
'areAnyPaymentMethodsAllowed' => ($allowedPaymentMethods !== '[]')
]);
}
}
......@@ -56,15 +56,18 @@ class GuestGetCreateTransaction extends Action
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id');
$quoteId = $quoteIdMask->getQuoteId();
$allowedPaymentMethods = '[]';
try {
$crefoPayTransaction = $this->crefoPayTransactionRepository->getByQuoteId($quoteId);
$crefoPayOrderId = $crefoPayTransaction->getCrefoPayOrderId();
$allowedPaymentMethods = $crefoPayTransaction->getPaymentMethods();
} catch (NoSuchEntityException $e) {
$crefoPayOrderId = null;
}
return $resultJson->setData([
'crefoPayOrderId' => $crefoPayOrderId,
'areAnyPaymentMethodsAllowed' => ($allowedPaymentMethods !== '[]')
]);
}
}
<?php
declare(strict_types=1);
namespace Trilix\CrefoPay\Gateway\Config;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
......@@ -128,7 +130,7 @@ class Config extends \Magento\Payment\Gateway\Config\Config
*/
public function isB2BEnabled(): bool
{
return (string) $this->getValue(self::KEY_IS_B2B_ENABLED);
return (bool) $this->getValue(self::KEY_IS_B2B_ENABLED);
}
/**
......@@ -222,7 +224,12 @@ class Config extends \Magento\Payment\Gateway\Config\Config
*/
public function getAutoCaptureCategoryIds(): array
{
return array_filter(explode(',', $this->getValue(self::KEY_AUTO_CAPTURE_CATEGORIES)));
$autoCaptureCategories = $this->getValue(self::KEY_AUTO_CAPTURE_CATEGORIES);
$result = [];
if ($autoCaptureCategories) {
$result = array_filter(explode(',', $autoCaptureCategories));
}
return $result;
}
/**
......
<?php
namespace Trilix\CrefoPay\Gateway\Request;
use Magento\Quote\Model\Quote\Item;
use Upg\Library\Request\Objects\BasketItem;
use Upg\Library\Request\Objects\Amount;
class BasketItemBuilder
{
/**
* @param Item $item
* @return BasketItem
*/
public function build(Item $item): BasketItem
{
$basketItem = new BasketItem();
$basketItemAmount = new Amount();
$basketItemAmount->setAmount(ceil($item->getRowTotal() * 100));
$basketItem->setBasketItemText($item->getName());
$basketItem->setBasketItemCount($item->getQty());
$basketItem->setBasketItemAmount($basketItemAmount);
return $basketItem;
}
}
......@@ -29,7 +29,7 @@ class CiaPending extends AbstractConsumer implements MnsConsumerInterface
* @param MnsEvent $event
*
* @throws \Magento\Framework\Exception\LocalizedException
* @throws \Trilix\CrefoPay\Mns\Consumers\MnsConsumerException
* @throws MnsConsumerException
*/
public function process(MnsEvent $event)
{
......@@ -46,4 +46,4 @@ class CiaPending extends AbstractConsumer implements MnsConsumerInterface
$this->orderHelper->getOrderRepository()->save($order);
}
}
\ No newline at end of file
}
......@@ -70,7 +70,6 @@ class PaymentMethodManagementPlugin
$response = $this->transport->sendRequest($createTransactionRequest);
$allowedPaymentMethods = Json::encode($response->getData('allowedPaymentMethods'));
} catch (\Exception $e) {
// @todo add logging
$allowedPaymentMethods = '[]';
}
......@@ -78,4 +77,3 @@ class PaymentMethodManagementPlugin
$this->crefoPayTransactionRepository->save($paymentMethods);
}
}
<?php
namespace Trilix\CrefoPay\Test\Unit\Client\Request;
use Trilix\CrefoPay\Client\Request\CancelRequestFactory;
class CancelRequestFactoryTest extends AbstractRequestFactoryTest
{
public function testCreate()
{
$orderId = 123;
/** @var CancelRequestFactory $uut */
$uut = $this->getUut(CancelRequestFactory::class);
$cancelRequest = $uut->create($orderId);
$this->assertEquals($orderId, $cancelRequest->getOrderID());
}
}
......@@ -19,50 +19,50 @@ use Magento\Framework\Locale\ResolverInterface as Locale;
class CreateTransactionRequestFactoryTest extends AbstractRequestFactoryTest
{
/**
* @param $isCompanyAddressExpected
* @param string $companyAddress
* @param $userType
*
* @throws \Magento\Framework\Exception\NoSuchEntityException
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
* @dataProvider createDataProvider
*/
public function testCreate($isCompanyAddressExpected, $userType, $storeLocale, $expectedCrefoPayLocale)
public function testCreate($companyAddress, $userType, $storeLocale, $expectedCrefoPayLocale)
{
$billingAddressMock = $this->getAddressMock();
$billingAddressMock
->expects($this->any())
->method('getCompany')
->willReturn($isCompanyAddressExpected);
->willReturn($companyAddress);
$shippingAddressMock = $this->getAddressMock();
$shippingAddressMock
->expects($this->any())
->expects($this->once())
->method('getEmail')
->willReturn('');
$quoteMock = $this->createMock(Quote::class);
$quoteMock
->expects($this->any())
->expects($this->once())
->method('getBillingAddress')
->willReturn($billingAddressMock);
$quoteMock
->expects($this->any())
->expects($this->once())
->method('getShippingAddress')
->willReturn($shippingAddressMock);
$quoteMock
->expects($this->any())
->method('getAllItems')
->willReturn([]);
->expects($this->once())
->method('isVirtual')
->willReturn(false);
$quoteRepositoryMock = $this->createMock(CartRepositoryInterface::class);
$quoteRepositoryMock
->expects($this->any())
->expects($this->once())
->method('getActive')
->willReturn($quoteMock);
......@@ -76,21 +76,21 @@ class CreateTransactionRequestFactoryTest extends AbstractRequestFactoryTest
$crefoPayUserFactoryMock = $this->createMock(CrefoPayUserFactory::class);
$crefoPayUserFactoryMock
->expects($this->any())
->expects($this->once())
->method('create')
->willReturn($crefoPayUserMock);
$companyBuilderMock = $this->createMock(CompanyBuilder::class);
$companyBuilderMock
->expects($this->any())
->expects($companyAddress && $userType === CreateTransactionRequest::USER_TYPE_BUSINESS ? $this->once() : $this->never())
->method('build')
->willReturn(new Company());
$localeMock = $this->createMock(Locale::class);
$localeMock
->expects($this->any())
->expects($this->once())
->method('getLocale')
->willReturn($storeLocale);
......@@ -110,7 +110,7 @@ class CreateTransactionRequestFactoryTest extends AbstractRequestFactoryTest
$createTransactionRequest = $uut->create('1');
if ($isCompanyAddressExpected) {
if ($companyAddress) {
$this->assertInstanceOf(Company::class, $createTransactionRequest->getCompanyData());
} else {
$this->assertNull($createTransactionRequest->getCompanyData());
......@@ -122,8 +122,8 @@ class CreateTransactionRequestFactoryTest extends AbstractRequestFactoryTest
public function createDataProvider()
{
return [
[true, CreateTransactionRequest::USER_TYPE_BUSINESS, 'nl_BE', 'NL'],
[false, CreateTransactionRequest::USER_TYPE_PRIVATE, 'uk_UA', 'EN'],
['company address', CreateTransactionRequest::USER_TYPE_BUSINESS, 'nl_BE', 'NL'],
['', CreateTransactionRequest::USER_TYPE_PRIVATE, 'uk_UA', 'EN'],
];
}
......@@ -132,7 +132,7 @@ class CreateTransactionRequestFactoryTest extends AbstractRequestFactoryTest
$addressMock = $this->createMock(Address::class);
$addressMock
->expects($this->any())
->expects($this->once())
->method('getStreet')
->willReturn([]);
......
......@@ -12,13 +12,22 @@ class ReserveRequestFactoryTest extends AbstractRequestFactoryTest
* @param string $paymentMethod
* @param PaymentDataObjectInterface $paymentDO
* @param bool $isPaymentInstrumentIdExpected
* @param bool $isAdditionalInfoExpected
*
* @throws \Upg\Library\Serializer\Exception\VisitorCouldNotBeFound
* @dataProvider createDataProvider
*/
public function testCreate(string $paymentMethod, PaymentDataObjectInterface $paymentDO, bool $isPaymentInstrumentIdExpected)
public function testCreate(string $paymentMethod, PaymentDataObjectInterface $paymentDO, bool $isPaymentInstrumentIdExpected, bool $isAdditionalInfoExpected)
{
$amountBuilderMock = $this->createMock(\Trilix\CrefoPay\Gateway\Request\AmountBuilder::class);
$amountBuilderMock
->expects($this->once())
->method('buildFromOrder')
->willReturn(new \Upg\Library\Request\Objects\Amount());
/** @var ReserveRequestFactory $uut */
$uut = $this->getUut(ReserveRequestFactory::class);
$uut = $this->getUut(ReserveRequestFactory::class, ['amountBuilder' => $amountBuilderMock]);
$reserveRequest = $uut->create($paymentMethod, $paymentDO);
if ($isPaymentInstrumentIdExpected) {
......@@ -26,17 +35,25 @@ class ReserveRequestFactoryTest extends AbstractRequestFactoryTest
} else {
$this->assertNull($reserveRequest->getPaymentInstrumentID());
}
if ($isAdditionalInfoExpected) {
$additionalInfo = new \Trilix\CrefoPay\Client\Request\Structure\AdditionalInfo([
\Trilix\CrefoPay\Client\Request\Structure\AdditionalInfo::DATE_OF_BIRTH => $this->getDateOfBirth()
]);
$this->assertTrue((string)$additionalInfo === $reserveRequest->getAdditionalInformation());
}
}
public function createDataProvider()
{
return [
['', $this->createDO(false), false],
['', $this->createDO(true), true],
['', $this->createDO(false, true), false, true],
['', $this->createDO(true, false), true, false],
];
}
private function createDO(bool $isPaymentInstrumentIdExpected)
private function createDO(bool $isPaymentInstrumentIdExpected, bool $isAdditionalInfoExpected)
{
$paymentDOMock = $this->createMock(PaymentDataObjectInterface::class);
$orderMock = $this->createMock(OrderAdapterInterface::class);
......@@ -46,19 +63,34 @@ class ReserveRequestFactoryTest extends AbstractRequestFactoryTest
->method('getOrder')
->willReturn($orderMock);
$additionalInformation = [];
if ($isPaymentInstrumentIdExpected) {
$additionalInformation['paymentInstrumentId'] = 'payment instrument id';
}
if ($isAdditionalInfoExpected) {
$additionalInformation[\Trilix\CrefoPay\Client\Request\Structure\AdditionalInfo::DATE_OF_BIRTH] = $this->getDateOfBirth();
$additionalInformation['something_else'] = 'random value';
}
$paymentMock = $this->createMock(PaymentInfoInterface::class);
$paymentMock
->expects($this->any())
->expects($this->once())
->method('getAdditionalInformation')
->with('paymentInstrumentId')
->willReturn($isPaymentInstrumentIdExpected ? 'payment instrument id' : null);
->willReturn($additionalInformation);
$paymentDOMock
->expects($this->any())
->expects($this->once())
->method('getPayment')
->willReturn($paymentMock);
return $paymentDOMock;
}
}
\ No newline at end of file
private function getDateOfBirth()
{
return '01-01-1980';
}
}
<?php
namespace Trilix\CrefoPay\Test\Unit\Client\Request\Structure;
use Trilix\CrefoPay\Client\Request\Structure\AdditionalInfo;
class AdditionalInfoTest extends \Trilix\CrefoPay\Test\Unit\Framework\TestCase
{
public function testNewInstance()
{
$uut = new AdditionalInfo(['wrong_field' => 'wrong_value', AdditionalInfo::DATE_OF_BIRTH => 'dob']);
$this->assertEquals('{"dateOfBirth":"dob"}', (string)$uut);
}
public function testHasData()
{
$uut = new AdditionalInfo([AdditionalInfo::DATE_OF_BIRTH => 'dob']);
$this->assertTrue($uut->hasData());
$uut = new AdditionalInfo(['wrong_field' => 'wrong_value']);
$this->assertFalse($uut->hasData());
}
}
......@@ -20,9 +20,9 @@ class SinkTest extends \PHPUnit\Framework\TestCase
$contextMock = $this->createPartialMock(\Magento\Framework\App\Action\Context::class, ['getResultFactory']);
$contextMock->expects($this->once())->method('getResultFactory')->willReturn($resultFactoryMock);
$mnsServiceMock = $this->createPartialMock(\Trilix\CrefoPay\Model\Mns\MnsService::class, ['acknowledge']);
$mnsServiceMock->expects($this->once())->method();
$mnsServiceMock->expects($this->once())->method('acknowledge');
$sink = new Sink($contextMock, $mnsServiceMock);
$result = $sink->execute();
$this->assertInstanceOf(\Magento\Framework\Controller\ResultInterface::class, $result);
}
}
\ No newline at end of file