Skip to content
This repository has been archived by the owner on Nov 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #11 from heidelpay/integration-1.0.0
Browse files Browse the repository at this point in the history
Integration 1.0.0
  • Loading branch information
Sascha authored Jun 29, 2020
2 parents 7e8c029 + b7ab07d commit 04c105a
Show file tree
Hide file tree
Showing 174 changed files with 4,109 additions and 471 deletions.
6 changes: 2 additions & 4 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
src/Resources/public/storefront/js/*
src/Resources/public/administration/js/*
src/Resources/dist/*
coverage/
src/Resources/public
src/Resources/app/**/dist
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
vendor
.phpunit.result.cache
.idea
.package-lock.json

package-lock.json
cypress.json
node_modules
21 changes: 19 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ variables:
MYSQL_USER: shopware
MYSQL_PASSWORD: shopware
PLUGIN_NAME: HeidelPayment6
SHOPWARE_VERSION: "6.1" # Tag
SHOPWARE_VERSION: "v6.2.0" # Tag

cache:
key: "$PLUGIN_NAME-$CI_COMMIT_REF_SLUG"
Expand All @@ -36,6 +36,7 @@ phpstan:
- composer
script:
- git clone -b ${SHOPWARE_VERSION} https://github.com/shopware/development "${CI_PROJECT_DIR}/opt/shopware"
- rm -rf "${CI_PROJECT_DIR}/opt/shopware/platform"
- git clone -b ${SHOPWARE_VERSION} https://github.com/shopware/platform "${CI_PROJECT_DIR}/opt/shopware/platform"
- mv ${CI_PROJECT_DIR}/opt /tmp/opt
- cp -r ${CI_PROJECT_DIR} /tmp/opt/shopware/custom/plugins/${PLUGIN_NAME}
Expand All @@ -55,13 +56,29 @@ codestyle:
key: global
paths:
- .php_cs.cache

package:
image: kellerkinder/shopware-package-plugin:latest
stage: package
only:
- tags
- master
services:
- mysql:5.7
script:
- mkdir /tmp/opt
- git clone -b ${SHOPWARE_VERSION} --depth 1 https://github.com/shopware/production /tmp/opt/shopware
- cp -r ${CI_PROJECT_DIR} /tmp/opt/shopware/custom/plugins/${CI_PROJECT_NAME}
- cd /tmp/opt/shopware && composer install --no-interaction -o
- cd /tmp/opt/shopware && php bin/console system:setup --database-url=mysql://${MYSQL_USER}:${MYSQL_PASSWORD}@mysql:3306/${MYSQL_DATABASE} --generate-jwt-keys -nq
- cd /tmp/opt/shopware && php bin/console system:install -fnq --create-database
- cd /tmp/opt/shopware && php bin/console plugin:refresh -nq && php bin/console plugin:install --activate -c ${CI_PROJECT_NAME} -nq
- cd /tmp/opt/shopware && bin/build-js.sh
- cd /tmp/opt/shopware && php bin/console theme:compile -nq
- rsync -r /tmp/opt/shopware/custom/plugins/${CI_PROJECT_NAME}/ ${CI_PROJECT_DIR}/
- cd ${CI_PROJECT_DIR} && git add -f .
- package-plugin
artifacts:
paths:
- $PLUGIN_NAME.zip
- ${CI_PROJECT_NAME}.zip

2 changes: 0 additions & 2 deletions bin/js_cs-fix.sh

This file was deleted.

2 changes: 0 additions & 2 deletions bin/php_cs-fix.sh

This file was deleted.

1 change: 0 additions & 1 deletion bin/phpstan.sh

This file was deleted.

8 changes: 7 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "heidel/payment6",
"description": "Heidelpay payment integration for Shopware 6",
"version": "v1.0.0",
"version": "v0.0.1",
"type": "shopware-platform-plugin",
"license": "Commercial",
"minimum-stability": "dev",
Expand Down Expand Up @@ -58,5 +58,11 @@
"conflict": {
"shopware/storefront": "<6,>=7",
"shopware/administration": "<6,>=7"
},
"scripts": {
"phpcs": "vendor/bin/php-cs-fixer fix",
"phpunit": "vendor/bin/phpunit",
"phpstan": "vendor/bin/phpstan analyse -c phpstan.neon src --autoload-file=../../../vendor/autoload.php",
"phpunit-coverage": "vendor/bin/phpunit --coverage-html ./coverage"
}
}
12 changes: 12 additions & 0 deletions cypress.json.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"baseUrl": "http://heidelpay.local",
"integrationFolder": "tests/cypress/integration",
"fixturesFolder": "tests/cypress/fixtures",
"componentFolder": "tests/cypress/component",
"pluginsFile": "tests/cypress/plugins",
"supportFile": "tests/cypress/support",
"videosFolder": "cypress/videos",
"screenshotsFolder": "cypress/screenshots",
"chromeWebSecurity": false,
"watchForFileChanges": false
}
13 changes: 13 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"scripts": {
"cypress:open": "./node_modules/.bin/cypress open",
"cypress:run": "./node_modules/.bin/cypress run --record false --config video=false",
"eslint:lint": "../../../vendor/shopware/platform/src/Administration/Resources/app/administration/node_modules/.bin/eslint -c ../../../vendor/shopware/platform/src/Administration/Resources/app/administration/.eslintrc.js --rulesdir . --ext .js,.vue src",
"eslint:fix": "../../../vendor/shopware/platform/src/Administration/Resources/app/administration/node_modules/.bin/eslint -c ../../../vendor/shopware/platform/src/Administration/Resources/app/administration/.eslintrc.js --rulesdir . --ext .js,.vue src --fix"
},
"devDependencies": {
"cypress": "^4.7.0",
"cypress-pipe": "^1.7.0"
}
}
111 changes: 74 additions & 37 deletions src/Commands/RegisterWebhookCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,33 @@

namespace HeidelPayment6\Commands;

use HeidelPayment6\Components\ClientFactory\ClientFactoryInterface;
use HeidelPayment6\Components\WebhookRegistrator\WebhookRegistrator;
use heidelpayPHP\Exceptions\HeidelpayApiException;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\System\SalesChannel\Aggregate\SalesChannelDomain\SalesChannelDomainEntity;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\Router;
use Throwable;

class RegisterWebhookCommand extends Command
{
private const EXIT_CODE_SUCCESS = 0;
private const EXIT_CODE_API_ERROR = 1;
private const EXIT_CODE_UNKNOWN_ERROR = 2;
private const EXIT_CODE_INVALID_HOST = 3;
/** @var WebhookRegistrator */
private $webhookRegistrator;

/** @var ClientFactoryInterface */
private $clientFactory;
/** @var EntityRepositoryInterface */
private $domainRepository;

/** @var Router */
private $router;

public function __construct(ClientFactoryInterface $clientFactory, Router $router)
public function __construct(WebhookRegistrator $webhookRegistrator, EntityRepositoryInterface $domainRepository)
{
$this->clientFactory = $clientFactory;
$this->router = $router;
$this->webhookRegistrator = $webhookRegistrator;
$this->domainRepository = $domainRepository;

parent::__construct();
}
Expand All @@ -51,40 +50,78 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$style = new SymfonyStyle($input, $output);
$style = new SymfonyStyle($input, $output);
$domain = $this->handleDomain($input->getArgument('host') ?? '', $style);

if (null === $domain) {
return WebhookRegistrator::EXIT_CODE_INVALID_HOST;
}

try {
$client = $this->clientFactory->createClient();
$client->deleteAllWebhooks();
$domainDataBag = new RequestDataBag([
new RequestDataBag([
'id' => $domain->getId(),
'url' => $domain->getUrl(),
]),
]);

$this->webhookRegistrator->clearWebhooks($domainDataBag);
$result = $this->webhookRegistrator->registerWebhook($domainDataBag);
} catch (HeidelpayApiException $exception) {
$style->error($exception->getMerchantMessage());

return WebhookRegistrator::EXIT_CODE_API_ERROR;
} catch (Throwable $exception) {
$style->error($exception->getMessage());

return WebhookRegistrator::EXIT_CODE_UNKNOWN_ERROR;
}

$host = parse_url($input->getArgument('host'));
if (empty($result)) {
return WebhookRegistrator::EXIT_CODE_API_ERROR;
}

if (empty($host['host']) || empty($host['scheme'])) {
$style->warning('The provided host is invalid.');
$style->success(
sprintf('The webhooks have been registered to the following URL: %s', $input->getArgument('host') ?? '')
);

return self::EXIT_CODE_INVALID_HOST;
}
return WebhookRegistrator::EXIT_CODE_SUCCESS;
}

$context = $this->router->getContext();
$context->setHost($host['host']);
$context->setScheme($host['scheme']);
protected function handleDomain(string $providedHost, SymfonyStyle $style): ?SalesChannelDomainEntity
{
$parsedHost = parse_url($providedHost);

$url = $this->router->generate('heidelpay.webhook.execute', [], UrlGeneratorInterface::ABSOLUTE_URL);
if (!is_array($parsedHost) ||
(is_array($parsedHost) && (empty($parsedHost['host']) || empty($parsedHost['scheme'])))) {
$style->warning('The provided host is invalid.');

$result = $client->createWebhook($url, 'all');
$message = sprintf('The webhooks have been registered to the following URL: %s', $result->getUrl());
return null;
}

$style->success($message);
} catch (HeidelpayApiException $exception) {
$style->error($exception->getMerchantMessage());
$salesChannelDomain = $this->getSalesChannelByHost($providedHost);

return self::EXIT_CODE_API_ERROR;
} catch (Throwable $exception) {
$style->error($exception->getMessage());
if (null === $salesChannelDomain) {
$style->warning('The provided host does not exist in any saleschannel.');

$possibleDomains = [];
/** @var SalesChannelDomainEntity $salesChannelDomain */
foreach ($this->domainRepository->search(new Criteria(), Context::createDefaultContext()) as $domainResult) {
$possibleDomains[] = [$domainResult->getUrl()];
}

return self::EXIT_CODE_UNKNOWN_ERROR;
$style->table(['Possible domains'], $possibleDomains);
}

return self::EXIT_CODE_SUCCESS;
return $salesChannelDomain;
}

protected function getSalesChannelByHost(string $url): ?SalesChannelDomainEntity
{
$domainCriteria = new Criteria();
$domainCriteria->addFilter(new EqualsFilter('url', $url));
$salesChannelResult = $this->domainRepository->search($domainCriteria, Context::createDefaultContext());
/** @var null|SalesChannelDomainEntity $firstResult */
return $salesChannelResult->first();
}
}
18 changes: 18 additions & 0 deletions src/Components/AbstractHeidelPaymentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace HeidelPayment6\Components;

use Exception;

abstract class AbstractHeidelPaymentException extends Exception
{
/** @var string */
protected $customerMessage = 'exception/statusMapper';

public function getCustomerMessage(): string
{
return $this->customerMessage;
}
}
7 changes: 4 additions & 3 deletions src/Components/ClientFactory/ClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace HeidelPayment6\Components\ClientFactory;

use HeidelPayment6\Components\ConfigReader\ConfigReader;
use HeidelPayment6\Components\ConfigReader\ConfigReaderInterface;
use heidelpayPHP\Heidelpay;
use heidelpayPHP\Interfaces\DebugHandlerInterface;
Expand All @@ -26,8 +27,8 @@ public function createClient(string $salesChannelId = '', string $locale = self:
{
$config = $this->configReader->read($salesChannelId);

$client = new Heidelpay($config->get('privateKey'), $locale);
$client->setDebugMode((bool) $config->get('extendedLogging'));
$client = new Heidelpay($config->get(ConfigReader::CONFIG_KEY_PRIVATE_KEY), $locale);
$client->setDebugMode((bool) $config->get(ConfigReader::CONFIG_KEY_EXTENDED_LOGGING));
$client->setDebugHandler($this->debugHandler);

return $client;
Expand All @@ -38,7 +39,7 @@ public function createClientFromPrivateKey(string $privateKey, string $locale =
$config = $this->configReader->read();

$client = new Heidelpay($privateKey, $locale);
$client->setDebugMode((bool) $config->get('extendedLogging'));
$client->setDebugMode((bool) $config->get(ConfigReader::CONFIG_KEY_EXTENDED_LOGGING));
$client->setDebugHandler($this->debugHandler);

return $client;
Expand Down
16 changes: 15 additions & 1 deletion src/Components/ConfigReader/ConfigReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ class ConfigReader implements ConfigReaderInterface
/** @var string */
public const SYSTEM_CONFIG_DOMAIN = 'HeidelPayment6.settings.';

public const CONFIG_KEY_PUBLIC_KEY = 'publicKey';
public const CONFIG_KEY_PRIVATE_KEY = 'privateKey';
public const CONFIG_KEY_TEST_MODE = 'testMode';
public const CONFIG_KEY_EXTENDED_LOGGING = 'extendedLogging';
public const CONFIG_KEY_BOOKINMODE_CARD = 'bookingModeCreditCard';
public const CONFIG_KEY_REGISTER_CARD = 'registerCreditCard';
public const CONFIG_KEY_BOOKINMODE_PAYPAL = 'bookingModePayPal';
public const CONFIG_KEY_REGISTER_PAYPAL = 'registerPayPal';
public const CONFIG_KEY_REGISTER_DIRECT_DEBIT = 'registerDirectDebit';
public const CONFIG_KEY_SHIPPING_STATUS = 'statusForAutomaticShippingNotification';

/** @var SystemConfigService */
private $systemConfigService;

Expand All @@ -33,7 +44,10 @@ public function read(string $salesChannelId = '', bool $fallback = true): Config
foreach ($values as $key => $value) {
$property = substr($key, strlen(self::SYSTEM_CONFIG_DOMAIN));

$config[$property] = $value;
if ($property) {
/** @var string $property */
$config[$property] = $value;
}
}

return new Configuration($config);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace HeidelPayment6\Components\DependencyInjection\Factory;

use HeidelPayment6\Components\PaymentTransitionMapper\AbstractTransitionMapper;
use HeidelPayment6\Components\PaymentTransitionMapper\Exception\NoTransitionMapperFoundException;
use heidelpayPHP\Resources\PaymentTypes\BasePaymentType;

class PaymentTransitionMapperFactory
{
/** @var AbstractTransitionMapper[]|iterable */
protected $transitionMapperCollection = [];

public function __construct(iterable $transitionMapperCollection)
{
$this->transitionMapperCollection = $transitionMapperCollection;
}

public function getTransitionMapper(BasePaymentType $paymentType): AbstractTransitionMapper
{
foreach ($this->transitionMapperCollection as $transitionMapper) {
if ($transitionMapper->supports($paymentType)) {
return $transitionMapper;
}
}

throw new NoTransitionMapperFoundException($paymentType::getResourceName());
}
}
Loading

0 comments on commit 04c105a

Please sign in to comment.