diff --git a/.github/workflows/analysis.yaml b/.github/workflows/analysis.yaml new file mode 100644 index 00000000..8411f1b8 --- /dev/null +++ b/.github/workflows/analysis.yaml @@ -0,0 +1,86 @@ +name: Analysis +'on': + push: + branches: + - develop + - qa + - master + paths-ignore: + - README.md + pull_request: + paths-ignore: + - README.md +jobs: + analysis: + name: 'PHP ${{ matrix.php }} Symfony ${{ matrix.symfony }}' + runs-on: ubuntu-latest + strategy: + matrix: + php: + - 8.2 + symfony: + - '6.4.*' + env: + APP_ENV: test + steps: + - + uses: actions/checkout@v2 + - + name: 'Setup PHP' + uses: shivammathur/setup-php@v2 + with: + php-version: '${{ matrix.php }}' + tools: symfony + coverage: none + - + name: 'Composer - Get Cache Directory' + id: composer-cache + run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' + - + name: 'Composer - Set cache' + uses: actions/cache@v4 + with: + path: '${{ steps.composer-cache.outputs.dir }}' + key: 'php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles(''**/composer.json'') }}' + restore-keys: "php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-\n" + - + name: 'Composer - Validate composer.json and composer.lock' + run: 'composer validate --strict' + - + name: 'Composer - Github Auth' + run: 'composer config -g github-oauth.github.com ${{ github.token }}' + - + name: 'Composer - Restrict Symfony version' + run: 'composer config extra.symfony.require "${{ matrix.symfony }}"' + - + name: 'Composer - Update dependencies' + run: 'composer update --no-progress' + id: end-of-setup + - + name: 'PHPStan - Run' + run: 'if [ -f ruleset/phpstan.neon ]; then vendor/bin/phpstan analyse -c ruleset/phpstan.neon src/ ; else echo PHPStan rulesets file does not exist, skipping step ; fi' + if: 'always() && steps.end-of-setup.outcome == ''success''' + # TODO: launch Grumphp + + sonarcloud: + if: github.event.repository.fork != true + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v3 + with: + # Disabling shallow clone is recommended for improving relevancy of reporting + fetch-depth: 0 + - name: SonarCloud Scan + uses: sonarsource/sonarcloud-github-action@master + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + projectBaseDir: . + args: > + -Dsonar.organization=${{ secrets.SONAR_ORGA }} + -Dsonar.projectKey=github-payplug-payplug-syliuspayplugplugin + -Dsonar.sources=src/ + -Dsonar.test.exclusions=tests/** + -Dsonar.tests=tests/ + -Dsonar.verbose=true diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index e63065b4..00000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,205 +0,0 @@ -name: CI - -on: - push: - branches: [develop, qa, master] - paths-ignore: - - README.md - pull_request: - paths-ignore: - - README.md - -jobs: - php: - name: PHP ${{ matrix.php }} Symfony ${{ matrix.symfony }} - runs-on: ubuntu-18.04 - - strategy: - fail-fast: false - matrix: - php: [7.4, 8.0] - symfony: [4.4.*, 5.2.*] - - env: - APP_ENV: test - - steps: - - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - tools: symfony - coverage: none - - - name: Composer - Get Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Composer - Set cache - uses: actions/cache@v2 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: | - php-${{ matrix.php }}-symfony-${{ matrix.symfony }}-composer- - - - name: Composer - Validate composer.json and composer.lock - run: composer validate --strict - - - name: Composer - Github Auth - run: composer config -g github-oauth.github.com ${{ github.token }} - - - name: Composer - Restrict Symfony version - run: composer config extra.symfony.require "${{ matrix.symfony }}" - - - name: Composer - Update dependencies - run: composer update --no-progress - id: end-of-setup - -# Disable in cause of error occurs symplify/symplify#2873 -# - name: ECS - Run -# run: if [ -f rulesets/ecs.php ]; then vendor/bin/ecs check src/ tests/Behat/ --no-progress-bar -c rulesets/ecs.php ; else echo Ecs ruleset file does not exist, skipping step ; fi -# if: always() && steps.end-of-setup.outcome == 'success' - - - name: PHPStan - Run - run: if [ -f rulesets/phpstan.neon ]; then vendor/bin/phpstan analyse -c rulesets/phpstan.neon src/ ; else echo PHPStan rulesets file does not exist, skipping step ; fi - if: always() && steps.end-of-setup.outcome == 'success' - - - name: PHPSpec - Run - run: if [ -f phpspec.yml.dist ]; then vendor/bin/phpspec run ; else echo PHPSpec config file does not exist, skipping step ; fi - if: always() && steps.end-of-setup.outcome == 'success' - - - name: Checks security issues - Run - run: symfony security:check - if: always() && steps.end-of-setup.outcome == 'success' - - sylius: - name: PHPUnit-Behat (PHP ${{ matrix.php }} Sylius ${{ matrix.sylius }} Symfony ${{ matrix.symfony }}) - runs-on: ubuntu-18.04 - strategy: - fail-fast: false - matrix: - php: [7.4, 8.0] - sylius: [1.9.0, 1.10.0] - symfony: [4.4, 5.2] - node: [10.x] - exclude: - - sylius: 1.9.0 - php: 8.0 - - sylius: 1.10.0 - symfony: 4.4 - - env: - APP_ENV: test - package-name: payplug/sylius-payplug-plugin - - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: "${{ matrix.php }}" - ini-values: date.timezone=UTC - extensions: intl - tools: symfony - coverage: none - - - name: Setup Node - uses: actions/setup-node@v1 - with: - node-version: "${{ matrix.node }}" - - - name: Wkhtmltopdf - Install - run: | - sudo apt-get update - sudo apt-get install xvfb libfontconfig wkhtmltopdf - printf '#!/bin/bash\nxvfb-run -a --server-args="-screen 0, 1024x768x24" /usr/bin/wkhtmltopdf -q $*' | sudo tee /usr/bin/wkhtmltopdf.sh - sudo chmod a+x /usr/bin/wkhtmltopdf.sh - sudo ln -s /usr/bin/wkhtmltopdf.sh /usr/local/bin/wkhtmltopdf - - - uses: actions/checkout@v2 - - - name: Composer - Get Cache Directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Composer - Set cache - uses: actions/cache@v2 - id: cache-composer - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: php-${{ matrix.php }}-sylius-${{ matrix.sylius }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: php-${{ matrix.php }}-sylius-${{ matrix.sylius }}-symfony-${{ matrix.symfony }}-composer- - - - name: Composer - Create cache directory - run: mkdir -p /home/runner/.composer/cache - if: steps.cache-composer.outputs.cache-hit != 'true' - - - name: Composer - Github Auth - run: composer config -g github-oauth.github.com ${{ github.token }} - - - name: Yarn - Get cache directory - id: yarn-cache - run: echo "::set-output name=dir::$(yarn cache dir)" - - - name: Yarn - Set Cache - uses: actions/cache@v2 - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }} - restore-keys: | - node-${{ matrix.node }}-yarn- - - - name: Install Sylius-Standard and Plugin - run: make install -e SYLIUS_VERSION=${{ matrix.sylius }} SYMFONY_VERSION=${{ matrix.symfony }} - - - name: Output PHP version for Symfony CLI - working-directory: ./tests/Application - run: php -v | head -n 1 | awk '{ print $2 }' > .php-version - - - name: Install certificates - working-directory: ./tests/Application - run: symfony server:ca:install - - - name: Run Chrome headless - working-directory: ./tests/Application - run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' https://127.0.0.1 > /dev/null 2>&1 & - - - name: Run webserver - working-directory: ./tests/Application - run: symfony server:start --port=8080 --dir=public --daemon - id: end-of-setup-sylius - - - name: Doctrine Schema Validate - Run - working-directory: ./tests/Application - run: php bin/console doctrine:schema:validate --skip-sync - if: always() && steps.end-of-setup-sylius.outcome == 'success' - - - name: Run PHPUnit - run: make phpunit - if: always() && steps.end-of-setup-sylius.outcome == 'success' - - - name: Configure Behat - run: make behat-configure - if: always() && steps.end-of-setup-sylius.outcome == 'success' - - - name: Run behat - working-directory: ./tests/Application - run: vendor/bin/behat --strict --no-interaction -f progress || vendor/bin/behat --strict -vvv --no-interaction --rerun - if: always() && steps.end-of-setup-sylius.outcome == 'success' - - - uses: actions/upload-artifact@v2.1.4 - if: failure() - with: - name: logs - path: ./tests/Application/etc/build - - services: - mariadb: - image: mariadb:10.4.11 - ports: - - 3306:3306 - env: - MYSQL_ALLOW_EMPTY_PASSWORD: true - options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3 diff --git a/.github/workflows/jira.yml b/.github/workflows/jira.yml new file mode 100644 index 00000000..45e4e4e8 --- /dev/null +++ b/.github/workflows/jira.yml @@ -0,0 +1,32 @@ +name: CREATE JIRA ISSUE + +on: + issues: + types: [opened, edited] + +jobs: + jira: + name: Create Jira issue + runs-on: ubuntu-latest + steps: + - name: Jira Login + uses: atlassian/gajira-login@master + env: + JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} + JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} + JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} + + - name: Create + id: create + uses: atlassian/gajira-create@master + env: + TITLE_ISSUE: ${{ github.event.issue.title }} + with: + project: SMP + issuetype: Sylius Technical Support + summary: "${{ env.TITLE_ISSUE }} #${{ github.event.issue.number }}" + # Valeur par default "from github" en MVP + fields: '{"customfield_10150": "${{ github.event.issue.html_url }} \n\nCreated from GitHub Action", "customfield_10106": "from github","customfield_10105": "https://www.from-github.fr","customfield_10108": "from github", "customfield_10145": "from github"}' + + - name: Log + run: echo "Created issue ${{ steps.create.outputs.issue }}" diff --git a/.github/workflows/pull_request_template.md b/.github/workflows/pull_request_template.md new file mode 100644 index 00000000..c90cc2c8 --- /dev/null +++ b/.github/workflows/pull_request_template.md @@ -0,0 +1,5 @@ +# ⚠️ Requirements +Reviewer, please take a look at those requirements: + +- [ ] Check that plugin version has been upgrated and are identical in both `composer.json` and `src/PayPlugSyliusPayPlugPlugin.php` files + diff --git a/.github/workflows/sylius.yaml b/.github/workflows/sylius.yaml new file mode 100644 index 00000000..33dc6c31 --- /dev/null +++ b/.github/workflows/sylius.yaml @@ -0,0 +1,105 @@ +name: Sylius +'on': + push: + branches: + - develop + - qa + - master + paths-ignore: + - README.md + pull_request: + paths-ignore: + - README.md +jobs: + sylius: + name: 'PHPUnit-Behat (PHP ${{ matrix.php }} Sylius ${{ matrix.sylius }} Symfony ${{ matrix.symfony }})' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: + - 8.2 + - 8.4 + sylius: + - 2.1.0 + - 2.0.0 + symfony: + - 6.4 + - 7.3 + node: + - 20.x + env: + APP_ENV: test + package-name: payplug/sylius-payplug-plugin + steps: + - + name: 'Setup PHP' + uses: shivammathur/setup-php@v2 + with: + php-version: '${{ matrix.php }}' + ini-values: date.timezone=UTC + extensions: intl + tools: symfony + coverage: none + - + name: 'Setup Node' + uses: actions/setup-node@v3 + with: + node-version: '${{ matrix.node }}' + - + uses: actions/checkout@v3 + - + name: 'Composer - Get Cache Directory' + id: composer-cache + run: 'echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT' + - + name: 'Composer - Set cache' + uses: actions/cache@v4 + id: cache-composer + with: + path: '${{ steps.composer-cache.outputs.dir }}' + key: 'php-${{ matrix.php }}-sylius-${{ matrix.sylius }}-symfony-${{ matrix.symfony }}-composer-${{ hashFiles(''**/composer.json'') }}' + restore-keys: 'php-${{ matrix.php }}-sylius-${{ matrix.sylius }}-symfony-${{ matrix.symfony }}-composer-' + - + name: 'Composer - Create cache directory' + run: 'mkdir -p /home/runner/.composer/cache' + if: 'steps.cache-composer.outputs.cache-hit != ''true''' + - + name: 'Composer - Github Auth' + run: 'composer config -g github-oauth.github.com ${{ github.token }}' + - + name: 'Yarn - Get cache directory' + id: yarn-cache + run: 'echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT' + - + name: 'Yarn - Set Cache' + uses: actions/cache@v4 + with: + path: '${{ steps.yarn-cache.outputs.dir }}' + key: 'node-${{ matrix.node }}-yarn-${{ hashFiles(''**/package.json **/yarn.lock'') }}' + restore-keys: "node-${{ matrix.node }}-yarn-\n" + - + name: 'Install Sylius-Standard and Plugin' + run: 'make install -e SYLIUS_VERSION=${{ matrix.sylius }} SYMFONY_VERSION=${{ matrix.symfony }}' + id: end-of-setup-sylius + - + name: 'Doctrine Schema Validate - Run' + run: 'vendor/bin/console doctrine:schema:validate --skip-sync' + - + name: 'Run PHPUnit' + run: 'make phpunit' + if: 'always() && steps.end-of-setup-sylius.outcome == ''success''' + - + uses: actions/upload-artifact@v4 + if: failure() + with: + name: logs + path: ./tests/Application/etc/build + services: + mariadb: + image: 'mariadb:10.4.11' + ports: + - '3306:3306' + env: + MYSQL_ALLOW_EMPTY_PASSWORD: true + options: '--health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3' diff --git a/.gitignore b/.gitignore index f3101a24..cde5dab0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ /etc/build/* !/etc/build/.gitignore -/tests/Application/yarn.lock +/tests/Application/* /behat.yml /phpspec.yml @@ -13,3 +13,14 @@ /.idea *.map + +/tests/TestApplication/.env.local +/tests/TestApplication/.env.*.local +/var/ + + +Audit.md +CLAUDE.md +.DS_Store +.claude +.review diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..7be32a5b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,33 @@ +# 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/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [2.0.0] - Unreleased + +### Added +- Support for Sylius v2.0+ +- PHP 8.2+ compatibility +- Use Payment Request API from Sylius +- New Unified Authentication System (OAuth2) + +> [!IMPORTANT] +> Merchants will need to contact support to switch to the new authentication method. + +### Changed +- Plugin structure has been changed to follow the new Symfony bundle structure +- Front assets have been migrated to use Stimulus + +### Removed +- Drop Payum support +- Drop Sylius 1.x support +- Drop usage of Secret key - Use OAuth2 instead + +Please refer to [github releases](https://github.com/payplug/SyliusPayPlugPlugin/releases) for historical release information. + +--- + +For migration guides and upgrade instructions, see [UPGRADE.md](UPGRADE.md). +For contributing guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 59b089dc..8c9b7307 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,10 +3,10 @@ From the plugin root directory, run the following commands: ```bash -$ make install -e SYLIUS_VERSION=XX SYMFONY_VERSION=YY +$ make install -e SYLIUS_VERSION=XX SYMFONY_VERSION=YY PHP_VERSION=ZZ ``` -Default values : XX=1.9.0 and YY=5.2 +Default values : XX=1.14.0 and YY=6.4 and ZZ=8.2 To be able to setup the plugin database, remember to configure you database credentials in `install/Application/.env.local` and `install/Application/.env.test.local`. @@ -22,7 +22,7 @@ $ make reset - GrumPHP (see configuration [grumphp.yml](grumphp.yml).) - GrumPHP is executed by the Git pre-commit hook, but you can launch it manualy with : + GrumPHP is executed by the Git pre-commit hook, but you can launch it manually with : ```bash $ make grumphp diff --git a/Makefile b/Makefile index 3ba136cd..b3007cc4 100644 --- a/Makefile +++ b/Makefile @@ -1,100 +1,58 @@ .DEFAULT_GOAL := help SHELL=/bin/bash COMPOSER_ROOT=composer -TEST_DIRECTORY=tests/Application -CONSOLE=cd tests/Application && php bin/console -e test -COMPOSER=cd tests/Application && composer -YARN=cd tests/Application && yarn - -SYLIUS_VERSION=1.9.0 -SYMFONY_VERSION=4.4 +TEST_DIRECTORY=tests/TestApplication +CONSOLE=vendor/bin/console +COMPOSER=composer +SYLIUS_VERSION=2.1.0 +SYMFONY_VERSION=6.4 PLUGIN_NAME=payplug/sylius-payplug-plugin ### ### DEVELOPMENT ### ¯¯¯¯¯¯¯¯¯¯¯ - -install: sylius ## Install Plugin on Sylius [SyliusVersion=1.9] [SymfonyVersion=5.2] +install: sylius ## Install all dependencies with [SYLIUS_VERSION=2.1.0] [SYMFONY_VERSION=6.4] .PHONY: install reset: ## Remove dependencies - rm -rf tests/Application + ${CONSOLE} doctrine:database:drop --force --if-exists || true + rm -rf vendor .PHONY: reset -phpunit: phpunit-configure phpunit-run ## Run PHPUnit +phpunit: ## Run PHPUnit tests + ./vendor/bin/phpunit .PHONY: phpunit ### ### OTHER ### ¯¯¯¯¯¯ - -sylius: sylius-standard update-dependencies install-plugin install-sylius +sylius: install-sylius .PHONY: sylius -sylius-standard: - ${COMPOSER_ROOT} create-project sylius/sylius-standard ${TEST_DIRECTORY} "~${SYLIUS_VERSION}" - -update-dependencies: - ${COMPOSER} config extra.symfony.require "^${SYMFONY_VERSION}" - ${COMPOSER} require --dev donatj/mock-webserver:^2.1 --no-scripts --no-update -# FIX since https://github.com/Sylius/Sylius/pull/13215 is not merged - ${COMPOSER} require doctrine/dbal:"^2.6" doctrine/orm:"^2.9" --no-scripts --no-update -ifeq ($(SYMFONY_VERSION), 4.4) - ${COMPOSER} require sylius/admin-api-bundle --no-scripts --no-update -endif -ifeq ($(SYLIUS_VERSION), 1.8.0) - ${COMPOSER} update --no-progress --no-scripts --prefer-dist -n -endif - ${COMPOSER} update --no-progress -n - -install-plugin: - ${COMPOSER} config repositories.plugin '{"type": "path", "url": "../../"}' - ${COMPOSER} config extra.symfony.allow-contrib true - ${COMPOSER} config minimum-stability "dev" - ${COMPOSER} config prefer-stable true - ${COMPOSER} req ${PLUGIN_NAME}:* --prefer-source --no-scripts - ${COMPOSER} symfony:recipes:install "${PLUGIN_NAME}" --force - - cp -r install/Application tests - sed -i "4a \ \ \ \ form_themes: ['form/form_gateway_config_row.html.twig']" ${TEST_DIRECTORY}/config/packages/twig.yaml - mkdir -p ${TEST_DIRECTORY}/templates/form/ - cp -R src/Resources/views/form/* ${TEST_DIRECTORY}/templates/form/ - mkdir -p ${TEST_DIRECTORY}/templates/bundles/SyliusAdminBundle/ - cp -R src/Resources/views/SyliusAdminBundle/* ${TEST_DIRECTORY}/templates/bundles/SyliusAdminBundle/ - - # For Refund Plugin - cp -R ${TEST_DIRECTORY}/vendor/sylius/refund-plugin/src/Resources/views/SyliusAdminBundle/* ${TEST_DIRECTORY}/templates/bundles/SyliusAdminBundle/ - install-sylius: - ${CONSOLE} sylius:install -n -s default - ${YARN} install - ${YARN} build - ${CONSOLE} translation:update en PayPlugSyliusPayPlugPlugin --dump-messages - ${CONSOLE} translation:update fr PayPlugSyliusPayPlugPlugin --dump-messages - ${CONSOLE} cache:clear + @echo "Installing Sylius ${SYLIUS_VERSION} using TestApplication" + ${COMPOSER} config extra.symfony.require "^${SYMFONY_VERSION}" + ${COMPOSER} install + ${COMPOSER} require --dev sylius/test-application:"^${SYLIUS_VERSION}@alpha" -n -W # TODO: Remove alpha when stable + ${COMPOSER} test-application:install -phpunit-configure: - cp phpunit.xml.dist ${TEST_DIRECTORY}/phpunit.xml - echo -e "\nMOCK_SERVER_HOST=localhost\nMOCK_SERVER_PORT=8987\n" >> ${TEST_DIRECTORY}/.env.test.local -phpunit-run: - cd ${TEST_DIRECTORY} && ./vendor/bin/phpunit behat-configure: ## Configure Behat (cd ${TEST_DIRECTORY} && cp behat.yml.dist behat.yml) (cd ${TEST_DIRECTORY} && sed -i "s#vendor/sylius/sylius/src/Sylius/Behat/Resources/config/suites.yml#vendor/${PLUGIN_NAME}/tests/Behat/Resources/suites.yml#g" behat.yml) (cd ${TEST_DIRECTORY} && sed -i "s#vendor/sylius/sylius/features#vendor/${PLUGIN_NAME}/features#g" behat.yml) - (cd ${TEST_DIRECTORY} && echo ' - { resource: "../vendor/${PLUGIN_NAME}/tests/Behat/Resources/services.xml" }' >> config/services_test.yaml) - (cd ${TEST_DIRECTORY} && echo ' - { resource: "../vendor/${PLUGIN_NAME}/src/Resources/config/services.xml" }' >> config/services_test.yaml) - (cd ${TEST_DIRECTORY} && echo ' - { resource: "../vendor/sylius/refund-plugin/src/Resources/config/services.xml" }' >> config/services_test.yaml) - (cd ${TEST_DIRECTORY} && echo ' - { resource: "../vendor/sylius/refund-plugin/tests/Behat/Resources/services.xml" }' >> config/services_test.yaml) - (cd ${TEST_DIRECTORY} && echo ' - { resource: "services_payplug.yaml" }' >> config/services_test.yaml) + (cd ${TEST_DIRECTORY} && sed -i '2i \ \ \ \ - { resource: "../vendor/${PLUGIN_NAME}/tests/Behat/Resources/services.xml\" }' config/services_test.yaml) + (cd ${TEST_DIRECTORY} && sed -i '3i \ \ \ \ - { resource: "../vendor/${PLUGIN_NAME}/src/Resources/config/services.xml" }' config/services_test.yaml) + (cd ${TEST_DIRECTORY} && sed -i '4i \ \ \ \ - { resource: "../vendor/sylius/refund-plugin/src/Resources/config/services.xml" }' config/services_test.yaml) + (cd ${TEST_DIRECTORY} && sed -i '5i \ \ \ \ - { resource: "../vendor/sylius/refund-plugin/tests/Behat/Resources/services.xml" }' config/services_test.yaml) + (cd ${TEST_DIRECTORY} && sed -i '6i \ \ \ \ - { resource: "services_payplug.yaml" }' config/services_test.yaml) grumphp: vendor/bin/grumphp run help: SHELL=/bin/bash -help: ## Dislay this help +help: ## Display this help @IFS=$$'\n'; for line in `grep -h -E '^[a-zA-Z_#-]+:?.*?##.*$$' $(MAKEFILE_LIST)`; do if [ "$${line:0:2}" = "##" ]; then \ echo $$line | awk 'BEGIN {FS = "## "}; {printf "\033[33m %s\033[0m\n", $$2}'; else \ echo $$line | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m%s\n", $$1, $$2}'; fi; \ diff --git a/README.md b/README.md index ef06deb7..610a38d8 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,22 @@ -[![License](https://img.shields.io/packagist/l/payplug/payplug-sylius.svg)](https://github.com/payplug/SyliusPayPlugPlugin/blob/master/LICENSE) -![CI](https://github.com/payplug/SyliusPayPlugPlugin/workflows/CI/badge.svg?branch=master) -[![Version](https://img.shields.io/packagist/v/payplug/payplug-sylius.svg)](https://packagist.org/packages/payplug/payplug-sylius) -[![Total Downloads](https://poser.pugx.org/payplug/payplug-sylius/downloads)](https://packagist.org/packages/payplug/payplug-sylius) +[![License](https://img.shields.io/packagist/l/payplug/sylius-payplug-plugin.svg)](https://github.com/payplug/SyliusPayPlugPlugin/blob/master/LICENSE) +[![CI - Analysis](https://github.com/payplug/SyliusPayPlugPlugin/actions/workflows/analysis.yaml/badge.svg?branch=master)](https://github.com/payplug/SyliusPayPlugPlugin/actions/workflows/analysis.yaml) +[![CI - Sylius](https://github.com/payplug/SyliusPayPlugPlugin/actions/workflows/sylius.yaml/badge.svg?branch=master)](https://github.com/payplug/SyliusPayPlugPlugin/actions/workflows/sylius.yaml) +[![Version](https://img.shields.io/packagist/v/payplug/sylius-payplug-plugin.svg)](https://packagist.org/packages/payplug/sylius-payplug-plugin) +[![Total Downloads](https://poser.pugx.org/payplug/sylius-payplug-plugin/downloads)](https://packagist.org/packages/payplug/sylius-payplug-plugin)

- + + + + Sylius Logo. +

-

PayPlug payment plugin for Sylius

+

Payplug payment plugin for Sylius

-

This plugin allows you to integrate PayPlug payment with Sylius platform app including payment features and refunding orders.

+

This plugin allows you to integrate Payplug payment with Sylius platform app including payment features and refunding orders.

## Requirements @@ -26,122 +31,152 @@ In local environment, the plugin will not work properly because you will not be ## Compatibility -| | Version | -| :--- | :--- | -| PHP | 7.4, 8.0 | -| Sylius | 1.9, 1.10 | +| | Version | +|:-------|:--------| +| PHP | ^8.2 | +| Sylius | ^2.0 | -## Installation -1. Require the **payplug/sylius-payplug-plugin** : +### With Symfony Flex - ```bash - composer config extra.symfony.allow-contrib true - composer require payplug/sylius-payplug-plugin - ``` +#### 1. Allow contrib recipes and require the plugin -2. Apply migrations to your database: +```bash +composer config extra.symfony.allow-contrib true +composer require payplug/sylius-payplug-plugin +``` - ```shell - bin/console doctrine:migrations:migrate - ``` +#### 2. Install the Flex recipe -3. Copy templates that are overridden by Sylius into `templates/bundles/SyliusAdminBundle` - - ```shell - mkdir -p templates/bundles/SyliusAdminBundle/ - cp -R vendor/payplug/sylius-payplug-plugin/src/Resources/views/SyliusAdminBundle/* templates/bundles/SyliusAdminBundle/ - ``` +```bash +composer recipes:install payplug/sylius-payplug-plugin --force +``` -4. Add PayPlug to refundable payment method for Sylius Refund Plugin in `config/services.yaml` +This automatically registers the bundle, copies configuration files, and sets up assets (on Sylius 2.1+). - ```yaml - parameters: - sylius_refund.supported_gateways: - - payplug - - payplug_oney - ``` +#### 3. Apply migrations to your database -5. Add PayPlug routes in `config/routes.yaml` +```shell +bin/console doctrine:migrations:migrate +``` - ```yaml - sylius_payplug: - resource: "@PayPlugSyliusPayPlugPlugin/Resources/config/routing.yaml" - ``` +#### 4. Add Payplug to refundable payment methods for Sylius Refund Plugin in `config/services.yaml` + +```yaml +parameters: + locale: fr_FR + sylius_refund.supported_gateways: + - payplug + - payplug_oney + - payplug_bancontact + - payplug_apple_pay + - payplug_american_express +``` -8. Add Traits for Customer and PaymentMethod entities +#### 5. Add Traits for Customer and PaymentMethod entities * App\Entity\Customer\Customer - ```php - Payment methods`, then click on `Create` and choose "**PayPlug**". +In your back-office, go to `Configuration > Payment methods`, then click on `Create` and choose "**Payplug**". ## Logs -If you want to follow the logs in the production environment, you need to add the configuration in `config/packages/prod/monolog.yaml`, logs should be in `var/log/prod.log` which can be searched after the phrase `[Payum]` or `[PayPlug]`: +If you want to follow the logs in the production environment, you need to add the configuration in `config/packages/prod/monolog.yaml`, logs should be in `var/log/prod.log` which can be searched after the phrase `[Payum]` or `[Payplug]`: ```yaml monolog: @@ -164,22 +199,6 @@ Run the below command to see what Symfony services are shared with this plugin: $ bin/console debug:container payplug_sylius_payplug_plugin ``` -### Template overriding - -This plugin override some sylius templates. -If you plan override them also, you should retrieve them in your application. - -Copy Sylius templates overridden in plugin to your templates directory (e.g templates/bundles/) - - ```shell - mkdir -p templates/bundles/SyliusAdminBundle/ - mkdir -p templates/bundles/SyliusShopBundle/ - mkdir -p templates/bundles/SyliusUiBundle/ - cp -R vendor/payplug/sylius-payplug-plugin/src/Resources/views/SyliusAdminBundle/* templates/bundles/SyliusAdminBundle/ - cp -R vendor/payplug/sylius-payplug-plugin/src/Resources/views/SyliusShopBundle/* templates/bundles/SyliusShopBundle/ - cp -R vendor/payplug/sylius-payplug-plugin/src/Resources/views/SyliusUiBundle/* templates/bundles/SyliusUiBundle/ - ``` - ## Development See [How to contribute](CONTRIBUTING.md). @@ -192,6 +211,10 @@ This library is under the MIT license. For better Oney integration, you can check the [Oney enhancement documentation](doc/oney_enhancement.md). +## Authorized Payment + +Since 1.11.0, the plugin supports the authorized payment feature. You can check the [Authorized Payment documentation](doc/authorized_payment.md). + ## Doc - [Development](doc/development.md) - [Release Process](RELEASE.md) diff --git a/RELEASE.md b/RELEASE.md index 9773def5..6cc12383 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -2,3 +2,5 @@ Upon releasing a new version there are checks and updates to be made: * Update plugin's version inside `src/PayPlugSyliusPayPlugPlugin.php` +* Ensure that the `CHANGELOG.md` is up to date with the changes made +* Ensure that the date of the release version is updated in `CHANGELOG.md` diff --git a/src/Resources/dev/.eslintignore b/assets/.eslintignore similarity index 100% rename from src/Resources/dev/.eslintignore rename to assets/.eslintignore diff --git a/src/Resources/dev/.eslintrc b/assets/.eslintrc similarity index 100% rename from src/Resources/dev/.eslintrc rename to assets/.eslintrc diff --git a/src/Resources/dev/.gitignore b/assets/.gitignore similarity index 59% rename from src/Resources/dev/.gitignore rename to assets/.gitignore index 5dde5fca..7b6786d1 100644 --- a/src/Resources/dev/.gitignore +++ b/assets/.gitignore @@ -1,2 +1,3 @@ node_modules/ .*cache +yarn-error.log diff --git a/assets/admin/entrypoint.js b/assets/admin/entrypoint.js new file mode 100644 index 00000000..9ccfccbe --- /dev/null +++ b/assets/admin/entrypoint.js @@ -0,0 +1 @@ +// Mandatory by test application diff --git a/assets/controllers.json b/assets/controllers.json new file mode 100644 index 00000000..5582d953 --- /dev/null +++ b/assets/controllers.json @@ -0,0 +1,41 @@ +{ + "controllers": { + "@payplug/sylius-payplug-plugin": { + "oney-popin": { + "enabled": true, + "fetch": "lazy", + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/oney_common/index.css": true, + "@payplug/sylius-payplug-plugin/shop/dist/oney_popin/index.css": true + } + }, + "integrated-payment": { + "enabled": true, + "fetch": "lazy", + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/payment/integrated.css": true + } + }, + "oney-payment": { + "enabled": true, + "fetch": "lazy" + }, + "payment-logo": { + "enabled": true, + "fetch": "lazy" + }, + "checkout-select-payment": { + "enabled": true, + "fetch": "lazy", + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/payment/index.css": true + } + }, + "apple-pay": { + "enabled": true, + "fetch": "lazy" + } + } + }, + "entrypoints": [] +} diff --git a/assets/images/integrated/account.svg b/assets/images/integrated/account.svg new file mode 100644 index 00000000..297efca7 --- /dev/null +++ b/assets/images/integrated/account.svg @@ -0,0 +1,9 @@ + + + General/Icons/Icon 24x24 - Account + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/calendar.svg b/assets/images/integrated/calendar.svg new file mode 100644 index 00000000..82fb3686 --- /dev/null +++ b/assets/images/integrated/calendar.svg @@ -0,0 +1,13 @@ + + + General/Icons/Icon 24x24 - Calendar + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/card.svg b/assets/images/integrated/card.svg new file mode 100644 index 00000000..5c08a102 --- /dev/null +++ b/assets/images/integrated/card.svg @@ -0,0 +1,10 @@ + + + General/Icons/Icon 24x24 - Card + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/cb-dark.svg b/assets/images/integrated/cb-dark.svg new file mode 100644 index 00000000..5281a653 --- /dev/null +++ b/assets/images/integrated/cb-dark.svg @@ -0,0 +1,33 @@ + + + CB dark + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/cb.svg b/assets/images/integrated/cb.svg new file mode 100644 index 00000000..51c1cad5 --- /dev/null +++ b/assets/images/integrated/cb.svg @@ -0,0 +1,33 @@ + + + CB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/lock.svg b/assets/images/integrated/lock.svg new file mode 100644 index 00000000..316e1f5e --- /dev/null +++ b/assets/images/integrated/lock.svg @@ -0,0 +1,9 @@ + + + General/Icons/Icon 24x24 - Lock + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/logo-payplug.png b/assets/images/integrated/logo-payplug.png new file mode 100644 index 00000000..b67d7cce Binary files /dev/null and b/assets/images/integrated/logo-payplug.png differ diff --git a/assets/images/integrated/mastercard-dark.svg b/assets/images/integrated/mastercard-dark.svg new file mode 100644 index 00000000..652fb0ae --- /dev/null +++ b/assets/images/integrated/mastercard-dark.svg @@ -0,0 +1,19 @@ + + + Mastercard dark + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/mastercard.svg b/assets/images/integrated/mastercard.svg new file mode 100644 index 00000000..337ff9fb --- /dev/null +++ b/assets/images/integrated/mastercard.svg @@ -0,0 +1,18 @@ + + + Mastercard + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/visa-dark.svg b/assets/images/integrated/visa-dark.svg new file mode 100644 index 00000000..9de9cde7 --- /dev/null +++ b/assets/images/integrated/visa-dark.svg @@ -0,0 +1,19 @@ + + + General/Icons/Logos cb/Visa dark + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/integrated/visa.svg b/assets/images/integrated/visa.svg new file mode 100644 index 00000000..5c488458 --- /dev/null +++ b/assets/images/integrated/visa.svg @@ -0,0 +1,16 @@ + + + General/Icons/Logos cb/Visa + + + + + + + \ No newline at end of file diff --git a/assets/package.json b/assets/package.json new file mode 100644 index 00000000..52494447 --- /dev/null +++ b/assets/package.json @@ -0,0 +1,76 @@ +{ + "name": "@payplug/sylius-payplug-plugin", + "license": "MIT", + "version": "2.0.0", + "keywords": [ + "symfony-ux" + ], + "description": "Sylius Payplug Plugin", + "type": "module", + "files": [ + "dist" + ], + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "symfony": { + "controllers": { + "oney-popin": { + "main": "shop/controllers/oney-popin_controller.js", + "enabled": true, + "webpackMode": "lazy", + "fetch": "lazy", + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/oney_common/index.css": true, + "@payplug/sylius-payplug-plugin/shop/dist/oney_popin/index.css": true + } + }, + "integrated-payment": { + "main": "shop/controllers/integrated-payment_controller.js", + "webpackMode": "lazy", + "fetch": "lazy", + "enabled": true, + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/payment/integrated.css": true + } + }, + "oney-payment": { + "main": "shop/controllers/oney-payment_controller.js", + "webpackMode": "lazy", + "fetch": "lazy", + "enabled": true + }, + "payment-logo": { + "main": "shop/controllers/payment-logo_controller.js", + "webpackMode": "lazy", + "fetch": "lazy", + "enabled": true + }, + "checkout-select-payment": { + "main": "shop/controllers/checkout-select-payment_controller.js", + "autoimport": { + "@payplug/sylius-payplug-plugin/shop/dist/payment/index.css": true + }, + "webpackMode": "lazy", + "fetch": "lazy", + "enabled": true + }, + "apple-pay": { + "main": "shop/controllers/apple-pay_controller.js", + "webpackMode": "lazy", + "fetch": "lazy", + "enabled": true + } + } + }, + "peerDependencies": { + "@hotwired/stimulus": "^3.0.0" + }, + "devDependencies": { + "@hotwired/stimulus": "^3.0.0" + }, + "dependencies": { + "jquery": "^3.5.1", + "webfontloader": "^1.6.28" + } +} diff --git a/assets/shop/controllers/apple-pay_controller.js b/assets/shop/controllers/apple-pay_controller.js new file mode 100644 index 00000000..fe977eb6 --- /dev/null +++ b/assets/shop/controllers/apple-pay_controller.js @@ -0,0 +1,181 @@ +import { Controller } from '@hotwired/stimulus'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static values = { + paymentInputId: String, + settings: Object, + notice: String, + } + + connect() { + this.applePayButton = this.element.querySelector('apple-pay-button'); + this.onApplePayButtonClick = this.onApplePayButtonClick.bind(this); + + if (this.applePayButton) { + this.applePayButton.addEventListener('click', this.onApplePayButtonClick); + } + + this.retryCount = 0; + this.initApplePay(); + } + + initApplePay() { + if (typeof window.ApplePaySession !== 'undefined') { + this.checkSupport(); + return; + } + + if (this.retryCount < 20) { // Try for 2 seconds + this.retryCount++; + setTimeout(() => this.initApplePay(), 100); + } else { + this.disablePaymentMethod(); + } + } + + checkSupport() { + try { + const isSupported = window.ApplePaySession.canMakePayments(); + + if (isSupported && this.applePayButton) { + this.applePayButton.classList.add('enabled'); + } else { + this.disablePaymentMethod(); + } + } catch (e) { + this.disablePaymentMethod(); + } + } + + disablePaymentMethod() { + if (!this.paymentInputIdValue) return; + + const input = document.getElementById(this.paymentInputIdValue); + if (!input) return; + + const container = input.closest('.card, .item, .form-check, .field'); + if (container) { + container.style.opacity = '0.5'; + container.style.pointerEvents = 'none'; + container.classList.add('apple-pay-ineligible'); + + // Add a small info message if not already present + if (!container.querySelector('.apple-pay-notice')) { + const notice = document.createElement('div'); + notice.className = 'apple-pay-notice small text-muted mt-2'; + notice.style.padding = '0 1rem 1rem'; + notice.innerText = this.noticeValue || 'Apple Pay is not available on this browser or device.'; + container.appendChild(notice); + } + + if (input.checked) { + input.checked = false; + input.dispatchEvent(new Event('change', { bubbles: true })); + } + } + + input.disabled = true; + + if (this.element) { + this.element.style.display = 'none'; + } + } + + async onApplePayButtonClick(event) { + const applePayButton = event.currentTarget; + + if (!this.settingsValue) { + console.error('Invalid Apple Pay settings!'); + return; + } + + if (typeof window.ApplePaySession === 'undefined') { + return; + } + + // Prepare settings + const settings = { ...this.settingsValue }; + if (settings.applePayDomain) { + settings.applicationData = btoa(JSON.stringify({ + 'apple_pay_domain': settings.applePayDomain + })); + delete settings.applePayDomain; + } + + try { + const version = window.ApplePaySession.supportsVersion(14) ? 14 : 3; + const session = new window.ApplePaySession(version, settings); + + session.onvalidatemerchant = async (event) => { + try { + const response = await fetch(applePayButton.dataset.validateMerchantRoute, { + method: 'POST', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + }, + }); + const authorization = await response.json(); + + if (authorization.success === true) { + session.completeMerchantValidation(authorization.merchant_session); + } else { + session.abort(); + } + } catch (error) { + console.error(error); + session.abort(); + window.location.reload(); + } + }; + + session.onpaymentauthorized = async (event) => { + try { + const response = await fetch(applePayButton.dataset.paymentAuthorizedRoute, { + method: 'POST', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + token: event.payment.token, + }), + }); + const authorization = await response.json(); + + let applePaySessionStatus = window.ApplePaySession.STATUS_SUCCESS; + + if (authorization.data.responseToApple.status !== 1) { + applePaySessionStatus = window.ApplePaySession.STATUS_FAILURE; + } + + session.completePayment({ "status": applePaySessionStatus }); + window.location.href = authorization.data.returnUrl; + } catch (error) { + console.error(error); + window.location.reload(); + } + }; + + session.oncancel = async (event) => { + try { + const response = await fetch(applePayButton.dataset.sessionCancelRoute, { + method: 'POST', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + }, + }); + const authorization = await response.json(); + window.location.href = authorization.data.returnUrl; + } catch (error) { + console.error(error); + window.location.reload(); + } + }; + + session.begin(); + } catch (e) { + console.error('Failed to create Apple Pay session:', e); + } + } +} diff --git a/assets/shop/controllers/checkout-select-payment_controller.js b/assets/shop/controllers/checkout-select-payment_controller.js new file mode 100644 index 00000000..ead033d4 --- /dev/null +++ b/assets/shop/controllers/checkout-select-payment_controller.js @@ -0,0 +1,129 @@ +import { Controller } from '@hotwired/stimulus'; +import $ from 'jquery'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['trigger']; + form = null; + + connect() { + this.form = this.element.closest('form') || document.querySelector('form[name*="checkout_select_payment"]'); + this.findNextStepButton(); + + this.handleStateChange = this.handleStateChange.bind(this); + this.element.addEventListener('payment-method-state-change', this.handleStateChange); + + this.toggleGateway(); + + if (this.form) { + this.form.addEventListener('submit', (event) => { + this.handleForm(); + }); + } + } + + disconnect() { + this.element.removeEventListener('payment-method-state-change', this.handleStateChange); + } + + handleStateChange(event) { + this.updateNextStepButtonVisibility(event.target); + } + + findNextStepButton() { + if (!this.form) return; + this.nextStepButton = this.form.querySelector('button[type="submit"], button:not([type])'); + } + + toggleGateway() { + const $inputs = $(this.element).find('input[id*="checkout_select_payment_payments"]'); + const checkedInput = $inputs.filter(':checked')[0]; + + // Hide all initially + this.triggerTargets.forEach(target => $(target).hide()); + + if (checkedInput) { + const currentTarget = this.triggerTargets.find(target => target.dataset.paymentInputId === checkedInput.id); + if (currentTarget) { + $(currentTarget).show(); + this.updateNextStepButtonVisibility(currentTarget); + } else { + this.toggleNextStepButton(true); + } + } + + $inputs.on('change', (event) => { + const clickedPaymentMethodId = event.currentTarget.id; + + // Hide all choices + this.triggerTargets.forEach(target => $(target).slideUp()); + + const currentTarget = this.triggerTargets.find(target => target.dataset.paymentInputId === clickedPaymentMethodId); + if (currentTarget) { + $(currentTarget).slideDown(() => { + this.updateNextStepButtonVisibility(currentTarget); + }); + } else { + this.toggleNextStepButton(true); + } + }); + } + + updateNextStepButtonVisibility(container) { + let targetContainer = container; + + if (!targetContainer || !targetContainer.dataset.paymentInputId) { + // Fallback to currently checked input + const checkedInput = this.element.querySelector('input[id*="checkout_select_payment_payments"]:checked'); + if (checkedInput) { + targetContainer = this.triggerTargets.find(target => target.dataset.paymentInputId === checkedInput.id); + } + } + + if (!targetContainer) { + this.toggleNextStepButton(true); + return; + } + + const handlesSubmit = targetContainer.dataset.paymentInlineSubmit === 'true' || + targetContainer.querySelector('[data-payment-inline-submit="true"]') !== null; + + this.toggleNextStepButton(!handlesSubmit); + } + + toggleNextStepButton(show) { + if (!this.nextStepButton) { + this.findNextStepButton(); + } + if (!this.nextStepButton) return; + + if (show) { + this.nextStepButton.classList.remove('disabled'); + this.nextStepButton.disabled = false; + } else { + this.nextStepButton.classList.add('disabled'); + this.nextStepButton.disabled = true; + } + } + + enableNextStepButton() { + this.toggleNextStepButton(true); + } + + disableNextStepButton() { + this.toggleNextStepButton(false); + } + + handleForm() { + if ($('.checkbox-oney :radio:checked').length) { + $('.checkbox-payplug').closest('.oney-payment-choice__item, .payplug-payment-choice__item, .form-check, .payment-item').find('.payment-choice__input:checked').prop('checked', false); + } else if ($('.checkbox-payplug :radio:checked').length) { + $('.checkbox-oney').closest('.oney-payment-choice__item, .payplug-payment-choice__item, .form-check, .payment-item').find('.payment-choice__input:checked').prop('checked', false); + } + + const otherCardOther = document.querySelector('input#payplug_choice_card_other'); + if (otherCardOther) { + otherCardOther.disabled = true; + } + } +} diff --git a/assets/shop/controllers/integrated-payment_controller.js b/assets/shop/controllers/integrated-payment_controller.js new file mode 100644 index 00000000..5c85c16e --- /dev/null +++ b/assets/shop/controllers/integrated-payment_controller.js @@ -0,0 +1,259 @@ +import { Controller } from '@hotwired/stimulus'; +import WebFont from 'webfontloader'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['container'] + static values = { + code: String, + factoryName: String, + } + initialize() { + WebFont.load({ + google: { + families: ["Poppins:400,600"], + }, + }); + } + connect() { + this.options = { + api: null, + cartId: null, + form: {}, + fieldsValid: { + cardHolder: false, + pan: false, + cvv: false, + exp: false, + }, + fieldsEmpty: { + cardHolder: true, + pan: true, + cvv: true, + exp: true, + }, + inputStyle: { + default: { + color: '#2B343D', + fontFamily: 'Poppins, Arial, sans-serif', + fontSize: '14px', + textAlign: 'left', + '::placeholder': { + color: '#969a9f', + }, + ':focus': { + color: '#2B343D', + } + }, + invalid: { + color: '#E91932' + } + }, + save_card: false, + schemes: null, + scheme: null, + }; + + // Verify if we have required data + // TODO: Pass as param + if (typeof payplug_integrated_payment_params === 'undefined') { + return; + } + + this.form = this.element.closest('form'); + + if (payplug_integrated_payment_params.has_saved_cards) { + const otherCardRadio = this.element.querySelector('#payplug_choice_card_other'); + const payplugRadio = document.querySelector(`[id*="checkout_select_payment_payments"][value="${payplug_integrated_payment_params.payment_method_code}"]`); + + // Initial check + if ( + (otherCardRadio && otherCardRadio.checked && payplugRadio && payplugRadio.checked) || + (otherCardRadio && otherCardRadio.checked && !payplugRadio && document.querySelector('.payplug-payment-choice__input:checked')) + ) { + this.openFields(); + } + + this.element.querySelectorAll('.payment-choice__input, [id*="checkout_select_payment_payments"]').forEach((element) => { + element.addEventListener('change', (e) => { + const isOtherCardChecked = this.element.querySelector('#payplug_choice_card_other')?.checked; + const isPayplugSelected = document.querySelector(`[id*="checkout_select_payment_payments"][value="${payplug_integrated_payment_params.payment_method_code}"]`)?.checked; + + if (isOtherCardChecked && isPayplugSelected) { + this.openFields(); + } + }) + }) + return; + } + + const isChecked = this.getPaymentMethodSelectors({ methodCode: payplug_integrated_payment_params.payment_method_code, checked: true }); + if (isChecked.length) { + this.openFields(); + } + + const selectPaymentMethodsField = this.getPaymentMethodSelectors(); + selectPaymentMethodsField.forEach((element) => { + // On payment method select, open fields if payplug selected + element.addEventListener('change', (e) => { + if (payplug_integrated_payment_params.payment_method_code === e.currentTarget.value && e.currentTarget.checked) { + this.openFields(); + } + }) + }); + } + + handleShow(event) { + if (this.hasContainerTarget) { + import('jquery').then(({ default: $ }) => { + $(this.containerTarget).slideDown(); + }); + this.openFields(); + this.containerTarget.dataset.paymentInlineSubmit = "true"; + this.element.dispatchEvent(new CustomEvent('payment-method-state-change', { bubbles: true })); + } + } + + handleHide(event) { + if (this.hasContainerTarget) { + import('jquery').then(({ default: $ }) => { + $(this.containerTarget).slideUp(); + }); + this.closeFields(); + this.containerTarget.dataset.paymentInlineSubmit = "false"; + this.element.dispatchEvent(new CustomEvent('payment-method-state-change', { bubbles: true })); + } + } + + getPaymentMethodSelectors({ methodCode, checked } = {}) { + const baseSelector = '[id*=checkout_select_payment_payments]'; + + if (methodCode) { + if (checked) { + return document.querySelectorAll(`${baseSelector}[value=${methodCode}]:checked`); + } + return document.querySelectorAll(`${baseSelector}[value=${methodCode}]`); + } + return document.querySelectorAll(baseSelector); + } + + openFields() { + this.containerTarget.classList.add('payplugIntegratedPayment--loaded'); + if (null === this.options.api) { + this.load(); + } + } + + closeFields() { + this.containerTarget.classList.remove('payplugIntegratedPayment--loaded'); + } + + load() { + this.options.api = new window.Payplug.IntegratedPayment(payplug_integrated_payment_params.is_test_mode); + this.options.api.setDisplayMode3ds(window.Payplug.DisplayMode3ds.LIGHTBOX); + + const container = this.hasContainerTarget ? this.containerTarget : this.element; + + this.options.form.cardHolder = this.options.api.cardHolder( + container.querySelector('.cardHolder-input-container'), + { + default: this.options.inputStyle.default, + placeholder: payplug_integrated_payment_params.cardholder + } + ); + this.options.form.pan = this.options.api.cardNumber( + container.querySelector('.pan-input-container'), + { + default: this.options.inputStyle.default, + placeholder: payplug_integrated_payment_params.pan + } + ); + this.options.form.cvv = this.options.api.cvv( + container.querySelector('.cvv-input-container'), + { + default: this.options.inputStyle.default, + placeholder: payplug_integrated_payment_params.cvv + } + ); + this.options.form.exp = this.options.api.expiration( + container.querySelector('.exp-input-container'), + { + default: this.options.inputStyle.default, + placeholder: payplug_integrated_payment_params.exp + } + ); + this.options.schemes = this.options.api.getSupportedSchemes(); + this.bindEvents(); + this.fieldValidation(); + } + bindEvents() { + const container = this.hasContainerTarget ? this.containerTarget : this.element; + const paidButton = container.querySelector('#paid'); + if (paidButton) { + paidButton.addEventListener('click', (event) => { + event.preventDefault(); + this.options.api.validateForm(); + }); + } + + this.options.api.onValidateForm(async ({ isFormValid }) => { + if (isFormValid) { + this.toggleLoader(); + const saveCardElement = this.element.querySelector('#savecard'); + if (null !== saveCardElement) { + this.options.save_card = saveCardElement.checked; + } + const chosenScheme = this.element.querySelector('input.schemeOptions:checked'); + this.options.scheme = window.Payplug.Scheme.AUTO; + if (null !== chosenScheme) { + this.options.scheme = chosenScheme.value; + } + if (payplug_integrated_payment_params.payment_id !== undefined) { + this.options.api.pay(payplug_integrated_payment_params.payment_id, this.options.scheme, {save_card: this.options.save_card}); + return; + } + const response = await fetch(payplug_integrated_payment_params.routes.init_payment, {method: 'POST'}); + const data = await response.json(); + this.options.api.pay(data.payment_id, this.options.scheme, {save_card: this.options.save_card}); + } + }); + this.options.api.onCompleted((event) => { + if (event.error) { + console.error(event.error); + return; + } + document.querySelector('input[name=payplug_integrated_payment_token]').value = event.token; + this.form.submit(); + }); + } + fieldValidation () { + const container = this.hasContainerTarget ? this.containerTarget : this.element; + Object.keys(this.options.form).forEach((key) => { + const field = this.options.form[key]; + field.onChange((err) => { + if (err.error) { + container.querySelector(`.payplugIntegratedPayment__error--${key}`).classList.remove('payplugIntegratedPayment__error--hide'); + container.querySelector(`.${key}-input-container`).classList.add('payplugIntegratedPayment__container--invalid'); + if (err.error.name === "FIELD_EMPTY") { + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".emptyField").classList.remove('payplugIntegratedPayment__error--hide'); + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".invalidField").classList.add('payplugIntegratedPayment__error--hide'); + } else { + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".invalidField").classList.remove('payplugIntegratedPayment__error--hide'); + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".emptyField").classList.add('payplugIntegratedPayment__error--hide'); + } + } else { + container.querySelector(`.payplugIntegratedPayment__error--${key}`).classList.add('payplugIntegratedPayment__error--hide'); + container.querySelector(`.${key}-input-container`).classList.remove('payplugIntegratedPayment__container--invalid'); + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".invalidField").classList.add('payplugIntegratedPayment__error--hide'); + container.querySelector(`.payplugIntegratedPayment__error--${key}`).querySelector(".emptyField").classList.add('payplugIntegratedPayment__error--hide'); + this.options.fieldsValid[key] = true; + this.options.fieldsEmpty[key] = false; + } + }); + }) + } + toggleLoader() { + const container = this.hasContainerTarget ? this.containerTarget : this.element; + container.querySelector('.sylius-shop-loader').classList.toggle('d-none'); + } +} diff --git a/assets/shop/controllers/oney-payment_controller.js b/assets/shop/controllers/oney-payment_controller.js new file mode 100644 index 00000000..bdf7d63e --- /dev/null +++ b/assets/shop/controllers/oney-payment_controller.js @@ -0,0 +1,95 @@ +import { Controller } from '@hotwired/stimulus'; +import $ from 'jquery'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static values = { + modal: String, + area: String, + route: String, + } + connect() { + this.tabs(); + window.addEventListener('resize', () => { + setTimeout(this.tabs, 100); + }); + this.tabsHandler(); + } + tabs() { + if (window.innerWidth <= 991) { + $('.oney-payment-choice__item').hide(); + setTimeout(() => { + $.each($('.oney-payment-choice__input'), (k, el) => { + if ($(el).is(':checked')) { + $(el).parent().show(); + $(`a.tablink[data-id=${$(el).val()}]`).addClass('active'); + } + }); + }, 1); + } else { + $('.oney-payment-choice__item').show(); + $('a.tablink').removeClass('active'); + } + } + tabsHandler() { + const $tabLinks = $('a.tablink'); + $.each($tabLinks, (k, el) => { + $(el).click(function (evt) { + $('a.tablink').removeClass('active'); + $(this).addClass('active'); + $('.oney-payment-choice__item').hide(); + $(`#${$(this).data('id')}`).show(); + $(`input[value=${$(this).data('id')}`).prop('checked', true); + }); + }); + } + routeValueChanged() { + if (!this.hasRouteValue) { + return; + } + this.modalAppear(); + } + modalAppear() { + let path = this.routeValue; + $.get(path).then((data) => { + const modalTpl = document.querySelector('.modal'); + this.modal = new window.bootstrap.Modal(modalTpl); + $(modalTpl).find('.modal-body').html(data); + this.modal.show(); + this.bindModalEvents(); + }); + } + modalSubmit(e) { + if (!this.hasRouteValue) { + return; + } + e.preventDefault(); + $('.sylius-shop-loader').toggleClass("d-none"); + $.ajax({ + method: 'post', + url: this.routeValue, + data: $(e.currentTarget).serialize(), + success: (res) => { + if (Array.isArray(res)) { + $(`${this.modalValue}__content`).fadeOut(() => { + $(`${this.modalValue}__success`).show(); + }); + setTimeout(() => { + this.modal.hide(); + window.location.reload(); + }, 2500); + } + }, + error: (res) => { + $(this.modalValue).html(res.responseText); + this.bindModalEvents(); + }, + complete: () => { + $('.sylius-shop-loader').toggleClass("d-none"); + } + }); + } + bindModalEvents() { + $('form[name=form]').on('submit', (e) => this.modalSubmit(e)); + } +} diff --git a/assets/shop/controllers/oney-popin_controller.js b/assets/shop/controllers/oney-popin_controller.js new file mode 100644 index 00000000..e8cc4554 --- /dev/null +++ b/assets/shop/controllers/oney-popin_controller.js @@ -0,0 +1,167 @@ +import { Controller } from '@hotwired/stimulus'; +import $ from 'jquery'; +import WebFont from 'webfontloader'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static targets = ['popin', 'variantCodes']; + static values = { + eligibleUrl: String, + popinUrl: String, + productMeta: Object, + imagesMap: Object, + translations: Object, + } + inputs = { + option: "cartItem_variant", + quantity: "cartItem_quantity", + } + storage = [] + initialize() { + WebFont.load({ + google: { + families: ["Poppins:400,600"], + }, + }); + } + connect() { + if (this.hasProductMetaValue) { + this.watch(); + } + this.fade(); + this.closeHandler(); + } + watch() { + for (const prop in this.inputs) { + const $selectors = $(`[id*=${this.inputs[prop]}`); + if ($selectors.length > 0) { + this.handleProductOptionsChange($selectors, prop); + } + this.productMetaValue = { + ...this.productMetaValue, + [prop]: $selectors.val(), + }; + $selectors.on( + "input", + this.debounce((e) => { + e.preventDefault(); + if ($selectors.length > 0) { + this.handleProductOptionsChange($selectors, prop); + } + this.productMetaValue = { + ...this.productMetaValue, + [prop]: $(e.currentTarget).val(), + }; + this.check(); + }, 500) + ); + } + } + handleProductOptionsChange($selectors, prop) { + if (prop === "option") { + let selector = ""; + $selectors.each((k, v) => { + const select = $(v); + const option = select.find("option:selected").val(); + selector += `[data-${select.attr("data-option")}="${option}"]`; + }); + return (this.productMetaValue = { + ...this.productMetaValue, + product_variant_code: $(this.variantCodesTarget).find(selector).attr("data-value") + }); + } + } + check() { + this.storage = []; + this.toggleLoader(); + $.ajax({ + url: this.eligibleUrlValue, + data: this.productMetaValue, + success: (res) => { + $(this.element).find(".oney-logo").attr("src", this.imagesMapValue[res.isEligible ? 'enabled' : 'disabled']); + res.isEligible + ? $(this.popinTarget).removeClass("disabled").addClass("enabled") + : $(this.popinTarget).removeClass("enabled").addClass("disabled"); + }, + complete: () => { + this.toggleLoader(); + } + }); + } + /** + * https://davidwalsh.name/javascript-debounce-function + */ + debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + fade() { + $(this.element).on("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + if (this.hasEligibleUrlValue) { + if (!$(this.popinTarget).is(":empty") && $(this.popinTarget).text().trim() === this.storage) { + $(this.popinTarget).fadeIn(); + return; + } + } + // content isn't loaded yet or cart route + this.toggleLoader(); + this.load(); + }); + } + load() { + $.ajax({ + url: this.popinUrlValue, + data: this.productMetaValue, + success: (res) => { + if (res.includes(this.translationsValue.reason)) { + $(this.popinTarget).removeClass("enabled").addClass("disabled"); + } + this.storage = $(res).text().trim(); + $(this.popinTarget).html(res); + }, + error: ()=> { + $(this.popinTarget).removeClass("enabled").addClass("disabled").html(` +
+ + + +
+
+

${this.translationsValue.reason}

+
+ `); + }, + complete: ()=> { + this.toggleLoader(); + $(this.popinTarget).fadeIn(); + this.closeHandler(); + }, + }); + } + toggleLoader() { + $(this.element).find('.sylius-shop-loader').toggleClass("d-none"); + } + closeHandler() { + $("html") + .not(this.popinTarget) + .on("click", (e) => { + e.stopPropagation(); + $(this.popinTarget).fadeOut(); + }); + $(this.popinTarget) + .find("a.close") + .on("click", (e) => { + e.stopPropagation(); + $(this.popinTarget).fadeOut(); + }); + } +} diff --git a/assets/shop/controllers/payment-logo_controller.js b/assets/shop/controllers/payment-logo_controller.js new file mode 100644 index 00000000..486cb375 --- /dev/null +++ b/assets/shop/controllers/payment-logo_controller.js @@ -0,0 +1,20 @@ +import { Controller } from '@hotwired/stimulus'; +import $ from 'jquery'; + +/* stimulusFetch: 'lazy' */ +export default class extends Controller { + static values = { + inputId: String, + logoUrl: String, + className: String, + }; + connect() { + if (!this.inputIdValue || !this.logoUrlValue) { + return; + } + + const label = document.querySelector(`[for="${this.inputIdValue}"]`); + label.style.setProperty('--logo', `url(${this.logoUrlValue})`); + label.classList.add('payment-label-with-image', this.classNameValue); + } +} diff --git a/assets/shop/dist/oney_common/index.css b/assets/shop/dist/oney_common/index.css new file mode 100644 index 00000000..84b84648 --- /dev/null +++ b/assets/shop/dist/oney_common/index.css @@ -0,0 +1 @@ +[class*=oney] *{line-height:1.25;font-family:Poppins,Arial,sans-serif!important}[class*=oney] * p{color:#66727f;margin:0}[class*=oney] * small{font-size:90%}.oney-info{margin:1em auto .5em;display:inline-block;position:relative}.oney-info span{vertical-align:text-bottom;text-transform:uppercase;font-size:16px}.oney-info>img{cursor:pointer;vertical-align:middle;margin:0 4px}.oney-info.loading{pointer-events:none}.oney-logo[src*=without-fees]{max-width:190px}@media screen and (max-width:768px){.oney-logo{max-width:230px}} \ No newline at end of file diff --git a/assets/shop/dist/oney_popin/index.css b/assets/shop/dist/oney_popin/index.css new file mode 100644 index 00000000..ecaf7bff --- /dev/null +++ b/assets/shop/dist/oney_popin/index.css @@ -0,0 +1 @@ +.oney-popin{z-index:99;max-width:20em;background-color:#fff;padding:10px;display:none;position:absolute;top:0;left:calc(-20em - 32px);transform:translateY(calc(10px - 33.3333%))}.oney-popin:after{content:"";height:0;width:0;border-top:20px solid #0000;border-bottom:20px solid #0000;display:inline-block;position:absolute;top:calc(33.3333% - 10px);right:-20px}.oney-popin.enabled{border:1px solid #81bc00}.oney-popin.enabled hr{border-color:#81bc00}.oney-popin.enabled:after{border-left:20px solid #81bc00}.oney-popin.enabled a.close>span{background:#81bc00}.oney-popin.enabled .oney-popin__content>p{color:#81bc00}.oney-popin.disabled{border:1px solid #ccc}.oney-popin.disabled hr{border-color:#ccc}.oney-popin.disabled:after{border-left:20px solid #ccc}.oney-popin.disabled a.close>span{background:#ccc}.oney-popin.disabled .oney-popin__content>p{color:#66727f}.oney-popin__header{text-align:right}.oney-popin__header a.close{width:40px;height:40px;position:absolute;top:0;right:0}.oney-popin__header a.close>span{width:15px;height:2px;border-radius:0;margin:0;position:absolute;top:1em;right:.5em}.oney-popin__header a.close>span:first-of-type{transform:rotate(55deg)}.oney-popin__header a.close>span:last-of-type{transform:rotate(-55deg)}.oney-popin__content>p:not(.reasons){text-transform:uppercase;margin-bottom:0;font-size:16px}.oney-popin__content>p:not(.reasons):last-of-type{margin-bottom:1em}.oney-popin__content>p.reasons{max-width:95%}.oney-popin__footer{margin-top:1em}.oney-popin__footer>p{text-align:justify}.oney-popin section{align-items:flex-start;display:flex}.oney-popin img{height:auto;margin-right:.5em}.oney-popin hr{border-style:solid none none;border-width:1px 0 0;border-bottom-color:currentColor;border-left-color:currentColor;border-right-color:currentColor;margin:1.25em 0}@media screen and (max-width:768px){.oney-popin{top:60px;left:0;transform:none}.oney-popin__header a.close{padding:10px 50px}.oney-popin:after{top:-30px;right:calc(50% - 10px);transform:rotate(-90deg)}} \ No newline at end of file diff --git a/assets/shop/dist/payment/account.039342ad.svg b/assets/shop/dist/payment/account.039342ad.svg new file mode 100644 index 00000000..429c051d --- /dev/null +++ b/assets/shop/dist/payment/account.039342ad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/calendar.3c23bb16.svg b/assets/shop/dist/payment/calendar.3c23bb16.svg new file mode 100644 index 00000000..170acc49 --- /dev/null +++ b/assets/shop/dist/payment/calendar.3c23bb16.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/card.0d2bd9bc.svg b/assets/shop/dist/payment/card.0d2bd9bc.svg new file mode 100644 index 00000000..5806d291 --- /dev/null +++ b/assets/shop/dist/payment/card.0d2bd9bc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/cb-dark.888aec45.svg b/assets/shop/dist/payment/cb-dark.888aec45.svg new file mode 100644 index 00000000..eb75a35d --- /dev/null +++ b/assets/shop/dist/payment/cb-dark.888aec45.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/cb.ccd964e9.svg b/assets/shop/dist/payment/cb.ccd964e9.svg new file mode 100644 index 00000000..2fa204f2 --- /dev/null +++ b/assets/shop/dist/payment/cb.ccd964e9.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/index.css b/assets/shop/dist/payment/index.css new file mode 100644 index 00000000..95e0bf4b --- /dev/null +++ b/assets/shop/dist/payment/index.css @@ -0,0 +1,232 @@ +.oney-payment-choice__item label, .payplug-payment-choice__item label { + margin-top: 0 !important; + padding: 1em !important; + display: flex !important +} + +.oney-payment-choice__container, .payplug-payment-choice__container { + margin: 1rem 0; + display: flex +} + +.oney-payment-choice__header p, .payplug-payment-choice__header p { + color: #000; + margin: .5em 0 !important +} + +.oney-payment-choice__item, .payplug-payment-choice__item { + flex: auto +} + +.oney-payment-choice__item--oney_x3_with_fees, .oney-payment-choice__item--oney_x3_without_fees, .payplug-payment-choice__item--oney_x3_with_fees, .payplug-payment-choice__item--oney_x3_without_fees { + margin-right: 1em +} + +.oney-payment-choice__item input, .payplug-payment-choice__item input { + display: none +} + +.oney-payment-choice__item input:checked + label, .payplug-payment-choice__item input:checked + label { + background-color: #81bc0021; + border-color: #81bc00 +} + +.oney-payment-choice__item input:checked + label.payplug-payment-choice__label, .payplug-payment-choice__item input:checked + label.payplug-payment-choice__label { + background-color: #8fd2b821; + border-color: #8fd2b8 +} + +.oney-payment-choice__item label, .payplug-payment-choice__item label { + width: 100%; + height: 100%; + cursor: pointer; + border: 1px solid #ccc; + border-radius: .285714rem; + flex-direction: column; + transition: border-color, background-color .3s ease-in-out; + position: relative; + box-shadow: 0 1px 2px #22242626 +} + +.oney-payment-choice__item label img, .payplug-payment-choice__item label img { + vertical-align: text-bottom +} + +.oney-payment-choice__content, .payplug-payment-choice__content { + display: contents +} + +.oney-payment-choice__content p, .payplug-payment-choice__content p { + color: #000; + border-bottom: 1px solid #ccc; + flex-wrap: wrap; + justify-content: space-between; + display: flex; + margin: 0 !important; + padding: .75rem 0 !important +} + +.oney-payment-choice__content p:nth-last-of-type(2), .payplug-payment-choice__content p:nth-last-of-type(2) { + margin-bottom: 1rem !important +} + +.oney-payment-choice__content p:last-of-type, .payplug-payment-choice__content p:last-of-type { + border: none; + margin-top: auto !important; + margin-bottom: 0 !important +} + +.oney-payment-choice__content p.oney-without-fees-financing, .payplug-payment-choice__content p.oney-without-fees-financing { + display: inline-block +} + +.oney-payment-choice__content small, .payplug-payment-choice__content small { + margin-top: .5rem; + font-size: 80% +} + +.oney-payment-choice__tab { + display: none +} + +.oney-payment-choice__header { + text-align: center; + margin: 0 auto +} + +[data-gateway=oney] { + margin-top: 10px !important; + padding: 0 !important +} + +.oney-logo[src*=without-fees] { + max-width: 200px +} + +apple-pay-button { + --apple-pay-button-width: 222px; + --apple-pay-button-height: 40px; + --apple-pay-button-border-radius: 4px; + --apple-pay-button-padding: 4px 4px; + --apple-pay-button-box-sizing: border-box; + min-width: 140px; + max-width: 100%; +} + +label { + cursor: pointer +} + +.payplug-payment-choice__container { + flex-direction: column +} + +.payplug-payment-choice__item { + margin-bottom: 1em +} + +.payplug-payment-choice__header { + justify-content: space-between; + align-items: center; + display: flex +} + +.payplug-payment-choice__header .card-expiry span { + font-weight: 700 +} + +.oney-complete-info-popin { + max-width: 480px; + margin: auto; +} + +.oney-complete-info-popin__content ul { + padding: 0; + list-style: none +} + +.oney-complete-info-popin__success { + display: none +} + +.payment-label-with-image::after { + content: ""; + background-image: var(--logo); + display: inline-block; + width: 45px; + height: 40px; + margin-top: -6px; + margin-left: 10px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + float: right; +} +.payment-label-with-image.oney-label::after { + width: 130px; +} + +@media screen and (max-width: 991px) { + .oney-payment-choice__container, .payplug-payment-choice__container { + display: block + } + + .oney-payment-choice__content small, .payplug-payment-choice__content small { + width: 100% + } + + .oney-payment-choice__tab { + justify-content: space-between; + display: flex + } + + .oney-payment-choice__tab .tablink { + text-align: center; + border: 1px solid #ccc; + border-bottom: 0; + flex: 1; + padding: 1rem 0 + } + + .oney-payment-choice__tab .tablink.active { + border-bottom: 5px solid #81bc00 + } + + .oney-payment-choice__tab .tablink p { + color: #000 + } + + .oney-payment-choice__tab .tablink:first-of-type { + border-right: 0 + } + + .oney-payment-choice__tab .tablink > .oney-payment__image { + max-width: 120px + } + + .oney-payment-choice__header, .oney-payment-choice__item { + display: none + } + + .oney-payment-choice__item input:checked + label { + background-color: #fff; + border-color: #ccc + } + + .oney-payment-choice__item label { + border-top-left-radius: 0; + border-top-right-radius: 0 + } + + .oney-payment-choice__item--oney_x3_with_fees, .oney-payment-choice__item--oney_x3_without_fees { + margin-bottom: 1rem; + margin-right: 0; + display: block + } +} + +@media screen and (max-width: 480px) { + .payplug-payment-choice__header, .payplug-payment-choice__header .card-type, .payplug-payment-choice__header .card-expiry { + display: block + } +} diff --git a/assets/shop/dist/payment/integrated.css b/assets/shop/dist/payment/integrated.css new file mode 100644 index 00000000..2bf34d51 --- /dev/null +++ b/assets/shop/dist/payment/integrated.css @@ -0,0 +1,301 @@ +.payplugIntegratedPayment { + justify-self: center; + display: none +} + +.payplugIntegratedPayment * { + font-family: Poppins, Arial, sans-serif !important +} + +.payplugIntegratedPayment--loaded { + width: 100%; + max-width: 400px; + flex-wrap: wrap; + justify-content: space-between; + margin: 20px auto 0; + display: flex; + position: relative +} + +.payplugIntegratedPayment__select { + height: 36px; + width: 100%; + border: 1px solid #ccc; + border-radius: 5px; + margin: 0 0 10px; + padding: 0 8px +} + +.payplugIntegratedPayment__container { + width: 100%; + margin: 0 0 10px; + padding: 0; + display: flex; + position: relative +} + +.payplugIntegratedPayment__container--cardHolder, +.payplugIntegratedPayment__container--pan, +.payplugIntegratedPayment__container--exp, +.payplugIntegratedPayment__container--cvv { + height: 40px; + cursor: text; + border: 1px solid #d5d6d8; + border-radius: 2px; + padding: 0 16px 0 50px; + line-height: 40px +} + +.payplugIntegratedPayment__container--cardHolder:before, +.payplugIntegratedPayment__container--pan:before, +.payplugIntegratedPayment__container--exp:before, +.payplugIntegratedPayment__container--cvv:before { + content: ""; + width: 24px; + height: 24px; + background: #95999e 50%/100% no-repeat; + position: absolute; + top: 20%; + left: 16px +} + +.payplugIntegratedPayment__container--cardHolder:focus, +.payplugIntegratedPayment__container--pan:focus, +.payplugIntegratedPayment__container--exp:focus, +.payplugIntegratedPayment__container--cvv:focus { + border-color: #2b343d +} + +.payplugIntegratedPayment__container--cardHolder--invalid, +.payplugIntegratedPayment__container--pan--invalid, +.payplugIntegratedPayment__container--exp--invalid, +.payplugIntegratedPayment__container--cvv--invalid { + border-color: #e91932 +} + +.payplugIntegratedPayment__container--cardHolder:before { + -webkit-mask-image: url(account.039342ad.svg); + mask-image: url(account.039342ad.svg) +} + +.payplugIntegratedPayment__container--pan:before { + -webkit-mask-image: url(card.0d2bd9bc.svg); + mask-image: url(card.0d2bd9bc.svg) +} + +.payplugIntegratedPayment__container--exp:before { + -webkit-mask-image: url(calendar.3c23bb16.svg); + mask-image: url(calendar.3c23bb16.svg) +} + +.payplugIntegratedPayment__container--cvv:before { + -webkit-mask-image: url(lock.fe8a73cd.svg); + mask-image: url(lock.fe8a73cd.svg) +} + +.payplugIntegratedPayment__container--exp, +.payplugIntegratedPayment__container--cvv { + max-width: calc(50% - 2px); + display: inline-block +} + +.payplugIntegratedPayment__container--scheme { + text-transform: uppercase; + height: 22px; + justify-content: space-between; + align-items: center; + margin: 10px 0; + font-size: 14px; + font-weight: 700 +} + +.payplugIntegratedPayment__container--saveCard { + height: auto; + align-items: center; + padding: 10px 0 0; + display: flex +} + +.payplugIntegratedPayment__container--saveCard input { + display: none +} + +.payplugIntegratedPayment__container--saveCard input:checked+label span:before { + opacity: 1 +} + +.payplugIntegratedPayment__container--saveCard label { + cursor: pointer; + color: #918f8f; + margin: 0 !important; + font-size: 12px !important +} + +.payplugIntegratedPayment__container--saveCard label span { + cursor: pointer; + height: 16px; + -o-transition: border .4s; + width: 16px; + border: 1px solid #d5d6d8; + border-radius: 2px; + margin: 0 10px -3px 0; + transition: border .4s; + display: inline-block; + position: relative +} + +.payplugIntegratedPayment__container--saveCard label span:before { + content: ""; + height: 5px; + opacity: 0; + width: 10px; + border-top: none; + border-bottom: 2.5px solid #2b343d; + border-left: 2.5px solid #2b343d; + border-right: none; + border-radius: 1px; + transition: opacity .4s; + display: block; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -55%)rotate(-48deg) +} + +.payplugIntegratedPayment__container--saveCard label:hover { + color: #2b343d; + transition: all .1s +} + +.payplugIntegratedPayment__container--saveCard label:hover span { + border-color: #2b343d; + transition: all .1s +} + +.payplugIntegratedPayment__container--transaction { + align-items: center; + margin-top: 10px +} + +.payplugIntegratedPayment__container--transaction .transaction-label { + vertical-align: super; + margin-left: 5px; + font-size: 12px +} + +.payplugIntegratedPayment__container img.lock-icon { + width: 18px; + float: left !important +} + +.payplugIntegratedPayment__container img.payplug-logo { + width: 80px; + height: auto; + vertical-align: text-top; + margin-left: 6px; + display: inline-block; + float: inherit !important +} + +.payplugIntegratedPayment__container--privacy-policy { + text-align: center; + display: inline-block +} + +.payplugIntegratedPayment__container--privacy-policy a { + color: #918f8f; + font-size: 14px +} + +.payplugIntegratedPayment__schemes { + width: 115px; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + display: flex +} + +.payplugIntegratedPayment__schemes label { + display: table-cell +} + +.payplugIntegratedPayment__scheme { + margin: 0 +} + +.payplugIntegratedPayment__scheme span { + cursor: pointer; + width: 33px; + height: 22px; + background: 50%/100% no-repeat; + display: block +} + +.payplugIntegratedPayment__scheme span:before { + width: 100%; + height: 100%; + content: ""; + opacity: 0; + background: 50%/100% no-repeat; + display: block +} + +.payplugIntegratedPayment__scheme input { + display: none +} + +.payplugIntegratedPayment__scheme input:checked+span:before { + opacity: 1 +} + +.payplugIntegratedPayment__scheme--visa span { + background-image: url(visa-dark.87c34e0f.svg) +} + +.payplugIntegratedPayment__scheme--visa span:before { + background-image: url(visa.d11a46f6.svg) +} + +.payplugIntegratedPayment__scheme--mastercard span { + background-image: url(mastercard-dark.8977e440.svg) +} + +.payplugIntegratedPayment__scheme--mastercard span:before { + background-image: url(mastercard.7dd4ce0b.svg) +} + +.payplugIntegratedPayment__scheme--cb span { + background-image: url(./cb-dark.888aec45.svg) +} + +.payplugIntegratedPayment__scheme--cb span:before { + background-image: url(./cb.ccd964e9.svg) +} + +.payplugIntegratedPayment__error { + color: #e91932; + width: 100%; + margin: -10px 0 10px; + padding-left: 4px; + font-size: 12px; + line-height: 18px +} + +.payplugIntegratedPayment__error--cardHolder { + margin: -10px 0 0 +} + +.payplugIntegratedPayment__error--cvv { + justify-self: flex-end; + margin: -10px 0 10px auto +} + +.payplugIntegratedPayment__error--exp, +.payplugIntegratedPayment__error--cvv { + width: 100%; + max-width: 49% +} + +.payplugIntegratedPayment__error--hide { + display: none +} diff --git a/assets/shop/dist/payment/lock.fe8a73cd.svg b/assets/shop/dist/payment/lock.fe8a73cd.svg new file mode 100644 index 00000000..96076615 --- /dev/null +++ b/assets/shop/dist/payment/lock.fe8a73cd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/mastercard-dark.8977e440.svg b/assets/shop/dist/payment/mastercard-dark.8977e440.svg new file mode 100644 index 00000000..371c9023 --- /dev/null +++ b/assets/shop/dist/payment/mastercard-dark.8977e440.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/mastercard.7dd4ce0b.svg b/assets/shop/dist/payment/mastercard.7dd4ce0b.svg new file mode 100644 index 00000000..4a6736e6 --- /dev/null +++ b/assets/shop/dist/payment/mastercard.7dd4ce0b.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/visa-dark.87c34e0f.svg b/assets/shop/dist/payment/visa-dark.87c34e0f.svg new file mode 100644 index 00000000..40891108 --- /dev/null +++ b/assets/shop/dist/payment/visa-dark.87c34e0f.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/dist/payment/visa.d11a46f6.svg b/assets/shop/dist/payment/visa.d11a46f6.svg new file mode 100644 index 00000000..09454b38 --- /dev/null +++ b/assets/shop/dist/payment/visa.d11a46f6.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/shop/entrypoint.js b/assets/shop/entrypoint.js new file mode 100644 index 00000000..9ccfccbe --- /dev/null +++ b/assets/shop/entrypoint.js @@ -0,0 +1 @@ +// Mandatory by test application diff --git a/assets/yarn.lock b/assets/yarn.lock new file mode 100644 index 00000000..961087b2 --- /dev/null +++ b/assets/yarn.lock @@ -0,0 +1,18 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@hotwired/stimulus@^3.0.0": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.2.2.tgz#071aab59c600fed95b97939e605ff261a4251608" + integrity sha512-eGeIqNOQpXoPAIP7tC1+1Yc1yl1xnwYqg+3mzqxyrbE5pg5YFBZcA6YoTiByJB6DKAEsiWtl6tjTJS4IYtbB7A== + +jquery@^3.5.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.7.1.tgz#083ef98927c9a6a74d05a6af02806566d16274de" + integrity sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== + +webfontloader@^1.6.28: + version "1.6.28" + resolved "https://registry.yarnpkg.com/webfontloader/-/webfontloader-1.6.28.tgz#db786129253cb6e8eae54c2fb05f870af6675bae" + integrity sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ== diff --git a/composer.json b/composer.json old mode 100644 new mode 100755 index 0402c1c1..f7d338e1 --- a/composer.json +++ b/composer.json @@ -1,61 +1,83 @@ { "name": "payplug/sylius-payplug-plugin", "type": "sylius-plugin", - "keywords": ["sylius", "sylius-plugin", "payplug"], + "keywords": [ + "sylius", + "sylius-plugin", + "payplug", + "symfony-ux" + ], "description": "PayPlug payment plugin for Sylius applications.", "license": "MIT", "require": { - "php": "^7.4 || ^8.0", + "php": "^8.2", + "ext-json": "*", "giggsey/libphonenumber-for-php": "^8.12", - "payplug/payplug-php": "^3.1", - "sylius/refund-plugin": "^1.0.0", - "sylius/sylius": "^1.9.0 || ^1.10.0", - "symfony/lock": "^4.3|^5.0", - "symfony/validator": "^4.3|^5.0" + "payplug/payplug-php": "^4.0", + "php-http/message-factory": "^1.1", + "sylius/refund-plugin": "^2.0", + "sylius/sylius": "^2.0", + "symfony/asset": "^6.4|| ^7.2", + "symfony/lock": "^6.4|| ^7.2", + "symfony/validator": "^6.4|| ^7.2" }, "require-dev": { - "behat/behat": "^3.7", - "behat/mink-selenium2-driver": "^1.4", - "dmore/behat-chrome-extension": "^1.3", - "dmore/chrome-mink-driver": "^2.7", - "friends-of-behat/mink": "^1.8", - "friends-of-behat/mink-browserkit-driver": "^1.4", - "friends-of-behat/mink-debug-extension": "^2.0", - "friends-of-behat/mink-extension": "^2.4", - "friends-of-behat/page-object-extension": "^0.3", - "friends-of-behat/suite-settings-extension": "^1.0", - "friends-of-behat/symfony-extension": "^2.1", - "friends-of-behat/variadic-extension": "^1.3", - "friendsoftwig/twigcs": "^5.0", - "j13k/yaml-lint": "^1.1", - "php-parallel-lint/php-parallel-lint": "^1.0", - "lakion/mink-debug-extension": "^2.0", - "phpmd/phpmd": "^2.8", - "phpspec/phpspec": "^6.1", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "0.12.91", - "phpstan/phpstan-doctrine": "0.12.41", - "phpstan/phpstan-strict-rules": "^0.12.10", - "phpstan/phpstan-webmozart-assert": "0.12.14", - "phpunit/phpunit": "^9.0", - "slevomat/coding-standard": "^6.3.2", - "sylius-labs/coding-standard": "^4.0", - "symfony/browser-kit": "^5.1", - "symfony/debug-bundle": "^5.1", - "symfony/dotenv": "^5.1", - "symfony/intl": "^5.1", - "symfony/web-profiler-bundle": "^5.1", + "behat/behat": "3.20.0", + "behat/mink-selenium2-driver": "1.7.0", + "dmore/behat-chrome-extension": "1.4.0", + "dmore/chrome-mink-driver": "2.9.3", + "friends-of-behat/mink": "1.11.0", + "friends-of-behat/mink-browserkit-driver": "1.6.2", + "friends-of-behat/mink-debug-extension": "2.1.0", + "friends-of-behat/mink-extension": "2.7.5", + "friends-of-behat/page-object-extension": "0.3.2", + "friends-of-behat/suite-settings-extension": "1.1.0", + "friends-of-behat/symfony-extension": "2.6.0", + "friends-of-behat/variadic-extension": "1.6.0", + "friendsoftwig/twigcs": "6.5.0", + "lakion/mink-debug-extension": "2.0.0", + "mockery/mockery": "1.6.12", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpmd/phpmd": "^2.15.0", + "phpro/grumphp": "^2.12", + "phpstan/extension-installer": "1.4.3", + "phpstan/phpstan": "2.0.4", + "phpstan/phpstan-doctrine": "2.0.1", + "phpstan/phpstan-strict-rules": "2.0.1", + "phpstan/phpstan-webmozart-assert": "2.0.0", + "phpunit/phpunit": "^9.6", + "rector/rector": "2.0.4", + "sylius-labs/coding-standard": "4.4.0", + "sylius/test-application": "^2.1.0@alpha", + "symfony/apache-pack": "*", + "symfony/browser-kit": "^6.4|| ^7.2", + "symfony/debug-bundle": "^6.4|| ^7.2", + "symfony/dotenv": "^6.4|| ^7.2", + "symfony/web-profiler-bundle": "^6.4|| ^7.2", "webmozart/assert": "^1.8" }, "prefer-stable": true, "autoload": { "psr-4": { - "PayPlug\\SyliusPayPlugPlugin\\": "src/", - "Tests\\PayPlug\\SyliusPayPlugPlugin\\": "tests/" + "PayPlug\\SyliusPayPlugPlugin\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\PayPlug\\SyliusPayPlugPlugin\\": ["tests/", "tests/TestApplication/src/"] } }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "php-http/discovery": true, + "phpro/grumphp": true, + "phpstan/extension-installer": true, + "symfony/flex": true, + "symfony/runtime": true, + "symfony/thanks": true + } }, "scripts": { "ecs": "ecs check -c rulesets/ecs.php --ansi --clear-cache .", @@ -68,6 +90,26 @@ "@phpmd", "@phpstan", "@phpunit" + ], + "test-application:install": [ + "vendor/bin/console doctrine:database:drop --force --if-exists -n", + "vendor/bin/console doctrine:database:create -n", + "vendor/bin/console doctrine:migration:migrate -n", + "vendor/bin/console sylius:payment:generate-key -n", + "vendor/bin/console sylius:fixtures:load -n", + "yarn --cwd vendor/sylius/test-application install", + "yarn --cwd vendor/sylius/test-application build", + "vendor/bin/console assets:install --symlink -n" + ], + "test-application:front": [ + "yarn --cwd vendor/sylius/test-application install --force", + "yarn --cwd vendor/sylius/test-application build" ] + }, + "extra": { + "public-dir": "vendor/sylius/test-application/public", + "symfony": { + "require": "^6.4" + } } } diff --git a/src/Resources/config/config.yml b/config/config.yml similarity index 68% rename from src/Resources/config/config.yml rename to config/config.yml index c476d4c2..fb713c19 100644 --- a/src/Resources/config/config.yml +++ b/config/config.yml @@ -1,4 +1,4 @@ imports: - { resource: "state_machine.yml" } - { resource: "resources.yaml" } - - { resource: "ui.yaml" } + - { resource: "twig_hooks/*.yaml" } diff --git a/src/Resources/config/resources.yaml b/config/resources.yaml similarity index 100% rename from src/Resources/config/resources.yaml rename to config/resources.yaml diff --git a/config/routing.yaml b/config/routing.yaml new file mode 100644 index 00000000..84c98416 --- /dev/null +++ b/config/routing.yaml @@ -0,0 +1,6 @@ +payplug_sylius_admin: + resource: "@PayPlugSyliusPayPlugPlugin/config/routing/admin.yaml" + prefix: '/%sylius_admin.path_name%' + +payplug_sylius_shop: + resource: "@PayPlugSyliusPayPlugPlugin/config/routing/shop.yaml" diff --git a/config/routing/admin.yaml b/config/routing/admin.yaml new file mode 100644 index 00000000..4800b8e9 --- /dev/null +++ b/config/routing/admin.yaml @@ -0,0 +1,5 @@ +controllers: + resource: + path: '../../src/Action/Admin/' + namespace: 'PayPlug\SyliusPayPlugPlugin\Action\Admin' + type: attribute \ No newline at end of file diff --git a/config/routing/shop.yaml b/config/routing/shop.yaml new file mode 100644 index 00000000..4f34982e --- /dev/null +++ b/config/routing/shop.yaml @@ -0,0 +1,5 @@ +controllers: + resource: + path: '../../src/Controller/' + namespace: 'PayPlug\SyliusPayPlugPlugin\Controller' + type: attribute \ No newline at end of file diff --git a/config/services.yaml b/config/services.yaml new file mode 100644 index 00000000..8b5dac42 --- /dev/null +++ b/config/services.yaml @@ -0,0 +1,140 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + PayPlug\SyliusPayPlugPlugin\: + resource: '../src/*' + exclude: '../src/{ApiClient,DependencyInjection,Entity,Exception,Model,Repository,PayPlugSyliusPayPlugPlugin.php}' + bind: + Psr\Log\LoggerInterface: '@monolog.logger.payplug' + + PayPlug\SyliusPayPlugPlugin\Repository\PaymentRepositoryInterface: + class: PayPlug\SyliusPayPlugPlugin\Repository\PaymentRepository + parent: sylius.repository.payment + + PayPlug\SyliusPayPlugPlugin\Repository\PaymentMethodRepositoryInterface: + class: PayPlug\SyliusPayPlugPlugin\Repository\PaymentMethodRepository + parent: sylius.repository.payment_method + + PayPlug\SyliusPayPlugPlugin\Controller\OrderController: + parent: sylius.controller.order + autowire: true + + PayPlug\SyliusPayPlugPlugin\Provider\OneySimulation\OneySimulationDataProviderInterface: + class: PayPlug\SyliusPayPlugPlugin\Provider\OneySimulation\OneySimulationDataProvider + + payplug_sylius_payplug_plugin.action.capture: + class: PayPlug\SyliusPayPlugPlugin\Action\CaptureAction + + payplug_sylius_payplug_plugin.action.status: + class: PayPlug\SyliusPayPlugPlugin\Action\StatusAction + + payplug_sylius_payplug_plugin.action.convert_payment: + class: PayPlug\SyliusPayPlugPlugin\Action\ConvertPaymentAction + + payplug_sylius_payplug_plugin.action.notify: + class: PayPlug\SyliusPayPlugPlugin\Action\NotifyAction + + ## Default Payplug Gateway ## + payplug_sylius_payplug_plugin.command_provider.payplug: + class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.command_provider.payplug + index_by: 'action' + tags: + - name: sylius.payment_request.command_provider + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory::FACTORY_NAME + payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug: + class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.http_response_provider.payplug + index_by: action + tags: + - name: sylius.payment_request.provider.http_response + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory::FACTORY_NAME + + ## Oney Payplug Gateway ## + payplug_sylius_payplug_plugin.command_provider.payplug_oney: + class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.command_provider.payplug_oney + index_by: 'action' + tags: + - name: sylius.payment_request.command_provider + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory::FACTORY_NAME + payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug_oney: + class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.http_response_provider.payplug_oney + index_by: action + tags: + - name: sylius.payment_request.provider.http_response + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory::FACTORY_NAME + + + ## Bancontact Payplug Gateway ## + payplug_sylius_payplug_plugin.command_provider.payplug_bancontact: + class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.command_provider.payplug_bancontact + index_by: 'action' + tags: + - name: sylius.payment_request.command_provider + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory::FACTORY_NAME + payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug_bancontact: + class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.http_response_provider.payplug_bancontact + index_by: action + tags: + - name: sylius.payment_request.provider.http_response + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory::FACTORY_NAME + + + ## Amex Payplug Gateway ## + payplug_sylius_payplug_plugin.command_provider.payplug_american_express: + class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.command_provider.payplug_american_express + index_by: 'action' + tags: + - name: sylius.payment_request.command_provider + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory::FACTORY_NAME + payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug_american_express: + class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.http_response_provider.payplug_american_express + index_by: action + tags: + - name: sylius.payment_request.provider.http_response + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory::FACTORY_NAME + + ## Apple Pay Payplug Gateway ## + payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay: + class: Sylius\Bundle\PaymentBundle\CommandProvider\ActionsCommandProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay + index_by: 'action' + tags: + - name: sylius.payment_request.command_provider + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory::FACTORY_NAME + payplug_sylius_payplug_plugin.provider.order_pay.http_response.payplug_apple_pay: + class: Sylius\Bundle\PaymentBundle\Provider\ActionsHttpResponseProvider + arguments: + - !tagged_locator + tag: payplug_sylius_payplug_plugin.http_response_provider.payplug_apple_pay + index_by: action + tags: + - name: sylius.payment_request.provider.http_response + gateway_factory: !php/const PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory::FACTORY_NAME diff --git a/config/services/client.xml b/config/services/client.xml new file mode 100644 index 00000000..0ca32b00 --- /dev/null +++ b/config/services/client.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + payplug + + + + + payplug_oney + + + + + payplug_bancontact + + + + + payplug_apple_pay + + + + + american_express + + + diff --git a/config/services/gateway.xml b/config/services/gateway.xml new file mode 100644 index 00000000..eeda89e7 --- /dev/null +++ b/config/services/gateway.xml @@ -0,0 +1,51 @@ + + + + + + + + PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory + + + + + + PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory + + + + + + PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory + + + + + + PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory + + + + + + PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory + + + + diff --git a/config/state_machine.yml b/config/state_machine.yml new file mode 100644 index 00000000..2781aef2 --- /dev/null +++ b/config/state_machine.yml @@ -0,0 +1,10 @@ +framework: + workflows: + !php/const Sylius\Component\Core\OrderPaymentTransitions::GRAPH: + transitions: + oney_request_payment: # Allow to request payment from authorized (for Oney) + from: + - cart + - authorized + to: + - awaiting_payment diff --git a/config/twig_hooks/admin.yaml b/config/twig_hooks/admin.yaml new file mode 100644 index 00000000..931ecf69 --- /dev/null +++ b/config/twig_hooks/admin.yaml @@ -0,0 +1,49 @@ +sylius_twig_hooks: + hooks: + sylius_admin.payment_method.update.content: + payplug_flashes: + template: '@PayPlugSyliusPayPlugPlugin/admin/shared/flashes.html.twig' + priority: 350 + 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug': &payplugGateway + live_checkbox: &liveCheckbox + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/live_checkbox.html.twig' + priority: 0 + one_click: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/one_click.html.twig' + priority: 0 + integrated_payment: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/integrated_payment.html.twig' + priority: 0 + deferred_capture: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/deferred_capture.html.twig' + priority: 0 + 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_oney': &oneyGateway + live_checkbox: *liveCheckbox + fees_for: + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/fees_for.html.twig' + priority: 0 + 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_bancontact': &bancontactGateway + live_checkbox: *liveCheckbox + 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_apple_pay': &applePayGateway + live_checkbox: *liveCheckbox + + 'sylius_admin.payment_method.create.content.form.sections.gateway_configuration.payplug_american_express': &amexGateway + live_checkbox: *liveCheckbox + + 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug': + <<: *payplugGateway + renew_oauth: &renewOAuth + template: '@PayPlugSyliusPayPlugPlugin/admin/payment_method/form/renew_oauth.html.twig' + priority: -5 + 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_oney': + <<: *oneyGateway + renew_oauth: *renewOAuth + 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_bancontact': + <<: *bancontactGateway + renew_oauth: *renewOAuth + 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_apple_pay': + <<: *applePayGateway + renew_oauth: *renewOAuth + 'sylius_admin.payment_method.update.content.form.sections.gateway_configuration.payplug_american_express': + <<: *amexGateway + renew_oauth: *renewOAuth diff --git a/config/twig_hooks/shop.yaml b/config/twig_hooks/shop.yaml new file mode 100644 index 00000000..ed250d5f --- /dev/null +++ b/config/twig_hooks/shop.yaml @@ -0,0 +1,46 @@ +sylius_twig_hooks: + hooks: + 'sylius_shop.product.show.content.info.summary': + pay_with_oney: + template: '@PayPlugSyliusPayPlugPlugin/shop/oney/product/pay_with_oney.html.twig' + priority: 101 + 'sylius_shop.cart.index.content.form.sections.general#right': + pay_with_oney: + template: '@PayPlugSyliusPayPlugPlugin/shop/oney/cart/pay_with_oney.html.twig' + priority: 1 + 'sylius.shop.account.saved_cards.index.subcontent': + header: + template: '@PayPlugSyliusPayPlugPlugin/shop/saved_cards/index/_header.html.twig' + priority: 20 + subcontent: + template: "@PayPlugSyliusPayPlugPlugin/shop/saved_cards/index/_subcontent.html.twig" + priority: 10 + + 'sylius_shop.checkout.select_payment': + modal: + template: '@PayPlugSyliusPayPlugPlugin/shared/modal/index.html.twig' + priority: 0 + + 'sylius_shop.shared.form.select_payment.payment': + choice: + template: '@PayPlugSyliusPayPlugPlugin/shared/form/select_payment/payment/choice.html.twig' + priority: 0 + + 'sylius_shop.shared.form.select_payment.payment.choice.details': + choice: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/choice.html.twig' + 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug': + payplug: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_payplug.html.twig' + 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_oney': + oney: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_oney.html.twig' + 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_bancontact': + bancontact: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_bancontact.html.twig' + 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_apple_pay': + apple_pay: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_apple_pay.html.twig' + 'sylius_shop.shared.form.select_payment.payment.choice.details#payplug_american_express': + american_express: + template: '@PayPlugSyliusPayPlugPlugin/shop/select_payment/_american_express.html.twig' diff --git a/doc/authorized_payment.md b/doc/authorized_payment.md new file mode 100644 index 00000000..83332706 --- /dev/null +++ b/doc/authorized_payment.md @@ -0,0 +1,155 @@ +# Authorized Payment + +This feature allow merchant to deferred the capture of the payment. +The payment is authorized and the capture can be done later. + +> [!IMPORTANT] +> The authorized payment feature is only available for the "PayPlug" payment gateway. + +## Activation + +On the payment method configuration, you can enable the deferred capture feature. + +![admin_deferred_capture_feature.png](images/admin_deferred_capture_feature.png) + +## Trigger the capture + +### Periodically + +An authorized payment is valid for 7 days. +You can trigger the capture of the authorized payment by running the following command: + +```bash +$ bin/console payplug:capture-authorized-payments --days=6 +``` + +It will capture all authorized payments that are older than 6 days. + +> [!TIP] +> You can add this command to a cron job to automate the capture of the authorized payments. + +### Programmatically + +An authorized payment is in state `AUTHORIZED`. +A capture trigger is placed on the complete transition for such payments. + +```yaml +winzou_state_machine: + sylius_payment: + callbacks: + before: + payplug_sylius_payplug_plugin_complete: + on: ["complete"] + do: ["@payplug_sylius_payplug_plugin.payment_processing.capture", "process"] + args: ["object"] +``` +> [!NOTE] +> This configuration is already added by the plugin. + +### With Winzou State Machine + +For example, if you want to trigger the capture when an order is shipped, you can create a callback on the `sylius_order_shipping` state machine. + +File: `config/packages/winzou_state_machine.yaml` + +```yaml +winzou_state_machine: + sylius_order_shipping: + callbacks: + before: + app_ensure_capture_payment: + on: ["ship"] + do: ['@App\StateMachine\CaptureOrderProcessor', "process"] + args: ["object"] +``` + +File : `src/StateMachine/CaptureOrderProcessor.php` + +```php +getLastPayment(PaymentInterface::STATE_AUTHORIZED); + if (null === $payment) { + // No payment in authorized state, nothing to do here + return; + } + + $this->stateMachineFactory + ->get($payment, PaymentTransitions::GRAPH) + ->apply(PaymentTransitions::TRANSITION_COMPLETE); + + if (PaymentInterface::STATE_COMPLETED !== $payment->getState()) { + throw new \LogicException('Oh no! Payment capture failed 💸'); + } + } +} +``` + +### With Symfony Workflow (default in Sylius 2) + +If you are using Symfony Workflow, you can create a custom action to capture the payment, with a transition listener. + +File: `src/StateMachine/CaptureOrderProcessor.php` + +```php +getSubject(); + if (!$order instanceof OrderInterface) { + throw new \LogicException('Expected an instance of OrderInterface'); + } + + $payment = $order->getLastPayment(PaymentInterface::STATE_AUTHORIZED); + if (null === $payment) { + // No payment in authorized state, nothing to do here + return; + } + + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_COMPLETE); + if (PaymentInterface::STATE_COMPLETED !== $payment->getState()) { + throw new \LogicException('Oh no! Payment capture failed 💸'); + } + } +} +``` diff --git a/doc/development.md b/doc/development.md index 49ab58b7..ab362af8 100644 --- a/doc/development.md +++ b/doc/development.md @@ -3,13 +3,11 @@ ## Assets For the sake of quickness, the usage of a tool like [Parcel](https://github.com/parcel-bundler/parcel/tree/1.x) shows that its efficiency is indeed undeniable. - -So, if you want to edit assets (js, scss, ...) you'll likely go into `src/Resources/dev` and run `yarn install`. - +So, if you want to edit assets (js, scss, ...) you'll likely go into `assets` and run `yarn install`. Then, you'll find a list of commands inside `package.json` which are : ```bash -$ (cd src/Resources/dev && yarn build) +$ (cd assets && yarn build) ``` Or, if you prefer the dev mode; a `watch` command that compile in real time, then run: @@ -18,9 +16,10 @@ Or, if you prefer the dev mode; a `watch` command that compile in real time, the $ (cd src/Resources/dev && yarn dev) ``` -You can add any resources as far as Parcel can go, but those have to be located in `/pages` otherwize they won't be compiled. +You can add any resources as far as Parcel can go, +but those have to be located in `/pages` otherwise they won't be compiled. -Assets can be found in `src/Resources/public/assets/oney` so you'll have to install them in your application by running: +Assets can be found in `public/assets/oney` so you'll have to install them in your application by running: ```bash $ bin/console assets:install --symlink @@ -28,7 +27,8 @@ $ bin/console assets:install --symlink $ bin/console sylius:theme:assets:install --symlink # e.g if bootstrapTheme is enabled ``` -To make it fully compatible with [Sylius Bootstrap Theme](https://github.com/Sylius/BootstrapTheme), some lines have to be added to ̀the main entrypoint (such as `app.js`) of the theme: +To make it fully compatible with [Sylius Bootstrap Theme](https://github.com/Sylius/BootstrapTheme), +some lines have to be added to the main entrypoint (such as `app.js`) of the theme: ```js const $ = require('jquery'); diff --git a/doc/images/admin_deferred_capture_feature.png b/doc/images/admin_deferred_capture_feature.png new file mode 100644 index 00000000..0244aeba Binary files /dev/null and b/doc/images/admin_deferred_capture_feature.png differ diff --git a/grumphp.yml b/grumphp.yml new file mode 100644 index 00000000..1ae601d8 --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,32 @@ +grumphp: + ascii: + failed: ~ + succeeded: ~ + tasks: + composer: + no_check_all: true + jsonlint: + detect_key_conflicts: true + phplint: + exclude: ['vendor', 'tests/Application/*'] + triggered_by: ['php'] + phpstan: + level: ~ + configuration: 'ruleset/phpstan.neon' + use_grumphp_paths: false + securitychecker_symfony: ~ + yamllint: + parse_custom_tags: true + ecs: + config: 'ruleset/ecs.php' + no-progress-bar: true + twigcs: + path: 'src/' + severity: error + phpcs: + standard: "ruleset" + warning_severity: 0 + whitelist_patterns: + - 'src' + exclude: + - 'PSR12.Files.FileHeader' \ No newline at end of file diff --git a/install/Application/.gitignore b/install/Application/.gitignore deleted file mode 100644 index 83c72082..00000000 --- a/install/Application/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.env.*.local -.env.local -.env.local.php diff --git a/install/Application/config/packages/payplug.yaml b/install/Application/config/packages/payplug.yaml deleted file mode 100644 index 1d41d8b4..00000000 --- a/install/Application/config/packages/payplug.yaml +++ /dev/null @@ -1,30 +0,0 @@ -parameters: - sylius_refund.supported_gateways: - - payplug - - payplug_oney - - cash_on_delivery - -services: - payplug_sylius_payplug_plugin.api_client.payplug: - class: Tests\PayPlug\SyliusPayPlugPlugin\Behat\Mocker\PayPlugApiClient - public: true - arguments: - - "@service_container" - - 'payplug_sylius_payplug_plugin.api_client.payplug' - - payplug_sylius_payplug_plugin.api_client.oney: - class: Tests\PayPlug\SyliusPayPlugPlugin\Behat\Mocker\PayPlugApiClient - public: true - arguments: - - "@service_container" - - 'payplug_sylius_payplug_plugin.api_client.oney' - - Tests\Sylius\RefundPlugin\Behat\Services\Generator\FailedCreditMemoGenerator: - decorates: 'Sylius\RefundPlugin\Generator\CreditMemoGeneratorInterface' - arguments: - - '@Tests\Sylius\RefundPlugin\Behat\Services\Generator\FailedCreditMemoGenerator.inner' - - Tests\Sylius\RefundPlugin\Behat\Services\Factory\FailedRefundPaymentFactory: - decorates: 'sylius_refund.factory.refund_payment' - arguments: - - '@Tests\Sylius\RefundPlugin\Behat\Services\Factory\FailedRefundPaymentFactory.inner' diff --git a/install/Application/config/packages/sylius_payplug.yaml b/install/Application/config/packages/sylius_payplug.yaml deleted file mode 100644 index 82462ec0..00000000 --- a/install/Application/config/packages/sylius_payplug.yaml +++ /dev/null @@ -1,3 +0,0 @@ -imports: - - { resource: "@PayPlugSyliusPayPlugPlugin/Resources/config/config.yml" } - - { resource: "@PayPlugSyliusPayPlugPlugin/Resources/config/services.xml" } diff --git a/install/Application/config/packages/sylius_refund.yaml b/install/Application/config/packages/sylius_refund.yaml deleted file mode 100644 index ce7ff8ae..00000000 --- a/install/Application/config/packages/sylius_refund.yaml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: "@SyliusRefundPlugin/Resources/config/app/config.yml" } diff --git a/install/Application/config/routes/payplug.yaml b/install/Application/config/routes/payplug.yaml deleted file mode 100644 index 778bf549..00000000 --- a/install/Application/config/routes/payplug.yaml +++ /dev/null @@ -1,2 +0,0 @@ -sylius_payplug: - resource: "@PayPlugSyliusPayPlugPlugin/Resources/config/routing.yaml" diff --git a/install/Application/config/services_payplug.yaml b/install/Application/config/services_payplug.yaml deleted file mode 100644 index 1d41d8b4..00000000 --- a/install/Application/config/services_payplug.yaml +++ /dev/null @@ -1,30 +0,0 @@ -parameters: - sylius_refund.supported_gateways: - - payplug - - payplug_oney - - cash_on_delivery - -services: - payplug_sylius_payplug_plugin.api_client.payplug: - class: Tests\PayPlug\SyliusPayPlugPlugin\Behat\Mocker\PayPlugApiClient - public: true - arguments: - - "@service_container" - - 'payplug_sylius_payplug_plugin.api_client.payplug' - - payplug_sylius_payplug_plugin.api_client.oney: - class: Tests\PayPlug\SyliusPayPlugPlugin\Behat\Mocker\PayPlugApiClient - public: true - arguments: - - "@service_container" - - 'payplug_sylius_payplug_plugin.api_client.oney' - - Tests\Sylius\RefundPlugin\Behat\Services\Generator\FailedCreditMemoGenerator: - decorates: 'Sylius\RefundPlugin\Generator\CreditMemoGeneratorInterface' - arguments: - - '@Tests\Sylius\RefundPlugin\Behat\Services\Generator\FailedCreditMemoGenerator.inner' - - Tests\Sylius\RefundPlugin\Behat\Services\Factory\FailedRefundPaymentFactory: - decorates: 'sylius_refund.factory.refund_payment' - arguments: - - '@Tests\Sylius\RefundPlugin\Behat\Services\Factory\FailedRefundPaymentFactory.inner' diff --git a/install/Application/src/Entity/Customer/Customer.php b/install/Application/src/Entity/Customer/Customer.php deleted file mode 100644 index 805fdd5d..00000000 --- a/install/Application/src/Entity/Customer/Customer.php +++ /dev/null @@ -1,25 +0,0 @@ -cards = new ArrayCollection(); - } -} diff --git a/src/Migrations/Version20210410143918.php b/migrations/Version20210410143918.php similarity index 100% rename from src/Migrations/Version20210410143918.php rename to migrations/Version20210410143918.php diff --git a/src/Migrations/Version20210823123914.php b/migrations/Version20210823123914.php similarity index 100% rename from src/Migrations/Version20210823123914.php rename to migrations/Version20210823123914.php diff --git a/phpspec.yml.dist b/phpspec.yml.dist deleted file mode 100644 index cdbf5061..00000000 --- a/phpspec.yml.dist +++ /dev/null @@ -1,4 +0,0 @@ -suites: - main: - namespace: PayPlug\SyliusPayPlugPlugin - psr4_prefix: PayPlug\SyliusPayPlugPlugin diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8e5a0339..b01264ac 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,19 +1,18 @@ + bootstrap="vendor/sylius/test-application/config/bootstrap.php"> - vendor/payplug/sylius-payplug-plugin/tests/PHPUnit + tests/PHPUnit - - + diff --git a/public/assets/american-express/logo.svg b/public/assets/american-express/logo.svg new file mode 100644 index 00000000..b6dfc5b8 --- /dev/null +++ b/public/assets/american-express/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/apple-pay/logo.svg b/public/assets/apple-pay/logo.svg new file mode 100644 index 00000000..5a86310e --- /dev/null +++ b/public/assets/apple-pay/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/bancontact/logo.svg b/public/assets/bancontact/logo.svg new file mode 100644 index 00000000..1ab4d0f9 --- /dev/null +++ b/public/assets/bancontact/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/Resources/public/assets/oney/3x.svg b/public/assets/oney/3x.svg similarity index 100% rename from src/Resources/public/assets/oney/3x.svg rename to public/assets/oney/3x.svg diff --git a/src/Resources/public/assets/oney/3x4x-alt.svg b/public/assets/oney/3x4x-alt.svg similarity index 100% rename from src/Resources/public/assets/oney/3x4x-alt.svg rename to public/assets/oney/3x4x-alt.svg diff --git a/public/assets/oney/3x4x-without-fees-alt.svg b/public/assets/oney/3x4x-without-fees-alt.svg new file mode 100644 index 00000000..5c783bbb --- /dev/null +++ b/public/assets/oney/3x4x-without-fees-alt.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/public/assets/oney/3x4x-without-fees.svg b/public/assets/oney/3x4x-without-fees.svg new file mode 100644 index 00000000..a029d51b --- /dev/null +++ b/public/assets/oney/3x4x-without-fees.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/Resources/public/assets/oney/3x4x.svg b/public/assets/oney/3x4x.svg similarity index 100% rename from src/Resources/public/assets/oney/3x4x.svg rename to public/assets/oney/3x4x.svg diff --git a/src/Resources/public/assets/oney/4x.svg b/public/assets/oney/4x.svg similarity index 100% rename from src/Resources/public/assets/oney/4x.svg rename to public/assets/oney/4x.svg diff --git a/src/Resources/public/assets/oney/logo.svg b/public/assets/oney/logo.svg similarity index 100% rename from src/Resources/public/assets/oney/logo.svg rename to public/assets/oney/logo.svg diff --git a/public/assets/oney/oney_x3_with_fees.svg b/public/assets/oney/oney_x3_with_fees.svg new file mode 100644 index 00000000..ecd9c79d --- /dev/null +++ b/public/assets/oney/oney_x3_with_fees.svg @@ -0,0 +1,10 @@ + + + + + 3x + + + diff --git a/public/assets/oney/oney_x3_without_fees.svg b/public/assets/oney/oney_x3_without_fees.svg new file mode 100644 index 00000000..20c5dbc1 --- /dev/null +++ b/public/assets/oney/oney_x3_without_fees.svg @@ -0,0 +1,23 @@ + + FR_3x_fr_v + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/oney/oney_x4_with_fees.svg b/public/assets/oney/oney_x4_with_fees.svg new file mode 100644 index 00000000..7ec13955 --- /dev/null +++ b/public/assets/oney/oney_x4_with_fees.svg @@ -0,0 +1,10 @@ + + + + + 4x + + + diff --git a/public/assets/oney/oney_x4_without_fees.svg b/public/assets/oney/oney_x4_without_fees.svg new file mode 100644 index 00000000..362e95ee --- /dev/null +++ b/public/assets/oney/oney_x4_without_fees.svg @@ -0,0 +1,23 @@ + + FR_4x_fr_v + + diff --git a/public/assets/shop/images/integrated/lock.svg b/public/assets/shop/images/integrated/lock.svg new file mode 100644 index 00000000..316e1f5e --- /dev/null +++ b/public/assets/shop/images/integrated/lock.svg @@ -0,0 +1,9 @@ + + + General/Icons/Icon 24x24 - Lock + + + + + + \ No newline at end of file diff --git a/public/assets/shop/images/integrated/logo-payplug.png b/public/assets/shop/images/integrated/logo-payplug.png new file mode 100644 index 00000000..b67d7cce Binary files /dev/null and b/public/assets/shop/images/integrated/logo-payplug.png differ diff --git a/rulesets/.php_md.xml b/ruleset/.php_md.xml similarity index 100% rename from rulesets/.php_md.xml rename to ruleset/.php_md.xml diff --git a/ruleset/ecs.php b/ruleset/ecs.php new file mode 100644 index 00000000..7de9449a --- /dev/null +++ b/ruleset/ecs.php @@ -0,0 +1,19 @@ +import(dirname(__DIR__) . '/vendor/sylius-labs/coding-standard/ecs.php'); + + $ecsConfig->paths([ + dirname(__DIR__, 1) . '/src', + dirname(__DIR__, 1) . '/tests/Behat', + dirname(__DIR__, 1) . '/tests/PHPUnit', + ]); + + /** @phpstan-ignore-next-line */ + $ecsConfig->rule(\SlevomatCodingStandard\Sniffs\Classes\RequireMultiLineMethodSignatureSniff::class); + $ecsConfig->skip([\PhpCsFixer\Fixer\Basic\BracesFixer::class]); +}; diff --git a/ruleset/phpstan-baseline.neon b/ruleset/phpstan-baseline.neon new file mode 100644 index 00000000..1d16fed3 --- /dev/null +++ b/ruleset/phpstan-baseline.neon @@ -0,0 +1,1463 @@ +parameters: + ignoreErrors: + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Action/Admin/CompleteRefundPaymentAction.php + + - + message: '#^Parameter \#1 \$id of class Sylius\\RefundPlugin\\Event\\RefundPaymentGenerated constructor expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/Admin/CompleteRefundPaymentAction.php + + - + message: '#^Parameter \#5 \$paymentMethodId of class Sylius\\RefundPlugin\\Event\\RefundPaymentGenerated constructor expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/Admin/CompleteRefundPaymentAction.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Action/Admin/RefundUnitsAction.php + + - + message: '#^Cannot access offset ''billing'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot access offset ''can_save_cards'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot access offset ''cancel_url'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot access offset ''postcode'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 6 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot access offset ''shipping'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot access property \$payment_url on mixed\.$#' + identifier: property.nonObject + count: 2 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 6 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot call method getFirstModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot call method getModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot call method getToken\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/CaptureAction.php + + - + message: '#^Parameter \#1 \$timestamp of method DateTimeImmutable\:\:setTimestamp\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/CaptureAction.php + + - + message: '#^Parameter \#1 \$url of class Payum\\Core\\Reply\\HttpRedirect constructor expects string, mixed given\.$#' + identifier: argument.type + count: 3 + path: ../src/Action/CaptureAction.php + + - + message: '#^Cannot call method getSource\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/ConvertPaymentAction.php + + - + message: '#^Cannot call method setResult\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/ConvertPaymentAction.php + + - + message: '#^Cannot call method getFirstModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Action/NotifyAction.php + + - + message: '#^Cannot call method getModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/NotifyAction.php + + - + message: '#^Parameter \#1 \$payment of method PayPlug\\SyliusPayPlugPlugin\\Handler\\PaymentNotificationHandler\:\:treat\(\) expects Sylius\\Component\\Core\\Model\\PaymentInterface, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/NotifyAction.php + + - + message: '#^Parameter \#1 \$payment of method PayPlug\\SyliusPayPlugPlugin\\Handler\\RefundNotificationHandler\:\:treat\(\) expects Sylius\\Component\\Core\\Model\\PaymentInterface, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/NotifyAction.php + + - + message: '#^Access to an undefined property PayPlug\\SyliusPayPlugPlugin\\Action\\StatusAction\:\:\$stateMachineFactory\.$#' + identifier: property.notFound + count: 2 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method can\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method getFirstModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method getModel\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Action/StatusAction.php + + - + message: '#^Cannot call method markNew\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Parameter \#1 \$payment of method PayPlug\\SyliusPayPlugPlugin\\Handler\\PaymentNotificationHandler\:\:treat\(\) expects Sylius\\Component\\Core\\Model\\PaymentInterface, mixed given\.$#' + identifier: argument.type + count: 3 + path: ../src/Action/StatusAction.php + + - + message: '#^Parameter \#1 \$payment of method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandlerInterface\:\:updatePaymentStatus\(\) expects Sylius\\Component\\Core\\Model\\PaymentInterface, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Parameter \#1 \$paymentId of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:retrieve\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 3 + path: ../src/Action/StatusAction.php + + - + message: '#^Parameter \#1 \$status of method PayPlug\\SyliusPayPlugPlugin\\Action\\StatusAction\:\:markRequestAs\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Parameter \#2 \$request of method PayPlug\\SyliusPayPlugPlugin\\Action\\StatusAction\:\:markRequestAs\(\) expects Payum\\Core\\Request\\GetStatusInterface, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Action/StatusAction.php + + - + message: '#^Access to constant VERSION on an unknown class Sylius\\Bundle\\CoreBundle\\Application\\Kernel\.$#' + identifier: class.notFound + count: 2 + path: ../src/ApiClient/PayPlugApiClient.php + + - + message: '#^Anonymous function should return array but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/ApiClient/PayPlugApiClient.php + + - + message: '#^Binary operation "\." between ''Sylius/'' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 2 + path: ../src/ApiClient/PayPlugApiClient.php + + - + message: '#^PHPDoc tag @var with type Payplug\\Resource\\Refund\|null is not subtype of type Payplug\\Refund\|null\.$#' + identifier: varTag.type + count: 2 + path: ../src/ApiClient/PayPlugApiClient.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfig\|null is not subtype of type Sylius\\Resource\\Model\\ResourceInterface\|null\.$#' + identifier: varTag.type + count: 1 + path: ../src/ApiClient/PayPlugApiClientFactory.php + + - + message: '#^Parameter \#1 \$secretKey of class PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClient constructor expects string, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/ApiClient/PayPlugApiClientFactory.php + + - + message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Cannot access offset ''enabled'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Cannot call method getHostname\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Checker\\CanSavePayplugPaymentMethodChecker\:\:isEnabled\(\) should return bool but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Parameter \#1 \$method of method PayPlug\\SyliusPayPlugPlugin\\Checker\\CanSavePayplugPaymentMethodChecker\:\:isAllowedDomainNames\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Parameter \#2 \$haystack of function in_array expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Checker/CanSavePayplugPaymentMethodChecker.php + + - + message: '#^Cannot access offset ''allowed_countries'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Cannot access offset ''max_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Cannot access offset ''min_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Cannot access offset ''oney'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 3 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Cannot access offset string on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Parameter \#2 \$haystack of function in_array expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Checker/OneyChecker.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Command/CaptureAuthorizedPaymentCommand.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Command/CaptureAuthorizedPaymentCommand.php + + - + message: '#^Parameter \#2 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Command/CaptureAuthorizedPaymentCommand.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Command\\CaptureAuthorizedPaymentCommand\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/Command/CaptureAuthorizedPaymentCommand.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Controller/CardController.php + + - + message: '#^Parameter \#2 \$type of method Symfony\\Component\\Form\\FormBuilderInterface\:\:add\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/CompleteInfoController.php + + - + message: '#^PHPDoc tag @param for parameter \$paymentMethodRepository contains generic type Sylius\\Component\\Resource\\Repository\\RepositoryInterface\ but interface Sylius\\Component\\Resource\\Repository\\RepositoryInterface is not generic\.$#' + identifier: generics.notGeneric + count: 1 + path: ../src/Controller/IntegratedPaymentController.php + + - + message: '#^PHPDoc type for property PayPlug\\SyliusPayPlugPlugin\\Controller\\IntegratedPaymentController\:\:\$paymentMethodRepository contains generic type Sylius\\Component\\Resource\\Repository\\RepositoryInterface\ but interface Sylius\\Component\\Resource\\Repository\\RepositoryInterface is not generic\.$#' + identifier: generics.notGeneric + count: 1 + path: ../src/Controller/IntegratedPaymentController.php + + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../src/Controller/IpnAction.php + + - + message: '#^Parameter \#1 \$payplugPaymentId of method PayPlug\\SyliusPayPlugPlugin\\Repository\\PaymentRepositoryInterface\:\:findOneByPayPlugPaymentId\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/IpnAction.php + + - + message: '#^Parameter \#1 \$secretKey of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:initialise\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/IpnAction.php + + - + message: '#^Parameter \#2 \$key of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientFactoryInterface\:\:create\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/IpnAction.php + + - + message: '#^Cannot access offset ''payment_url'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^Cannot access offset ''return_url'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.type + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^Parameter \#1 \$url of class Symfony\\Component\\HttpFoundation\\RedirectResponse constructor expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^Parameter \#2 \$key of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientFactory\:\:create\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/OneClickAction.php + + - + message: '#^Cannot cast mixed to int\.$#' + identifier: cast.int + count: 1 + path: ../src/Controller/OneyIsProductEligible.php + + - + message: '#^PHPDoc tag @var with type int\|null is not subtype of native type int\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Controller/OneyIsProductEligible.php + + - + message: '#^Parameter \#2 \$productVariantCode of method PayPlug\\SyliusPayPlugPlugin\\Controller\\OneyIsProductEligible\:\:isProductEligible\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Controller/OneyIsProductEligible.php + + - + message: '#^Cannot cast mixed to int\.$#' + identifier: cast.int + count: 1 + path: ../src/Controller/OneySimulationPopin.php + + - + message: '#^PHPDoc tag @var with type int\|null is not subtype of native type int\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Controller/OneySimulationPopin.php + + - + message: '#^Binary operation "\." between ''apple_pay_cancel'' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../src/Controller/OrderController.php + + # Session Specific + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 4 + path: ../src/Controller/OrderController.php + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Action/Admin/Auth/UnifiedAuthenticationController.php + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Validator/PaymentMethodValidator.php + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/EventListener/PostSavePaymentMethodEventListener.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Controller/OrderController.php + + - + message: '#^Cannot call method can\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Controller/OrderController.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Controller/OrderController.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Controller\\OrderController\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/Controller/OrderController.php + + - + message: '#^Cannot access offset ''company_name'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Cannot access offset ''first_name'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Cannot access offset ''last_name'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^PHPDoc tag @SuppressWarnings has invalid value \(\(PHPMD\.UnusedFormalParameter\)\)\: Unexpected token "\.UnusedFormalParameter\)", expected ''\)'' at offset 34 on line 2$#' + identifier: phpDoc.parseError + count: 1 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Parameter \#2 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Parameter \#3 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Parameter &\$landingPhone by\-ref type of method PayPlug\\SyliusPayPlugPlugin\\Creator\\PayPlugPaymentDataCreator\:\:loadPhoneNumbers\(\) expects string\|null, mixed given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Parameter &\$mobilePhone by\-ref type of method PayPlug\\SyliusPayPlugPlugin\\Creator\\PayPlugPaymentDataCreator\:\:loadPhoneNumbers\(\) expects string\|null, mixed given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../src/Creator/PayPlugPaymentDataCreator.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.type + count: 1 + path: ../src/Creator/RefundUnitsCommandCreatorDecorator.php + + - + message: '#^Parameter \#1 \$paymentId of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:retrieve\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Creator/RefundUnitsCommandCreatorDecorator.php + + - + message: '#^Parameter \#1 \$unit of method PayPlug\\SyliusPayPlugPlugin\\Creator\\RefundUnitsCommandCreatorDecorator\:\:getAmount\(\) expects Sylius\\RefundPlugin\\Model\\UnitRefundInterface, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Creator/RefundUnitsCommandCreatorDecorator.php + + - + message: '#^Parameter \#1 \$units of method Sylius\\RefundPlugin\\Converter\\RefundUnitsConverterInterface\:\:convert\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Creator/RefundUnitsCommandCreatorDecorator.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Entity\\RefundHistory\:\:\$value type mapping mismatch\: database can contain int\|null but property expects int\.$#' + identifier: doctrine.columnType + count: 1 + path: ../src/Entity/RefundHistory.php + + - + message: '#^Trait PayPlug\\SyliusPayPlugPlugin\\Entity\\Traits\\CustomerTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: ../src/Entity/Traits/CustomerTrait.php + + - + message: '#^Trait PayPlug\\SyliusPayPlugPlugin\\Entity\\Traits\\PaymentMethodTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: ../src/Entity/Traits/PaymentMethodTrait.php + + - + message: '#^Trait PayPlug\\SyliusPayPlugPlugin\\Entity\\Traits\\PaymentTrait is used zero times and is not analysed\.$#' + identifier: trait.unused + count: 1 + path: ../src/Entity/Traits/PaymentTrait.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/EventSubscriber/DisplayOneyGatewayFormEventSubscriber.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/EventSubscriber/PostPaymentSelectEventSubscriber.php + + - + message: '#^Cannot call method can\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/EventSubscriber/PostPaymentSelectEventSubscriber.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/EventSubscriber/PostPaymentSelectEventSubscriber.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\EventSubscriber\\PostPaymentSelectEventSubscriber\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/EventSubscriber/PostPaymentSelectEventSubscriber.php + + - + message: '#^Parameter \#1 \$input of method Payum\\Core\\Bridge\\Spl\\ArrayObject\:\:defaults\(\) expects array\|Traversable, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/AbstractGatewayFactory.php + + - + message: '#^Parameter \#1 \$required of method Payum\\Core\\Bridge\\Spl\\ArrayObject\:\:validateNotEmpty\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/AbstractGatewayFactory.php + + - + message: '#^Parameter \#1 \$secretKey of class PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClient constructor expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/AbstractGatewayFactory.php + + - + message: '#^Parameter \#2 \$factoryName of class PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClient constructor expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/AbstractGatewayFactory.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Form/Type/AbstractGatewayConfigurationType.php + + - + message: '#^Cannot call method getId\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Form/Type/AbstractGatewayConfigurationType.php + + - + message: '#^Cannot access offset ''secretKey'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Cannot call method getConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Cannot call method getData\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Cannot call method getGatewayConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Gateway\\Validator\\Constraints\\IsCanSaveCardsValidator\:\:validate\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Parameter \#2 \$key of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientFactory\:\:create\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSaveCardsValidator.php + + - + message: '#^Cannot call method getChannels\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Cannot call method getData\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Cannot call method getFactoryName\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Cannot call method getGatewayConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Gateway\\Validator\\Constraints\\IsCanSavePaymentMethodValidator\:\:validate\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Parameter \#2 \$channels of method PayPlug\\SyliusPayPlugPlugin\\Checker\\CanSavePayplugPaymentMethodChecker\:\:isEnabled\(\) expects Doctrine\\Common\\Collections\\Collection, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/Validator/Constraints/IsCanSavePaymentMethodValidator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Gateway\\Validator\\Constraints\\IsOneyEnabledValidator\:\:validate\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: ../src/Gateway/Validator/Constraints/IsOneyEnabledValidator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Gateway\\Validator\\Constraints\\IsPayPlugSecretKeyValidator\:\:validate\(\) has parameter \$value with no type specified\.$#' + identifier: missingType.parameter + count: 1 + path: ../src/Gateway/Validator/Constraints/IsPayPlugSecretKeyValidator.php + + - + message: '#^Cannot access offset ''secretKey'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Gateway/Validator/Constraints/PayplugPermissionValidator.php + + - + message: '#^Cannot call method getConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/PayplugPermissionValidator.php + + - + message: '#^Cannot call method getData\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/PayplugPermissionValidator.php + + - + message: '#^Cannot call method getGatewayConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Gateway/Validator/Constraints/PayplugPermissionValidator.php + + - + message: '#^Parameter \#2 \$key of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientFactory\:\:create\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Gateway/Validator/Constraints/PayplugPermissionValidator.php + + - + message: '#^Binary operation "\." between ''payment_'' and mixed results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access offset ''customer_id'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$brand on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$code on mixed\.$#' + identifier: property.nonObject + count: 2 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$country on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$exp_month on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$exp_year on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$id on mixed\.$#' + identifier: property.nonObject + count: 4 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$last4 on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access property \$message on mixed\.$#' + identifier: property.nonObject + count: 2 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$brand of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setBrand\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$countryCode of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setCountryCode\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$expirationMonth of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setExpirationMonth\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$expirationYear of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setExpirationYear\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$externalId of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setExternalId\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$isLive of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setIsLive\(\) expects bool, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$last4 of method PayPlug\\SyliusPayPlugPlugin\\Entity\\Card\:\:setLast4\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#1 \$timestamp of method DateTimeImmutable\:\:setTimestamp\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Parameter \#2 \$array of function array_key_exists expects array, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Handler/PaymentNotificationHandler.php + + - + message: '#^Cannot access offset ''refund_from_sylius'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Handler/RefundNotificationHandler.php + + - + message: '#^Parameter \#1 \$externalId of method PayPlug\\SyliusPayPlugPlugin\\Entity\\RefundHistory\:\:setExternalId\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/RefundNotificationHandler.php + + - + message: '#^Parameter \#1 \$value of method PayPlug\\SyliusPayPlugPlugin\\Entity\\RefundHistory\:\:setValue\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Handler/RefundNotificationHandler.php + + - + message: '#^Call to static method Webmozart\\Assert\\Assert\:\:isInstanceOf\(\) with DateTimeInterface and ''DateTimeInterface'' will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 1 + path: ../src/MessageHandler/RefundPaymentGeneratedHandler.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/MessageHandler/RefundPaymentGeneratedHandler.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/MessageHandler/RefundPaymentGeneratedHandler.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 2 + path: ../src/MessageHandler/RefundPaymentGeneratedHandler.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\MessageHandler\\RefundPaymentGeneratedHandler\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/MessageHandler/RefundPaymentGeneratedHandler.php + + - + message: '#^Parameter \#1 \$paymentId of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:abortPayment\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/AbortPaymentProcessor.php + + - + message: '#^Binary operation "\-\=" between float\|int and mixed results in an error\.$#' + identifier: assignOp.invalid + count: 2 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Cannot cast mixed to float\.$#' + identifier: cast.double + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Class Sylius\\RefundPlugin\\Command\\RefundUnits constructor invoked with 5 parameters, 4 required\.$#' + identifier: arguments.count + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandler\:\:parseIdsToUnitRefunds\(\) should return array\ but returns list\\.$#' + identifier: return.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^PHPDoc tag @var with type Sylius\\Component\\Core\\Model\\ShipmentInterface is not subtype of type Sylius\\Component\\Order\\Model\\AdjustmentInterface\.$#' + identifier: varTag.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#1 \$id of method Sylius\\RefundPlugin\\Provider\\RemainingTotalProviderInterface\:\:getTotalLeftToRefund\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#1 \$unit of method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandler\:\:getAmount\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#1 \$units of method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandler\:\:parseIdsToUnitRefunds\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#1 \$value of function count expects array\|Countable, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#3 \$amount of method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandler\:\:addItem\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#3 \$amount of method PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentHandler\:\:dispatchRefundPrice\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#3 \$paymentMethodId of class Sylius\\RefundPlugin\\Command\\RefundUnits constructor expects int, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Parameter \#4 \$comment of class Sylius\\RefundPlugin\\Command\\RefundUnits constructor expects int\|string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentHandler.php + + - + message: '#^Cannot access an offset on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot access property \$amount on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot access property \$id on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot access property \$metadata on mixed\.$#' + identifier: property.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot call method refundPayment\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot call method refundPaymentWithAmount\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Parameter \#1 \$secretKey of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:initialise\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Parameter \#2 \$key of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientFactoryInterface\:\:create\(\) expects string\|null, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\PaymentProcessing\\RefundPaymentProcessor\:\:\$payPlugApiClient has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/PaymentProcessing/RefundPaymentProcessor.php + + - + message: '#^Cannot call method apply\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Processor/OrderPaymentProcessor.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Processor/OrderPaymentProcessor.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Processor\\OrderPaymentProcessor\:\:getFactoryName\(\) should return string but returns string\|null\.$#' + identifier: return.type + count: 1 + path: ../src/Processor/OrderPaymentProcessor.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Processor\\OrderPaymentProcessor\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/Processor/OrderPaymentProcessor.php + + - + message: '#^Call to an undefined method Sylius\\RefundPlugin\\Provider\\RefundPaymentMethodsProviderInterface\:\:findForChannel\(\)\.$#' + identifier: method.notFound + count: 2 + path: ../src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php + + - + message: '#^Cannot call method getGatewayConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Provider\\AbstractSupportedRefundPaymentMethodsProvider\:\:findForChannel\(\) should return array but returns mixed\.$#' + identifier: return.type + count: 3 + path: ../src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php + + - + message: '#^Parameter \#1 \$paymentMethods of method PayPlug\\SyliusPayPlugPlugin\\Provider\\AbstractSupportedRefundPaymentMethodsProvider\:\:find\(\) expects array, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php + + - + message: '#^Parameter \#2 \$callback of function array_filter expects \(callable\(mixed\)\: bool\)\|null, Closure\(Sylius\\Component\\Core\\Model\\PaymentMethodInterface\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php + + - + message: '#^Cannot access offset ''max_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Provider/OneySimulation/OneySimulationDataProvider.php + + - + message: '#^Cannot access offset ''min_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Provider/OneySimulation/OneySimulationDataProvider.php + + - + message: '#^Cannot access offset ''oney'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Provider/OneySimulation/OneySimulationDataProvider.php + + - + message: '#^Cannot access offset string\|null on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Provider/OneySimulation/OneySimulationDataProvider.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Provider\\OneySupportedPaymentChoiceProvider\:\:getFeesFor\(\) should return string but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Provider/OneySupportedPaymentChoiceProvider.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of native type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Provider/OneySupportedPaymentChoiceProvider.php + + - + message: '#^Call to method apply\(\) on an unknown class SM\\StateMachine\\StateMachineInterface\.$#' + identifier: class.notFound + count: 3 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Cannot access offset ''merchant_session'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 3 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^PHPDoc tag @var for variable \$stateMachine contains unknown class SM\\StateMachine\\StateMachineInterface\.$#' + identifier: class.notFound + count: 3 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Parameter \#1 \$customer of method Sylius\\Component\\Customer\\Model\\CustomerAwareInterface\:\:setCustomer\(\) expects Sylius\\Component\\Customer\\Model\\CustomerInterface\|null, true given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Parameter \#1 \$paymentId of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:retrieve\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Parameter \#1 \$timestamp of method DateTimeImmutable\:\:setTimestamp\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Parameter \#2 \$array of function array_key_exists expects array, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Provider\\Payment\\ApplePayPaymentProvider\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/Provider/Payment/ApplePayPaymentProvider.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.type + count: 1 + path: ../src/Provider/PaymentTokenProvider.php + + - + message: '#^Cannot access offset ''max_amount'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Provider/SupportedMethodsProvider.php + + - + message: '#^Cannot access offset ''min_amount'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Provider/SupportedMethodsProvider.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of native type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Provider/SupportedMethodsProvider.php + + - + message: '#^Cannot call method add\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php + + - + message: '#^Cannot call method getGatewayConfig\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php + + - + message: '#^Parameter \#2 \$callback of function array_filter expects \(callable\(mixed\)\: bool\)\|null, Closure\(Sylius\\Component\\Core\\Model\\PaymentMethodInterface\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: ../src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\PaymentMethodRepository\:\:findOneByGatewayName\(\) should return Sylius\\Component\\Core\\Model\\PaymentMethodInterface\|null but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/PaymentMethodRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\PaymentRepository\:\:findAllActiveByGatewayFactoryName\(\) should return array but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/PaymentRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\PaymentRepository\:\:findAllAuthorizedOlderThanDays\(\) should return array\ but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/PaymentRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\PaymentRepository\:\:findOneByPayPlugPaymentId\(\) should return Sylius\\Component\\Core\\Model\\PaymentInterface but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/PaymentRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\RefundHistoryRepository\:\:findLastProcessedRefundForPayment\(\) should return PayPlug\\SyliusPayPlugPlugin\\Entity\\RefundHistory\|null but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/RefundHistoryRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Repository\\RefundHistoryRepository\:\:findLastRefundForPayment\(\) should return PayPlug\\SyliusPayPlugPlugin\\Entity\\RefundHistory\|null but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Repository/RefundHistoryRepository.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Resolver\\AmericanExpressPaymentMethodsResolverDecorator\:\:getSupportedMethods\(\) should return array\ but returns array\.$#' + identifier: return.type + count: 1 + path: ../src/Resolver/AmericanExpressPaymentMethodsResolverDecorator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Resolver\\ApplePayPaymentMethodsResolverDecorator\:\:getSupportedMethods\(\) should return array\ but returns array\.$#' + identifier: return.type + count: 1 + path: ../src/Resolver/ApplePayPaymentMethodsResolverDecorator.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of native type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Resolver/ApplePayPaymentMethodsResolverDecorator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Resolver\\BancontactPaymentMethodsResolverDecorator\:\:getSupportedMethods\(\) should return array\ but returns array\.$#' + identifier: return.type + count: 1 + path: ../src/Resolver/BancontactPaymentMethodsResolverDecorator.php + + - + message: '#^PHPDoc tag @var with type Payum\\Core\\Model\\GatewayConfigInterface is not subtype of native type Sylius\\Component\\Payment\\Model\\GatewayConfigInterface\|null\.$#' + identifier: varTag.nativeType + count: 1 + path: ../src/Resolver/OneyPaymentMethodsResolverDecorator.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Resolver\\PayPlugPaymentMethodsResolverDecorator\:\:getSupportedMethods\(\) should return array\ but returns array\.$#' + identifier: return.type + count: 1 + path: ../src/Resolver/PayPlugPaymentMethodsResolverDecorator.php + + - + message: '#^Call to method apply\(\) on an unknown class SM\\StateMachine\\StateMachineInterface\.$#' + identifier: class.notFound + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Call to method can\(\) on an unknown class SM\\StateMachine\\StateMachineInterface\.$#' + identifier: class.notFound + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Cannot call method get\(\) on mixed\.$#' + identifier: method.nonObject + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Cannot cast mixed to string\.$#' + identifier: cast.string + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Parameter \#1 \$paymentStateMachine of method PayPlug\\SyliusPayPlugPlugin\\Resolver\\PaymentStateResolver\:\:applyTransition\(\) expects SM\\StateMachine\\StateMachineInterface, mixed given\.$#' + identifier: argument.type + count: 4 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Parameter \#1 \$secretKey of method PayPlug\\SyliusPayPlugPlugin\\ApiClient\\PayPlugApiClientInterface\:\:initialise\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Parameter \#1 \$timestamp of method DateTimeImmutable\:\:setTimestamp\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Parameter \$paymentStateMachine of method PayPlug\\SyliusPayPlugPlugin\\Resolver\\PaymentStateResolver\:\:applyTransition\(\) has invalid type SM\\StateMachine\\StateMachineInterface\.$#' + identifier: class.notFound + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Property PayPlug\\SyliusPayPlugPlugin\\Resolver\\PaymentStateResolver\:\:\$stateMachineFactory has no type specified\.$#' + identifier: missingType.property + count: 1 + path: ../src/Resolver/PaymentStateResolver.php + + - + message: '#^Method PayPlug\\SyliusPayPlugPlugin\\Twig\\GetCurrentRouteExtension\:\:payplugGetCurrentRoute\(\) should return string but returns mixed\.$#' + identifier: return.type + count: 1 + path: ../src/Twig/GetCurrentRouteExtension.php + + - + message: '#^Cannot access offset ''max_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^Cannot access offset ''min_amounts'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^Cannot access offset ''oney'' on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^Cannot access offset string on mixed\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 2 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^PHPDoc tag @var with type Sylius\\Component\\Core\\Model\\ProductVariantInterface\|null is not subtype of type Sylius\\Component\\Product\\Model\\ProductVariantInterface\|false\.$#' + identifier: varTag.type + count: 1 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^Parameter \#1 \$amount of method Sylius\\Bundle\\MoneyBundle\\Formatter\\MoneyFormatterInterface\:\:format\(\) expects int, mixed given\.$#' + identifier: argument.type + count: 2 + path: ../src/Twig/OneyRulesExtension.php + + - + message: '#^Parameter \#2 \$callback of function array_filter expects \(callable\(mixed\)\: bool\)\|null, Closure\(string\)\: bool given\.$#' + identifier: argument.type + count: 1 + path: ../src/Twig/OneySimulationExtension.php diff --git a/ruleset/phpstan.neon b/ruleset/phpstan.neon new file mode 100644 index 00000000..558e1a7d --- /dev/null +++ b/ruleset/phpstan.neon @@ -0,0 +1,25 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: max + reportUnmatchedIgnoredErrors: false + paths: + - ../src + bootstrapFiles: + - ../vendor/autoload.php + excludePaths: + # Makes PHPStan crash + - ../src/DependencyInjection/ + - ../migrations + # Test dependencies + - ../tests/TestApplication? + - ../tests/PHPUnit + ignoreErrors: + - identifier: missingType.iterableValue + - identifier: missingType.generics + # ignore false positive + - '#Access to an undefined property Payplug\\Resource\\[a-zA-Z0-9]+::\$#' + - '#Call to static method getSimulations\(\) on an unknown class Payplug\\OneySimulation.#' + - '#Strict comparison using !== between null and mixed will always evaluate to true.#' + - "#^Call to an undefined method Symfony\\\\Component\\\\HttpFoundation\\\\Session\\\\SessionInterface\\:\\:getFlashBag\\(\\)\\.$#" diff --git a/ruleset/rector.php b/ruleset/rector.php new file mode 100644 index 00000000..c68c6f8f --- /dev/null +++ b/ruleset/rector.php @@ -0,0 +1,41 @@ +withPaths([ + \dirname(__DIR__) . '/src', + \dirname(__DIR__) . '/tests/PHPUnit', + ]) + ->withSkipPath( + \dirname(__DIR__) . '/src/Entity', + ) + ->withPHPStanConfigs([__DIR__ . '/phpstan.neon']) + ->withPhpSets(php82: true) + ->withAttributesSets(symfony: true, doctrine: true) + ->withPreparedSets( + deadCode: true, + codeQuality: true, + doctrineCodeQuality: true, + symfonyConfigs: true, + ) + ->withSkip([ + ReadOnlyPropertyRector::class, + ]) + ->withTypeCoverageLevel(0) + ->withSets([ + SymfonySetList::SYMFONY_60, + SymfonySetList::SYMFONY_61, + SymfonySetList::SYMFONY_62, + SymfonySetList::SYMFONY_63, + SymfonySetList::SYMFONY_64, + SymfonySetList::SYMFONY_71, + SymfonySetList::SYMFONY_72, + SetList::CODE_QUALITY, + SetList::DEAD_CODE, + ]); \ No newline at end of file diff --git a/ruleset/ruleset.xml b/ruleset/ruleset.xml new file mode 100644 index 00000000..72bffd83 --- /dev/null +++ b/ruleset/ruleset.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rulesets/ecs.php b/rulesets/ecs.php deleted file mode 100644 index f29f2542..00000000 --- a/rulesets/ecs.php +++ /dev/null @@ -1,24 +0,0 @@ -import(dirname(__DIR__) . '/vendor/sylius-labs/coding-standard/ecs.php'); - - $parameters = $containerConfigurator->parameters(); - $parameters->set(Option::PATHS, [ - dirname(__DIR__, 1) . '/src', - dirname(__DIR__, 1) . '/tests/Behat', - dirname(__DIR__, 1) . '/tests/PHPUnit', - dirname(__DIR__, 1) . '/spec', - ]); - $parameters->set(Option::SKIP, [ - __DIR__ . '/tests/Application', - ]); - - $containerConfigurator->import(SetList::SYMFONY); -}; diff --git a/rulesets/phpstan.neon b/rulesets/phpstan.neon deleted file mode 100644 index 703aa833..00000000 --- a/rulesets/phpstan.neon +++ /dev/null @@ -1,21 +0,0 @@ -parameters: - level: max - reportUnmatchedIgnoredErrors: false - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false - excludes_analyse: - # Makes PHPStan crash - - ../src/DependencyInjection/Configuration.php - - ../src/Migrations/ - - # Test dependencies - - ../tests - - # PHPSpec - - ../spec - - ignoreErrors: - # ignore false positive - - '#Access to an undefined property Payplug\\Resource\\[a-zA-Z0-9]+::\$#' - - '#Call to static method getSimulations\(\) on an unknown class Payplug\\OneySimulation.#' - - '#Strict comparison using !== between null and mixed will always evaluate to true.#' diff --git a/spec/Action/CaptureActionSpec.php b/spec/Action/CaptureActionSpec.php deleted file mode 100644 index fe05e253..00000000 --- a/spec/Action/CaptureActionSpec.php +++ /dev/null @@ -1,107 +0,0 @@ -beConstructedWith($logger, $flashBag, $translator); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(CaptureAction::class); - } - - public function it_implements_action_interface(): void - { - $this->shouldHaveType(ActionInterface::class); - } - - public function it_implements_api_aware_interface(): void - { - $this->shouldHaveType(ApiAwareInterface::class); - } - - public function it_implements_gateway_aware_interface(): void - { - $this->shouldHaveType(GatewayAwareInterface::class); - } - - public function it_executes( - Capture $request, - ArrayObject $arrayObject, - TokenInterface $token, - GatewayInterface $gateway, - PayPlugApiClientInterface $payPlugApiClient, - GenericTokenFactory $genericTokenFactory, - TokenInterface $notifyToken - ): void { - $payment = \Mockery::mock('payment', Payment::class); - - $payment->id = 1; - $payment->is_live = true; - $payment->hosted_payment = (object) [ - 'payment_url' => 'test', - ]; - - $this->setGateway($gateway); - $this->setApi($payPlugApiClient); - $this->setGenericTokenFactory($genericTokenFactory); - - $arrayObject->getArrayCopy()->willReturn([]); - $request->getModel()->willReturn($arrayObject); - $request->getFirstModel()->willReturn($payment); - $request->getToken()->willReturn($token); - $token->getTargetUrl()->willReturn('url'); - $token->getAfterUrl()->willReturn('url'); - $token->getGatewayName()->willReturn('test'); - $token->getDetails()->willReturn([]); - $genericTokenFactory->createNotifyToken('test', [])->willReturn($notifyToken); - $notifyToken->getTargetUrl()->willReturn('url'); - $notifyToken->getHash()->willReturn('test'); - $payPlugApiClient->createPayment([])->willReturn($payment); - $arrayObject->offsetGet('order_number')->willReturn('000001'); - $arrayObject->offsetGet('initiator')->shouldBeCalled(); - - $arrayObject->offsetExists('status')->shouldBeCalled(); - $arrayObject->offsetSet('hosted_payment', ['return_url' => 'url', 'cancel_url' => 'url?&status=canceled'])->shouldBeCalled(); - $arrayObject->offsetSet('notification_url', 'url')->shouldBeCalled(); - $arrayObject->offsetSet('payment_id', 1)->shouldBeCalled(); - $arrayObject->offsetSet('is_live', true)->shouldBeCalled(); - $arrayObject->offsetSet('status', PayPlugApiClientInterface::STATUS_CREATED)->shouldBeCalled(); - - $this - ->shouldThrow(HttpRedirect::class) - ->during('execute', [$request]) - ; - } - - public function it_supports_only_capture_request_and_array_access( - Capture $request, - \ArrayAccess $arrayAccess - ): void { - $request->getModel()->willReturn($arrayAccess); - $this->supports($request)->shouldReturn(true); - } -} diff --git a/spec/Action/ConvertPaymentActionSpec.php b/spec/Action/ConvertPaymentActionSpec.php deleted file mode 100644 index 13e306c5..00000000 --- a/spec/Action/ConvertPaymentActionSpec.php +++ /dev/null @@ -1,243 +0,0 @@ -beConstructedWith($session, $canSaveCardChecker, $payplugCardRepository); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(ConvertPaymentAction::class); - } - - public function it_implements_action_interface(): void - { - $this->shouldHaveType(ActionInterface::class); - } - - public function it_executes( - Convert $request, - PaymentInterface $payment, - OrderInterface $order, - CustomerInterface $customer, - AddressInterface $address - ): void { - $this->setApi(new PayPlugApiClient('test', PayPlugGatewayFactory::FACTORY_NAME)); - - $customer = $this->getCustomer($customer); - $address = $this->getAddress($address); - $order = $this->getOrder($order, $customer, $address, $address); - $payment = $this->getPayment($payment, $order); - $payment->getMethod(); - - $request->getSource()->willReturn($payment); - $request->getTo()->willReturn('array'); - - $request->setResult([ - 'amount' => 100, - 'currency' => 'EUR', - 'metadata' => [ - 'customer_id' => 1, - 'order_number' => '000000001', - ], - 'billing' => [ - 'title' => null, - 'first_name' => 'John', - 'last_name' => 'Doe', - 'company_name' => 'Bob', - 'email' => 'test@test.pl', - 'mobile_phone_number' => null, - 'landline_phone_number' => null, - 'address1' => 'test', - 'address2' => null, - 'postcode' => '97980', - 'city' => 'City', - 'state' => 'State', - 'country' => 'US', - 'language' => 'en', - ], - 'shipping' => [ - 'title' => null, - 'first_name' => 'John', - 'last_name' => 'Doe', - 'company_name' => 'Bob', - 'email' => 'test@test.pl', - 'mobile_phone_number' => null, - 'landline_phone_number' => null, - 'address1' => 'test', - 'address2' => null, - 'postcode' => '97980', - 'city' => 'City', - 'state' => 'State', - 'country' => 'US', - 'language' => 'en', - 'delivery_type' => 'BILLING', - ], - ])->shouldBeCalled(); - - $this->execute($request); - } - - public function it_executes_with_different_address( - Convert $request, - PaymentInterface $payment, - OrderInterface $order, - CustomerInterface $customer, - AddressInterface $address, - AddressInterface $otherAddress - ): void { - $this->setApi(new PayPlugApiClient('test', PayPlugGatewayFactory::FACTORY_NAME)); - - $customer = $this->getCustomer($customer); - $address = $this->getAddress($address); - $otherAddress = $this->getOtherAddress($otherAddress); - $order = $this->getOrder($order, $customer, $address, $otherAddress); - $payment = $this->getPayment($payment, $order); - $payment->getMethod(); - - $request->getSource()->willReturn($payment); - $request->getTo()->willReturn('array'); - - $request->setResult([ - 'amount' => 100, - 'currency' => 'EUR', - 'metadata' => [ - 'customer_id' => 1, - 'order_number' => '000000001', - ], - 'billing' => [ - 'title' => null, - 'first_name' => 'John', - 'last_name' => 'Doe', - 'company_name' => 'Bob', - 'email' => 'test@test.pl', - 'mobile_phone_number' => null, - 'landline_phone_number' => null, - 'address1' => 'test', - 'address2' => null, - 'postcode' => '97980', - 'city' => 'City', - 'state' => 'State', - 'country' => 'US', - 'language' => 'en', - ], - 'shipping' => [ - 'title' => null, - 'first_name' => 'Jean', - 'last_name' => 'Bon', - 'company_name' => 'Paris', - 'email' => 'test@test.pl', - 'mobile_phone_number' => null, - 'landline_phone_number' => null, - 'address1' => 'test', - 'address2' => null, - 'postcode' => '97980', - 'city' => 'Paris', - 'state' => 'Paris', - 'country' => 'US', - 'language' => 'en', - 'delivery_type' => 'NEW', - ], - ])->shouldBeCalled(); - - $this->execute($request); - } - - public function it_supports_only_convert_request_payment_source_and_array_to( - Convert $request, - PaymentInterface $payment - ): void { - $request->getSource()->willReturn($payment); - $request->getTo()->willReturn('array'); - $this->supports($request)->shouldReturn(true); - } - - private function getCustomer($customer) - { - $customer->getEmail()->willReturn('test@test.pl'); - $customer->getId()->willReturn(1); - $customer->getGender()->willReturn('M'); - - return $customer; - } - - private function getAddress(AddressInterface $address) - { - $address->getId()->willReturn(1); - $address->getFirstName()->willReturn('John'); - $address->getLastName()->willReturn('Doe'); - $address->getPhoneNumber()->willReturn('0606060606'); - $address->getCompany()->willReturn('Bob'); - $address->getPostcode()->willReturn('97980'); - $address->getStreet()->willReturn('test'); - $address->getCity()->willReturn('City'); - $address->getProvinceName()->willReturn('State'); - $address->getCountryCode()->willReturn('US'); - - return $address; - } - - private function getOtherAddress(AddressInterface $address) - { - $address->getId()->willReturn(2); - $address->getFirstName()->willReturn('Jean'); - $address->getLastName()->willReturn('Bon'); - $address->getPhoneNumber()->willReturn('0606060606'); - $address->getCompany()->willReturn('Paris'); - $address->getPostcode()->willReturn('97980'); - $address->getStreet()->willReturn('test'); - $address->getCity()->willReturn('Paris'); - $address->getProvinceName()->willReturn('Paris'); - $address->getCountryCode()->willReturn('US'); - - return $address; - } - - private function getOrder( - OrderInterface $order, - CustomerInterface $customer, - AddressInterface $billingAddress, - AddressInterface $shippingAddress - ) { - $order->getCustomer()->willReturn($customer); - $order->getBillingAddress()->willReturn($billingAddress); - $order->getShippingAddress()->willReturn($shippingAddress); - $order->getNumber()->willReturn('000000001'); - $order->getLocaleCode()->willReturn('en_US'); - - return $order; - } - - private function getPayment(PaymentInterface $payment, OrderInterface $order) - { - $payment->getOrder()->willReturn($order); - $payment->getDetails()->willReturn([]); - $payment->getAmount()->willReturn(100); - $payment->getCurrencyCode()->willReturn('EUR'); - - return $payment; - } -} diff --git a/spec/Action/NotifyActionSpec.php b/spec/Action/NotifyActionSpec.php deleted file mode 100644 index 51260ddc..00000000 --- a/spec/Action/NotifyActionSpec.php +++ /dev/null @@ -1,80 +0,0 @@ -beConstructedWith( - $logger, - $paymentNotificationHandler, - $refundNotificationHandler - ); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(NotifyAction::class); - } - - public function it_implements_action_interface(): void - { - $this->shouldHaveType(ActionInterface::class); - } - - public function it_implements_api_aware_interface(): void - { - $this->shouldHaveType(ApiAwareInterface::class); - } - - public function it_implements_gateway_aware_interface(): void - { - $this->shouldHaveType(GatewayAwareInterface::class); - } - - public function it_executes( - Notify $request, - \ArrayObject $arrayObject, - GatewayInterface $gateway, - PayPlugApiClient $payPlugApiClient - ): void { - $payment = \Mockery::mock('payment', Payment::class); - - $payment->is_paid = true; - - $this->setGateway($gateway); - $this->setApi($payPlugApiClient); - - $request->getModel()->willReturn($arrayObject); - $payPlugApiClient->treat('')->willReturn($payment); - - $this->execute($request); - } - - public function it_supports_only_notify_request_and_array_access( - Notify $request, - \ArrayAccess $arrayAccess - ): void { - $request->getModel()->willReturn($arrayAccess); - $this->supports($request)->shouldReturn(true); - } -} diff --git a/spec/Action/StatusActionSpec.php b/spec/Action/StatusActionSpec.php deleted file mode 100644 index bec55198..00000000 --- a/spec/Action/StatusActionSpec.php +++ /dev/null @@ -1,67 +0,0 @@ -beConstructedWith($stateMachineFactory, $refundPaymentHandler, $paymentNotificationHandler, $flashBag); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(StatusAction::class); - } - - public function it_implements_action_interface(): void - { - $this->shouldHaveType(ActionInterface::class); - } - - public function it_implements_gateway_aware_interface(): void - { - $this->shouldHaveType(GatewayAwareInterface::class); - } - - public function it_executes( - GetStatusInterface $request, - PaymentInterface $payment, - GatewayInterface $gateway - ): void { - $this->setGateway($gateway); - - $payment->getDetails()->willReturn([]); - $request->getModel()->willReturn($payment); - - $request->markNew()->shouldBeCalled(); - - $this->execute($request); - } - - public function it_supports_only_get_status_request_and_array_access( - GetStatusInterface $request, - PaymentInterface $payment - ): void { - $request->getModel()->willReturn($payment); - $this->supports($request)->shouldReturn(true); - } -} diff --git a/spec/PaymentProcessing/RefundPaymentProcessorSpec.php b/spec/PaymentProcessing/RefundPaymentProcessorSpec.php deleted file mode 100644 index 423f7670..00000000 --- a/spec/PaymentProcessing/RefundPaymentProcessorSpec.php +++ /dev/null @@ -1,73 +0,0 @@ -beConstructedWith( - $session, - $payPlugApiClient, - $logger, - $translator, - $refundPaymentRepository, - $payplugRefundHistoryRepository - ); - } - - public function it_is_initializable(): void - { - $this->shouldHaveType(RefundPaymentProcessor::class); - } - - public function it_implements_payment_processor_interface(): void - { - $this->shouldHaveType(PaymentProcessorInterface::class); - } - - public function it_processes( - PaymentInterface $payment, - PaymentMethodInterface $paymentMethod, - GatewayConfigInterface $gatewayConfig, - PayPlugApiClientInterface $payPlugApiClient - ): void { - $gatewayConfig->getFactoryName()->willReturn(PayPlugGatewayFactory::FACTORY_NAME); - $gatewayConfig->getConfig()->willReturn([ - 'secretKey' => 'test', - ]); - $paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); - $paymentMethod->getGatewayConfig()->willReturn($gatewayConfig); - $payment->getMethod()->willReturn($paymentMethod); - $payment->getDetails()->willReturn([ - 'payment_id' => 'test', - ]); - - $payPlugApiClient->refundPayment('test')->shouldBeCalled(); - $payPlugApiClient->initialise('test')->shouldBeCalled(); - - $this->process($payment); - } -} diff --git a/src/Action/Admin/Auth/UnifiedAuthenticationController.php b/src/Action/Admin/Auth/UnifiedAuthenticationController.php new file mode 100644 index 00000000..603ad6aa --- /dev/null +++ b/src/Action/Admin/Auth/UnifiedAuthenticationController.php @@ -0,0 +1,154 @@ + $paymentMethodRepository + */ + public function __construct( + private RouterInterface $router, + private RepositoryInterface $paymentMethodRepository, + private EntityManagerInterface $entityManager, + private PaymentMethodValidator $paymentMethodValidator, + private LoggerInterface $logger, + private CacheInterface $cache, + ) { + } + + #[Route('/setup-redirection', name: 'payplug_sylius_admin_auth_setup_redirection')] + public function setupRedirection(Request $request): Response + { + try { + $clientId = $request->query->get('client_id'); + $companyId = $request->query->get('company_id'); + + $request->getSession()->set('payplug_client_id', $clientId); + $request->getSession()->set('payplug_company_id', $companyId); + + $challenge = bin2hex(openssl_random_pseudo_bytes(50)); + $request->getSession()->set('payplug_oauth_challenge', $challenge); + + $callBackUrl = $this->router->generate('payplug_sylius_admin_auth_oauth_callback', [], RouterInterface::ABSOLUTE_URL); + + // This method will redirect the user to PayPlug's oauth page via header('Location')' + Authentication::initiateOAuth($clientId, $callBackUrl, $challenge); + // Fetch the header Location the Sdk put and redirect the user to it + $headers = \headers_list(); + foreach ($headers as $header) { + if (str_starts_with($header, 'Location:')) { + return new RedirectResponse(substr($header, 9)); + } + } + throw new \LogicException('No location header found'); + } catch (\Throwable $e) { + $this->logger->critical('Error while perform Payplug OAuth Setup redirection', ['message' => $e->getMessage(), 'exception' => $e]); + return $this->handleOAuthError($request); + } + } + + #[Route('/oauth-callback', name: 'payplug_sylius_admin_auth_oauth_callback')] + public function oauthCallback(Request $request): Response + { + try { + $code = $request->query->getString('code'); + /** @var string $clientId */ + $clientId = $request->getSession()->get('payplug_client_id'); + /** @var string $challenge */ + $challenge = $request->getSession()->get('payplug_oauth_challenge'); + $callback = $this->generateUrl('payplug_sylius_admin_auth_oauth_callback', [], UrlGeneratorInterface::ABSOLUTE_URL); + + $jwt = Authentication::generateJWTOneShot($code, $callback, $clientId, $challenge); + if ([] === $jwt || $jwt['httpStatus'] !== 200 || !\is_array($jwt['httpResponse'])) { + throw new BadRequestHttpException('Error while generating JWT'); + } + $paymentMethodId = $request->getSession()->get('payplug_sylius_oauth_payment_method_id'); + if (null === $paymentMethodId) { + throw new BadRequestHttpException('No payment method id found in session'); + } + $paymentMethod = $this->paymentMethodRepository->find($paymentMethodId); + if (null === $paymentMethod) { + throw new \LogicException('No payment method found'); + } + $gatewayConfig = $paymentMethod->getGatewayConfig(); + if (null === $gatewayConfig) { + throw new \LogicException('No gateway config found'); + } + + $companyId = $request->getSession()->get('payplug_company_id'); + Payplug::init(['secretKey' => $jwt['httpResponse']['access_token']]); + $clientName = 'Sylius - ' . $paymentMethod->getName(); + $testClientDataResult = Authentication::createClientIdAndSecret($companyId, $clientName, 'test'); + $liveClientDataResult = Authentication::createClientIdAndSecret($companyId, $clientName, 'live'); + + $config = $gatewayConfig->getConfig(); + $config['live_client'] = $liveClientDataResult['httpResponse']; + $config['test_client'] = $testClientDataResult['httpResponse']; + $gatewayConfig->setConfig($config); + + $this->entityManager->flush(); + $this->cleanSession($request); + + $request->getSession()->getFlashBag()->add('success', 'payplug_sylius_payplug_plugin.admin.oauth_callback_success'); + // Clean previous cached client config + $cacheKeyLive = sprintf('payplug_%s_api_key_live', $gatewayConfig->getFactoryName()); + $cacheKeyTest = sprintf('payplug_%s_api_key_test', $gatewayConfig->getFactoryName()); + $this->cache->delete($cacheKeyLive); + $this->cache->delete($cacheKeyTest); + + // Ensure that the payment method is well configured + $this->paymentMethodValidator->process($paymentMethod); + + return new RedirectResponse($this->router->generate('sylius_admin_payment_method_update', ['id' => $paymentMethod->getId()])); + } catch (\Throwable $e) { + $this->logger->critical('Error while perform Payplug OAuth callback', ['message' => $e->getMessage(), 'exception' => $e]); + return $this->handleOAuthError($request); + } + } + + private function handleOAuthError(Request $request): RedirectResponse + { + $request->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.admin.oauth_setup_error'); + $paymentMethodId = $request->getSession()->get('payplug_sylius_oauth_payment_method_id'); + if (null === $paymentMethodId) { + return new RedirectResponse($this->router->generate('sylius_admin_payment_method_index')); + } + + return new RedirectResponse($this->router->generate('sylius_admin_payment_method_update', ['id' => $paymentMethodId])); + } + + private function cleanSession(Request $request): void + { + $session = $request->getSession(); + $session->remove('payplug_client_id'); + $session->remove('payplug_company_id'); + $session->remove('payplug_oauth_challenge'); + $session->remove('payplug_sylius_oauth_payment_method_id'); + } +} diff --git a/src/Action/Admin/CompleteRefundPaymentAction.php b/src/Action/Admin/CompleteRefundPaymentAction.php deleted file mode 100644 index 92cec047..00000000 --- a/src/Action/Admin/CompleteRefundPaymentAction.php +++ /dev/null @@ -1,101 +0,0 @@ -session = $session; - $this->refundPaymentRepository = $refundPaymentInterface; - $this->refundPaymentCompletedStateApplier = $refundPaymentCompletedStateApplier; - $this->router = $router; - $this->orderRepository = $orderRepository; - $this->messageBus = $messageBus; - $this->relatedPaymentIdProvider = $relatedPaymentIdProvider; - $this->translator = $translator; - } - - public function __invoke(string $orderNumber, string $id): Response - { - /** @var RefundPaymentInterface $refundPayment */ - $refundPayment = $this->refundPaymentRepository->find($id); - - /** @var OrderInterface $order */ - $order = $this->orderRepository->findOneByNumber($orderNumber); - - try { - $this->messageBus->dispatch(new RefundPaymentGenerated( - $refundPayment->getId(), - $refundPayment->getOrder()->getNumber() ?? '', - $refundPayment->getAmount(), - $refundPayment->getCurrencyCode(), - $refundPayment->getPaymentMethod()->getId(), - $this->relatedPaymentIdProvider->getForRefundPayment($refundPayment) - )); - - if ($refundPayment->getState() !== self::COMPLETED_STATE) { - $this->refundPaymentCompletedStateApplier->apply($refundPayment); - } - $this->session->getFlashBag()->add('success', 'sylius_refund.refund_payment_completed'); - } catch (Throwable $throwable) { - $this->session->getFlashBag()->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.ui.impossible_to_refund_this_payment')); - } - - return new RedirectResponse($this->router->generate( - 'sylius_admin_order_show', - ['id' => $order->getId()] - )); - } -} diff --git a/src/Action/Admin/RefundUnitsAction.php b/src/Action/Admin/RefundUnitsAction.php deleted file mode 100644 index 165a1572..00000000 --- a/src/Action/Admin/RefundUnitsAction.php +++ /dev/null @@ -1,80 +0,0 @@ -commandBus = $commandBus; - $this->session = $session; - $this->router = $router; - $this->commandCreator = $commandCreator; - $this->logger = $logger; - $this->translator = $translator; - } - - public function __invoke(Request $request): Response - { - try { - $this->commandBus->dispatch($this->commandCreator->fromRequest($request)); - - $this->session->getFlashBag()->add('success', 'sylius_refund.units_successfully_refunded'); - } catch (InvalidRefundAmount $exception) { - $this->session->getFlashBag()->add('error', $exception->getMessage()); - - $this->logger->error($exception->getMessage()); - } catch (HandlerFailedException $exception) { - /** @var Exception $previousException */ - $previousException = $exception->getPrevious(); - - $this->session->getFlashBag()->add('error', $previousException->getMessage()); - - $this->logger->error($previousException->getMessage()); - } - - return new RedirectResponse($this->router->generate( - 'sylius_refund_order_refunds_list', - ['orderNumber' => $request->attributes->get('orderNumber')] - )); - } -} diff --git a/src/Action/CaptureAction.php b/src/Action/CaptureAction.php index 9e70db00..8030246c 100644 --- a/src/Action/CaptureAction.php +++ b/src/Action/CaptureAction.php @@ -8,10 +8,17 @@ use Payplug\Exception\BadRequestException; use Payplug\Exception\ForbiddenException; use Payplug\Resource\Payment; +use Payplug\Resource\PaymentAuthorization; use PayPlug\SyliusPayPlugPlugin\Action\Api\ApiAwareTrait; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; +use PayPlug\SyliusPayPlugPlugin\Entity\Card; use PayPlug\SyliusPayPlugPlugin\Exception\UnknownApiErrorException; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\AbortPaymentProcessor; use Payum\Core\Action\ActionInterface; use Payum\Core\ApiAwareInterface; use Payum\Core\Bridge\Spl\ArrayObject; @@ -25,34 +32,61 @@ use Payum\Core\Security\GenericTokenFactoryInterface; use Payum\Core\Security\TokenInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface; +use Sylius\Component\Core\Model\PaymentInterface; +use Sylius\Component\Core\Model\PaymentMethodInterface; +use Sylius\Component\Resource\Repository\RepositoryInterface; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Contracts\Translation\TranslatorInterface; use Webmozart\Assert\Assert; +/** @deprecated */ +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => PayPlugGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.capture', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => OneyGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.capture', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => BancontactGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.capture', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => AmericanExpressGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.capture', + ], +)] +#[Autoconfigure(public: true)] final class CaptureAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface, GenericTokenFactoryAwareInterface { - use GatewayAwareTrait, ApiAwareTrait; + use GatewayAwareTrait; + use ApiAwareTrait; /** @var GenericTokenFactoryInterface|null */ private $tokenFactory; - /** @var LoggerInterface */ - private $logger; - - /** @var FlashBagInterface */ - private $flashBag; - - /** @var TranslatorInterface */ - private $translator; - public function __construct( - LoggerInterface $logger, - FlashBagInterface $flashBag, - TranslatorInterface $translator + private LoggerInterface $logger, + private TranslatorInterface $translator, + private AbortPaymentProcessor $abortPaymentProcessor, + private RequestStack $requestStack, + private RepositoryInterface $payplugCardRepository, ) { - $this->logger = $logger; - $this->flashBag = $flashBag; - $this->translator = $translator; } public function setGenericTokenFactory(GenericTokenFactoryInterface $genericTokenFactory = null): void @@ -65,36 +99,47 @@ public function execute($request): void Assert::isInstanceOf($this->tokenFactory, GenericTokenFactoryInterface::class); RequestNotSupportedException::assertSupports($this, $request); + $paymentModel = $request->getFirstModel(); + Assert::isInstanceOf($paymentModel, PaymentInterface::class); + $details = ArrayObject::ensureArrayObject($request->getModel()); - if (isset($details['status']) && PayPlugApiClientInterface::FAILED === $details['status']) { - // Unset current status to allow to use payplug to change payment method - unset($details['status']); + if ( + isset($details['payment_method']) && + ApplePayGatewayFactory::PAYMENT_METHOD_APPLE_PAY === $details['payment_method'] + ) { + $this->abortPaymentProcessor->process($paymentModel); + $details['status'] = PayPlugApiClientInterface::STATUS_CANCELED; return; } - if (isset($details['status'], $details['payment_id'])) { - if (PayPlugApiClientInterface::STATUS_CREATED !== $details['status']) { - return; - } - - $times = 0; - - do { - $payment = $this->payPlugApiClient->retrieve((string) $details['payment_id']); - - if ($payment->is_paid) { - $details['status'] = PayPlugApiClientInterface::STATUS_CAPTURED; + if ( + PayPlugApiClientInterface::FAILED === ($details['status'] ?? null) && + PayPlugApiClientInterface::INTEGRATED_PAYMENT_INTEGRATION === ($details['integration'] ?? null) + ) { + // Do not try to capture a failed integrated payment and do not remove status + return; + } - return; - } + if (isset($details['status']) && PayPlugApiClientInterface::FAILED === $details['status']) { + // Unset current status to allow to use payplug to change payment method + unset($details['status']); - sleep(1); + return; + } - ++$times; - } while ($times < 3); + if ( + isset($details['status'], $details['payment_id']) && + PayPlugApiClientInterface::STATUS_CREATED !== $details['status'] + ) { + return; + } + if ( + array_key_exists('status', $paymentModel->getDetails()) && + PayPlugApiClientInterface::STATUS_CAPTURED === $paymentModel->getDetails()['status'] + ) { return; } @@ -108,14 +153,49 @@ public function execute($request): void 'cancel_url' => $token->getTargetUrl() . '?&' . http_build_query(['status' => PayPlugApiClientInterface::STATUS_CANCELED]), ]; - if (isset($details['status']) && $details['status'] === 'pending') { + if (isset($details['status']) && 'pending' === $details['status']) { // We previously made a payment but not yet "authorized", // Unset current status to allow to use payplug to change payment method unset($details['status']); } + if ( + !in_array( + $details['payment_method'], + array_merge( + [ApplePayGatewayFactory::PAYMENT_METHOD_APPLE_PAY], + OneyGatewayFactory::PAYMENT_CHOICES, + ), + true, + ) + ) { + // clean other detail values + if ($details->offsetExists('payment_context')) { + unset($details['payment_context']); + } + + if ($details->offsetExists('merchant_session')) { + unset($details['merchant_session']); + } + } + try { - $payment = $this->createPayment($details); + // gateway payplug case: open many browsers and pay by save card in any of these browsers + $cardId = $this->requestStack->getSession()->get('payplug_payment_method'); + if ( + null !== $cardId && + 'PAYER' !== $details['initiator'] && + $paymentModel->getMethod() instanceof PaymentMethodInterface && + PayPlugGatewayFactory::FACTORY_NAME === $token->getGatewayName() + ) { + $card = $this->payplugCardRepository->find($cardId); + if ($card instanceof Card) { + $details['payment_method'] = $card->getExternalId(); + $details['initiator'] = 'PAYER'; + } + } + + $payment = $this->createPayment($details, $paymentModel); $details['status'] = PayPlugApiClientInterface::STATUS_CREATED; // Pay with a saved card: https://docs.payplug.com/api/guide-savecard-en.html @@ -125,6 +205,16 @@ public function execute($request): void return; } + $now = new \DateTimeImmutable(); + if ( + $payment->__isset('authorization') && + $payment->__get('authorization') instanceof PaymentAuthorization && + null !== $payment->__get('authorization')->__get('expires_at') && + $now < $now->setTimestamp($payment->__get('authorization')->__get('expires_at')) + ) { + return; + } + $details['status'] = PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK; $details['hosted_payment'] = [ 'payment_url' => $payment->hosted_payment->payment_url, @@ -135,28 +225,30 @@ public function execute($request): void $oneClickToken = $this->tokenFactory->createCaptureToken( $token->getGatewayName(), $token->getDetails(), - 'payplug_sylius_oneclick_verification' + 'payplug_sylius_oneclick_verification', ); throw new HttpRedirect($oneClickToken->getAfterUrl()); } throw new HttpRedirect($payment->hosted_payment->payment_url); - } catch (ForbiddenException $forbiddenException) { + } catch (ForbiddenException) { $accountData = $this->payPlugApiClient->getAccount(true); $canSaveCard = (bool) $accountData['permissions']['can_save_cards']; - /** @var \Sylius\Component\Core\Model\PaymentMethod $paymentMethod */ - $paymentMethod = $request->getFirstModel()->getMethod(); - /** @var \Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface $gatewayConfig */ - $gatewayConfig = $paymentMethod->getGatewayConfig(); - $config = $gatewayConfig->getConfig(); - $config[PayPlugGatewayFactory::ONE_CLICK] = $canSaveCard; - $gatewayConfig->setConfig($config); + $paymentMethod = $paymentModel->getMethod(); + if ( + $paymentMethod instanceof PaymentMethodInterface && + ($gatewayConfig = $paymentMethod->getGatewayConfig()) instanceof GatewayConfigInterface + ) { + $config = $gatewayConfig->getConfig(); + $config[PayPlugGatewayFactory::ONE_CLICK] = $canSaveCard; + $gatewayConfig->setConfig($config); + } } catch (BadRequestException $badRequestException) { $errorObject = $badRequestException->getErrorObject(); if (null === $errorObject || [] === $errorObject) { - $this->flashBag->add('error', 'payplug_sylius_payplug_plugin.error.api_unknow_error'); + $this->requestStack->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.error.api_unknow_error'); return; } @@ -164,7 +256,7 @@ public function execute($request): void $this->notifyErrors($details, $errorObject); throw new HttpRedirect($details['hosted_payment']['cancel_url']); - } catch (UnknownApiErrorException $unknownApiErrorException) { + } catch (UnknownApiErrorException) { $details['status'] = PayPlugApiClientInterface::FAILED; $this->displayGenericError($details); @@ -175,12 +267,12 @@ public function execute($request): void private function displayGenericError(ArrayObject $details): void { if ('PAYER' === $details['initiator']) { - $this->flashBag->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.error.transaction_failed_1click')); + $this->requestStack->getSession()->getFlashBag()->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.error.transaction_failed_1click')); return; } - $this->flashBag->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.error.api_unknow_error')); + $this->requestStack->getSession()->getFlashBag()->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.error.api_unknow_error')); } public function supports($request): bool @@ -198,23 +290,42 @@ private function addNotificationUrl(TokenInterface $token, ArrayObject $details) } $notifyToken = $this->tokenFactory->createNotifyToken($token->getGatewayName(), $token->getDetails()); - $notificationUrl = $notifyToken->getTargetUrl(); - $details['notification_url'] = $notificationUrl; return $details; } - private function createPayment(ArrayObject $details): Payment + /** + * @throws UnknownApiErrorException + * @throws BadRequestException + */ + private function createPayment(ArrayObject $details, PaymentInterface $paymentModel): Payment { try { + if ( + $details->offsetExists('payment_id') && + $details->offsetExists('status') && + $details->offsetExists('is_live') + ) { + $this->abortPaymentProcessor->process($paymentModel); + unset($details['status'], $details['payment_id'], $details['is_live']); + // the parameter allow_save_card must be false when payment_method parameter is provided + if (null !== $details['payment_method']) { + $details['allow_save_card'] = false; + } + } + + $this->logger->debug('[PayPlug] Create payment', [ + 'detail' => $details->getArrayCopy(), + ]); $payment = $this->payPlugApiClient->createPayment($details->getArrayCopy()); $details['payment_id'] = $payment->id; $details['is_live'] = $payment->is_live; $this->logger->debug('[PayPlug] Create payment', [ 'payment_id' => $payment->id, + 'payment' => (array) $payment, ]); return $payment; @@ -225,11 +336,7 @@ private function createPayment(ArrayObject $details): Payment } catch (\Throwable $throwable) { $details['status'] = PayPlugApiClientInterface::FAILED; - throw new UnknownApiErrorException( - 'payplug_sylius_payplug_plugin.error.api_unknow_error', - $throwable->getCode(), - $throwable, - ); + throw new UnknownApiErrorException('payplug_sylius_payplug_plugin.error.api_unknow_error', $throwable->getCode(), $throwable); } } @@ -240,26 +347,28 @@ private function notifyErrors(ArrayObject $details, array $errorDetails): void } if (isset($errorDetails['details']['billing']['postcode'])) { - $this->flashBag->add( + $this->requestStack->getSession()->getFlashBag()->add( 'error', $this->translator->trans('payplug_sylius_payplug_plugin.ui.error.billing.postcode', [ '%postalCode%' => $details['billing']['postcode'], - ]) + ]), ); } if (isset($errorDetails['details']['shipping']['postcode'])) { - $this->flashBag->add( + $this->requestStack->getSession()->getFlashBag()->add( 'error', $this->translator->trans('payplug_sylius_payplug_plugin.ui.error.shipping.postcode', [ '%postalCode%' => $details['shipping']['postcode'], - ]) + ]), ); } - if (!isset($errorDetails['details']['billing']['postcode']) && - !isset($errorDetails['details']['shipping']['postcode'])) { - $this->flashBag->add('error', 'payplug_sylius_payplug_plugin.error.api_unknow_error'); + if ( + !isset($errorDetails['details']['billing']['postcode']) && + !isset($errorDetails['details']['shipping']['postcode']) + ) { + $this->requestStack->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.error.api_unknow_error'); } } } diff --git a/src/Action/ConvertPaymentAction.php b/src/Action/ConvertPaymentAction.php index 644ca156..663b9b1a 100644 --- a/src/Action/ConvertPaymentAction.php +++ b/src/Action/ConvertPaymentAction.php @@ -4,59 +4,56 @@ namespace PayPlug\SyliusPayPlugPlugin\Action; -use DateInterval; -use DateTime; -use libphonenumber\PhoneNumberFormat as PhoneNumberFormat; -use libphonenumber\PhoneNumberType; -use libphonenumber\PhoneNumberUtil as PhoneNumberUtil; use PayPlug\SyliusPayPlugPlugin\Action\Api\ApiAwareTrait; -use PayPlug\SyliusPayPlugPlugin\Checker\CanSaveCardCheckerInterface; -use PayPlug\SyliusPayPlugPlugin\Entity\Card; +use PayPlug\SyliusPayPlugPlugin\Creator\PayPlugPaymentDataCreator; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use Payum\Core\Action\ActionInterface; use Payum\Core\ApiAwareInterface; -use Payum\Core\Bridge\Spl\ArrayObject; use Payum\Core\Exception\RequestNotSupportedException; use Payum\Core\Request\Convert; -use function sprintf; -use Sylius\Component\Core\Model\AddressInterface; -use Sylius\Component\Core\Model\CustomerInterface; -use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; -use Sylius\Component\Core\Model\PaymentMethodInterface; -use Sylius\Component\Core\Model\Shipment; -use Sylius\Component\Core\Model\ShipmentInterface; -use Sylius\Component\Resource\Repository\RepositoryInterface; -use Symfony\Component\HttpFoundation\Session\SessionInterface; - +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; + +/** @deprecated */ +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => PayPlugGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.convert_payment', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => OneyGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.convert_payment', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => BancontactGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.convert_payment', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => AmericanExpressGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.convert_payment', + ], +)] +#[Autoconfigure(public: true)] final class ConvertPaymentAction implements ActionInterface, ApiAwareInterface { use ApiAwareTrait; - private const DELIVERY_TYPE_BILLING = 'BILLING'; - - private const DELIVERY_TYPE_NEW = 'NEW'; - - private const PAYPLUG_CARD_ID_OTHER = 'other'; - - /** @var SessionInterface */ - private $session; - - /** @var CanSaveCardCheckerInterface */ - private $canSaveCardChecker; - - /** @var RepositoryInterface */ - private $payplugCardRepository; - - public function __construct( - SessionInterface $session, - CanSaveCardCheckerInterface $canSaveCard, - RepositoryInterface $payplugCardRepository - ) { - $this->session = $session; - $this->canSaveCardChecker = $canSaveCard; - $this->payplugCardRepository = $payplugCardRepository; + public function __construct(private PayPlugPaymentDataCreator $paymentDataCreator) + { } public function execute($request): void @@ -66,45 +63,7 @@ public function execute($request): void /** @var PaymentInterface $payment */ $payment = $request->getSource(); - /** @var OrderInterface $order */ - $order = $payment->getOrder(); - - /** @var CustomerInterface $customer */ - $customer = $order->getCustomer(); - - $details = ArrayObject::ensureArrayObject($payment->getDetails()); - $details['amount'] = $payment->getAmount(); - $details['currency'] = $payment->getCurrencyCode(); - - $details['metadata'] = [ - 'customer_id' => $customer->getId(), - 'order_number' => $order->getNumber(), - ]; - - // DSP2 fields - /** @var AddressInterface $shipping */ - $shipping = $order->getShippingAddress(); - /** @var AddressInterface $billing */ - $billing = $order->getBillingAddress(); - - $deliveryType = $shipping->getId() === $billing->getId( - ) ? self::DELIVERY_TYPE_BILLING : self::DELIVERY_TYPE_NEW; - - $this->addBillingInfo($billing, $customer, $order, $details); - $this->addShippingInfo($shipping, $customer, $order, $deliveryType, $details); - - $paymentMethod = $payment->getMethod(); - - if (PayPlugGatewayFactory::FACTORY_NAME === $this->payPlugApiClient->getGatewayFactoryName() && - $paymentMethod instanceof PaymentMethodInterface) { - $details['allow_save_card'] = false; - $details = $this->alterPayPlugDetails($paymentMethod, $details); - } - - if (OneyGatewayFactory::FACTORY_NAME === $this->payPlugApiClient->getGatewayFactoryName()) { - $details = $this->alterOneyDetails($details); - $details->offsetSet('payment_context', $this->getCartContext($order)); - } + $details = $this->paymentDataCreator->create($payment); $request->setResult((array) $details); } @@ -114,217 +73,6 @@ public function supports($request): bool return $request instanceof Convert && $request->getSource() instanceof PaymentInterface && - $request->getTo() === 'array'; - } - - public function formatNumber(string $phoneNumber, ?string $isoCode): array - { - $phoneNumberUtil = PhoneNumberUtil::getInstance(); - $parsed = $phoneNumberUtil->parse($phoneNumber, $isoCode); - - if (!$phoneNumberUtil->isValidNumber($parsed)) { - return [ - 'phone' => null, - 'is_mobile' => null, - ]; - } - - $formatted = $phoneNumberUtil->format($parsed, PhoneNumberFormat::E164); - - return [ - 'phone' => $formatted, - 'is_mobile' => $phoneNumberUtil->getNumberType($parsed) === PhoneNumberType::MOBILE, - ]; - } - - private function formatTitle(CustomerInterface $customer): ?string - { - $gender = $customer->getGender(); - - return $gender === 'm' ? 'mr' : ($gender === 'f' ? 'mrs' : null); - } - - private function formatLanguageCode(?string $languageCode): ?string - { - if (null === $languageCode) { - return null; - } - - $parse = explode('_', $languageCode); - - return strtolower($parse[0]); - } - - private function loadPhoneNumbers( - ?array $phoneData, - ?string &$mobilePhone = null, - ?string &$landingPhone = null - ): void { - if (null === $phoneData) { - return; - } - if (!isset($phoneData['phone'], $phoneData['is_mobile'])) { - return; - } - if ($phoneData['is_mobile'] === true) { - $mobilePhone = $phoneData['phone']; - } - if ($phoneData['is_mobile'] !== true) { - $landingPhone = $phoneData['phone']; - } - } - - private function addBillingInfo( - AddressInterface $billing, - CustomerInterface $customer, - OrderInterface $order, - ArrayObject &$details - ): void { - //Sylius does not require any phone number so we have to considere it null - $billingPhone = $billing->getPhoneNumber() !== null ? $this->formatNumber( - $billing->getPhoneNumber(), - $billing->getCountryCode() - ) : null; - $this->loadPhoneNumbers($billingPhone, $billingMobilePhone, $billingLandingPhone); - - $details['billing'] = [ - 'title' => $this->formatTitle($customer), - 'first_name' => $billing->getFirstName(), - 'last_name' => $billing->getLastName(), - 'company_name' => $billing->getCompany(), - 'email' => $customer->getEmail(), - 'mobile_phone_number' => $billingMobilePhone, - 'landline_phone_number' => $billingLandingPhone, - 'address1' => $billing->getStreet(), - 'address2' => null, - 'postcode' => $billing->getPostcode(), - 'city' => $billing->getCity(), - 'state' => $billing->getProvinceName(), - 'country' => $billing->getCountryCode(), - 'language' => $this->formatLanguageCode($order->getLocaleCode()), - ]; - } - - private function addShippingInfo( - AddressInterface $shipping, - CustomerInterface $customer, - OrderInterface $order, - string $deliveryType, - ArrayObject &$details - ): void { - $shippingPhone = $shipping->getPhoneNumber() !== null ? $this->formatNumber( - $shipping->getPhoneNumber(), - $shipping->getCountryCode() - ) : null; - $this->loadPhoneNumbers($shippingPhone, $shippingMobilePhone, $shippingLandingPhone); - - $details['shipping'] = [ - 'title' => $this->formatTitle($customer), - 'first_name' => $shipping->getFirstName(), - 'last_name' => $shipping->getLastName(), - 'company_name' => $shipping->getCompany(), - 'email' => $customer->getEmail(), - 'mobile_phone_number' => $shippingMobilePhone, - 'landline_phone_number' => $shippingLandingPhone, - 'address1' => $shipping->getStreet(), - 'address2' => null, - 'postcode' => $shipping->getPostcode(), - 'city' => $shipping->getCity(), - 'state' => $shipping->getProvinceName(), - 'country' => $shipping->getCountryCode(), - 'language' => $this->formatLanguageCode($order->getLocaleCode()), - 'delivery_type' => $deliveryType, - ]; - } - - private function alterPayPlugDetails(PaymentMethodInterface $paymentMethod, ArrayObject $details): ArrayObject - { - if (!$this->canSaveCardChecker->isAllowed($paymentMethod)) { - return $details; - } - - /** @var string|null $cardId */ - $cardId = $this->session->get('payplug_payment_method'); - - if ((null === $cardId || self::PAYPLUG_CARD_ID_OTHER === $cardId) && $this->canSaveCardChecker->isAllowed( - $paymentMethod - )) { - $details['allow_save_card'] = true; - - return $details; - } - - if (null === $cardId) { - return $details; - } - - $card = $this->payplugCardRepository->find($cardId); - - if (!$card instanceof Card) { - return $details; - } - - $details['payment_method'] = $card->getExternalId(); - $details['initiator'] = 'PAYER'; - - return $details; - } - - private function alterOneyDetails(ArrayObject $details): ArrayObject - { - $details['payment_method'] = $this->session->get('oney_payment_method', 'oney_x3_with_fees'); - $details['auto_capture'] = true; - $details['authorized_amount'] = $details['amount']; - unset($details['amount']); - - $billing = $details['billing']; - if ($billing['company_name'] === null) { - $billing['company_name'] = sprintf('%s %s', $billing['first_name'], $billing['last_name']); - } - $details['billing'] = $billing; - - $shipping = $details['shipping']; - if ($shipping['company_name'] === null) { - $shipping['company_name'] = sprintf('%s %s', $shipping['first_name'], $shipping['last_name']); - } - $details['shipping'] = $shipping; - - return $details; - } - - private function getCartContext(OrderInterface $order): array - { - /** @var Shipment $shipment */ - $shipment = $order->getShipments()->current(); - - $expectedDeliveryDate = (new DateTime())->add(new DateInterval('P7D'))->format('Y-m-d'); - $deliveryType = $this->retrieveDeliveryType($shipment); - $data = []; - - foreach ($order->getItems() as $orderItem) { - $data[] = [ - 'delivery_label' => (null !== $shipment->getMethod()) ? $shipment->getMethod()->getName() : 'none', - 'delivery_type' => $deliveryType, - 'expected_delivery_date' => $expectedDeliveryDate, - 'merchant_item_id' => (null !== $orderItem->getVariant()) ? $orderItem->getVariant()->getCode( - ) : 'none', - 'brand' => $orderItem->getProductName(), - 'name' => $orderItem->getProductName() . ' ' . $orderItem->getVariantName(), - 'total_amount' => $orderItem->getTotal(), - 'price' => $orderItem->getUnitPrice(), - 'quantity' => $orderItem->getQuantity(), - ]; - } - - return ['cart' => $data]; - } - - /** - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - private function retrieveDeliveryType(ShipmentInterface $shipment): string - { - // Possible delivery type : [storepickup, networkpickup, travelpickup, carrier, edelivery] - return 'storepickup'; + 'array' === $request->getTo(); } } diff --git a/src/Action/NotifyAction.php b/src/Action/NotifyAction.php index 4a50e9df..e90dac54 100644 --- a/src/Action/NotifyAction.php +++ b/src/Action/NotifyAction.php @@ -9,6 +9,10 @@ use Payplug\Exception\PayplugException; use PayPlug\SyliusPayPlugPlugin\Action\Api\ApiAwareTrait; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Handler\PaymentNotificationHandler; use PayPlug\SyliusPayPlugPlugin\Handler\RefundNotificationHandler; use Payum\Core\Action\ActionInterface; @@ -18,32 +22,57 @@ use Payum\Core\GatewayAwareTrait; use Payum\Core\Request\Notify; use Psr\Log\LoggerInterface; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +/** @deprecated */ +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => PayPlugGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.notify', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => OneyGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.notify', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => BancontactGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.notify', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => AmericanExpressGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.notify', + ], +)] +#[Autoconfigure(public: true)] final class NotifyAction implements ActionInterface, ApiAwareInterface, GatewayAwareInterface { - use GatewayAwareTrait, ApiAwareTrait; - - /** @var LoggerInterface */ - private $logger; - - /** @var \PayPlug\SyliusPayPlugPlugin\Handler\PaymentNotificationHandler */ - private $paymentNotificationHandler; - - /** @var \PayPlug\SyliusPayPlugPlugin\Handler\RefundNotificationHandler */ - private $refundNotificationHandler; + use GatewayAwareTrait; + use ApiAwareTrait; public function __construct( - LoggerInterface $logger, - PaymentNotificationHandler $paymentNotificationHandler, - RefundNotificationHandler $refundNotificationHandler + #[Autowire('@monolog.logger.payum')] + private LoggerInterface $logger, + private PaymentNotificationHandler $paymentNotificationHandler, + private RefundNotificationHandler $refundNotificationHandler, ) { - $this->logger = $logger; - $this->paymentNotificationHandler = $paymentNotificationHandler; - $this->refundNotificationHandler = $refundNotificationHandler; } public function execute($request): void { + // Put notification asleep to prevent double processing while user is redirected manually + sleep(10); $details = ArrayObject::ensureArrayObject($request->getModel()); $input = file_get_contents('php://input'); @@ -54,8 +83,8 @@ public function execute($request): void } $resource = $this->payPlugApiClient->treat($input); - $this->paymentNotificationHandler->treat($request, $resource, $details); - $this->refundNotificationHandler->treat($request, $resource, $details); + $this->paymentNotificationHandler->treat($request->getFirstModel(), $resource, $details); + $this->refundNotificationHandler->treat($request->getFirstModel(), $resource, $details); } catch (PayplugException $exception) { $details['status'] = PayPlugApiClientInterface::FAILED; $this->logger->error('[PayPlug] Notify action', ['error' => $exception->getMessage()]); diff --git a/src/Action/StatusAction.php b/src/Action/StatusAction.php index 73d60ed4..135af4a6 100644 --- a/src/Action/StatusAction.php +++ b/src/Action/StatusAction.php @@ -6,6 +6,10 @@ use PayPlug\SyliusPayPlugPlugin\Action\Api\ApiAwareTrait; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Handler\PaymentNotificationHandler; use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\RefundPaymentHandlerInterface; use PayPlug\SyliusPayPlugPlugin\StateMachine\Transition\OrderPaymentTransitions; @@ -17,37 +21,54 @@ use Payum\Core\GatewayAwareTrait; use Payum\Core\Request\GetHttpRequest; use Payum\Core\Request\GetStatusInterface; -use SM\Factory\FactoryInterface; +use Sylius\Abstraction\StateMachine\StateMachineInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; - +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +use Symfony\Component\HttpFoundation\RequestStack; + +/** @deprecated */ +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => PayPlugGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.status', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => OneyGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.status', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => BancontactGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.status', + ], +)] +#[AutoconfigureTag( + name: 'payum.action', + attributes: [ + 'factory' => AmericanExpressGatewayFactory::FACTORY_NAME, + 'alias' => 'payum.action.status', + ], +)] +#[Autoconfigure(public: true)] final class StatusAction implements ActionInterface, GatewayAwareInterface, ApiAwareInterface { - use GatewayAwareTrait, ApiAwareTrait; - - /** @var FactoryInterface */ - private $stateMachineFactory; - - /** @var RefundPaymentHandlerInterface */ - private $refundPaymentHandler; - - /** @var \PayPlug\SyliusPayPlugPlugin\Handler\PaymentNotificationHandler */ - private $paymentNotificationHandler; - - /** @var FlashBagInterface */ - private $flashBag; + use GatewayAwareTrait; + use ApiAwareTrait; public function __construct( - FactoryInterface $stateMachineFactory, - RefundPaymentHandlerInterface $refundPaymentHandler, - PaymentNotificationHandler $paymentNotificationHandler, - FlashBagInterface $flashBag + private StateMachineInterface $stateMachine, + private RefundPaymentHandlerInterface $refundPaymentHandler, + private PaymentNotificationHandler $paymentNotificationHandler, + private RequestStack $requestStack, ) { - $this->stateMachineFactory = $stateMachineFactory; - $this->refundPaymentHandler = $refundPaymentHandler; - $this->paymentNotificationHandler = $paymentNotificationHandler; - $this->flashBag = $flashBag; } public function execute($request): void @@ -68,25 +89,34 @@ public function execute($request): void $this->gateway->execute($httpRequest = new GetHttpRequest()); //If we don't have received the notification when we reach this page, call the API manually to update the status - if (PayPlugApiClientInterface::STATUS_CREATED === $details['status'] - && isset($httpRequest->query['payum_token'])) { + if ( + PayPlugApiClientInterface::STATUS_CREATED === $details['status'] && + isset($httpRequest->query['payum_token']) + ) { $resource = $this->payPlugApiClient->retrieve($details['payment_id']); - $this->paymentNotificationHandler->treat($request, $resource, $details); + $this->paymentNotificationHandler->treat($request->getFirstModel(), $resource, $details); } - if (isset($httpRequest->query['status']) && - PayPlugApiClientInterface::STATUS_CANCELED === $httpRequest->query['status']) { + if ( + isset($httpRequest->query['status']) && + PayPlugApiClientInterface::STATUS_CANCELED === $httpRequest->query['status'] + ) { // we need to show a specific error message when the payment is cancelled using the 1click feature - if ($details['status'] === PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK) { - $this->flashBag->add('error', 'payplug_sylius_payplug_plugin.error.transaction_failed_1click'); + if (PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK === $details['status']) { + $this->requestStack->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.error.transaction_failed_1click'); } $details['status'] = PayPlugApiClientInterface::STATUS_CANCELED; } - if ($details['status'] === PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK) { + if (PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK === $details['status']) { $resource = $this->payPlugApiClient->retrieve($details['payment_id']); - $this->paymentNotificationHandler->treat($request, $resource, $details); + $this->paymentNotificationHandler->treat($request->getFirstModel(), $resource, $details); + } + + if (PaymentInterface::STATE_PROCESSING === $details['status']) { + $resource = $this->payPlugApiClient->retrieve($details['payment_id']); + $this->paymentNotificationHandler->treat($request->getFirstModel(), $resource, $details); } $payment->setDetails($details->getArrayCopy()); @@ -150,14 +180,10 @@ private function markOrderPaymentAsAwaitingPayment($request): void /** @var OrderInterface $order */ $order = $payment->getOrder(); - $stateMachine = $this->stateMachineFactory->get($order, OrderPaymentTransitions::GRAPH); - - if (!$stateMachine->can(OrderPaymentTransitions::TRANSITION_REQUEST_PAYMENT)) { + if (!$this->stateMachine->can($order, OrderPaymentTransitions::GRAPH, OrderPaymentTransitions::TRANSITION_ONEY_REQUEST_PAYMENT)) { return; } - $this->stateMachineFactory - ->get($order, OrderPaymentTransitions::GRAPH) - ->apply(OrderPaymentTransitions::TRANSITION_REQUEST_PAYMENT); + $this->stateMachine->apply($order, OrderPaymentTransitions::GRAPH, OrderPaymentTransitions::TRANSITION_ONEY_REQUEST_PAYMENT); } } diff --git a/src/ApiClient/PayPlugApiClient.php b/src/ApiClient/PayPlugApiClient.php index d622ec8b..8da541f6 100644 --- a/src/ApiClient/PayPlugApiClient.php +++ b/src/ApiClient/PayPlugApiClient.php @@ -15,7 +15,7 @@ use Payplug\Resource\Refund; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\PayPlugSyliusPayPlugPlugin; -use Sylius\Bundle\CoreBundle\Application\Kernel; +use Sylius\Bundle\CoreBundle\SyliusCoreBundle; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Contracts\Cache\CacheInterface; use Webmozart\Assert\Assert; @@ -41,7 +41,7 @@ public function __construct(string $secretKey, ?string $factoryName = null, ?Cac ]); $this->factoryName = $factoryName ?? PayPlugGatewayFactory::FACTORY_NAME; - if (null === $cache) { + if (!$cache instanceof \Symfony\Contracts\Cache\CacheInterface) { $cache = new ArrayAdapter(); } $this->cache = $cache; @@ -49,20 +49,7 @@ public function __construct(string $secretKey, ?string $factoryName = null, ?Cac HttpClient::addDefaultUserAgentProduct( 'PayPlug-Sylius', PayPlugSyliusPayPlugPlugin::VERSION, - 'Sylius/' . Kernel::VERSION - ); - } - - /** - * @deprecated use DI instead to get a pre-configured client - */ - public function initialise(string $secretKey): void - { - Payplug::setSecretKey($secretKey); - HttpClient::addDefaultUserAgentProduct( - 'PayPlug-Sylius', - PayPlugSyliusPayPlugPlugin::VERSION, - 'Sylius/' . Kernel::VERSION + 'Sylius/' . SyliusCoreBundle::VERSION, ); } @@ -73,9 +60,7 @@ public function getAccount(bool $refresh = false): array $this->cache->delete($cacheKey); } - return $this->cache->get($cacheKey, function (): array { - return Authentication::getAccount($this->configuration)['httpResponse'] ?? []; - }); + return $this->cache->get($cacheKey, fn (): array => Authentication::getAccount($this->configuration)['httpResponse'] ?? []); } public function getGatewayFactoryName(): string @@ -87,7 +72,7 @@ public function getPermissions(): array { try { return Authentication::getPermissions($this->configuration) ?? []; - } catch (UnauthorizedException $exception) { + } catch (UnauthorizedException) { return []; } } @@ -105,6 +90,14 @@ public function createPayment(array $data): Payment return $payment; } + public function abortPayment(string $paymentId): Payment + { + $payment = \Payplug\Payment::abort($paymentId, $this->configuration); + Assert::isInstanceOf($payment, Payment::class); + + return $payment; + } + public function refundPayment(string $paymentId): Refund { /** @var Refund|null $refund */ diff --git a/src/ApiClient/PayPlugApiClientFactory.php b/src/ApiClient/PayPlugApiClientFactory.php index 298586d6..4d12c900 100644 --- a/src/ApiClient/PayPlugApiClientFactory.php +++ b/src/ApiClient/PayPlugApiClientFactory.php @@ -4,37 +4,78 @@ namespace PayPlug\SyliusPayPlugPlugin\ApiClient; +use Payplug\Authentication; +use PayPlug\SyliusPayPlugPlugin\Exception\GatewayConfigurationException; +use Sylius\Component\Payment\Model\GatewayConfigInterface; +use Sylius\Component\Payment\Model\PaymentMethodInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; +use Symfony\Config\SyliusPayment\GatewayConfigConfig; use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\ItemInterface; -final class PayPlugApiClientFactory +final class PayPlugApiClientFactory implements PayPlugApiClientFactoryInterface { - /** @var \Sylius\Component\Resource\Repository\RepositoryInterface */ - private $gatewayConfigRepository; - - /** @var CacheInterface */ - private $cache; - public function __construct( - RepositoryInterface $gatewayConfigRepository, - CacheInterface $cache + private RepositoryInterface $gatewayConfigRepository, + private CacheInterface $cache, ) { - $this->gatewayConfigRepository = $gatewayConfigRepository; - $this->cache = $cache; } - public function create(string $factoryName, ?string $key = null): PayPlugApiClientInterface + public function create(string $factoryName): PayPlugApiClientInterface { - if (null === $key) { - /** @var \Payum\Core\Model\GatewayConfig|null $gatewayConfig */ - $gatewayConfig = $this->gatewayConfigRepository->findOneBy(['factoryName' => $factoryName]); + /** @var GatewayConfigInterface|null $gatewayConfig */ + $gatewayConfig = $this->gatewayConfigRepository->findOneBy(['factoryName' => $factoryName]); - if (null === $gatewayConfig) { - throw new \LogicException('Not yet gateway created for ' . $factoryName); - } - $key = $gatewayConfig->getConfig()['secretKey']; + if (null === $gatewayConfig) { + throw new \LogicException('Not yet gateway created for ' . $factoryName); } + $key = $this->getTokenForGatewayConfig($gatewayConfig); + return new PayPlugApiClient($key, $factoryName, $this->cache); } + + public function createForPaymentMethod(PaymentMethodInterface $paymentMethod): PayPlugApiClientInterface + { + $gatewayConfig = $paymentMethod->getGatewayConfig() ?? throw new \LogicException('Gateway config not found'); + + $key = $this->getTokenForGatewayConfig($gatewayConfig); + $factoryName = $gatewayConfig->getFactoryName(); + + return new PayPlugApiClient($key, $factoryName, $this->cache); + } + + private function getTokenForGatewayConfig(GatewayConfigInterface $gatewayConfig): string + { + $config = $gatewayConfig->getConfig(); + $clientConfig = $config['live_client']; + if (true !== $config['live']) { // The live mode is not enabled, use client config for test mode + $clientConfig = $config['test_client']; + } + if (!\is_array($clientConfig)) { + throw new GatewayConfigurationException('No client config found for ' . $gatewayConfig->getFactoryName() . '. Please renew your credentials in the PayPlug plugin configuration.'); + } + + $cacheKey = sprintf('payplug_%s_api_key_%s', $gatewayConfig->getFactoryName(), $config['live'] === true ? 'live' : 'test'); + + /** @var array $clientConfig */ + return $this->cache->get($cacheKey, function (ItemInterface $item) use ($clientConfig) { + $response = Authentication::generateJWT($clientConfig['client_id'] ?? '', $clientConfig['client_secret'] ?? ''); + if ([] === $response || !is_array($response['httpResponse'])) { + throw new GatewayConfigurationException('Unable to connect to PayPlug API. Please check your credentials in the PayPlug plugin configuration.'); + } + + $accessToken = $response['httpResponse']['access_token']; + if (!is_string($accessToken)) { + throw new GatewayConfigurationException('Unable to connect to PayPlug API. Please check your credentials in the PayPlug plugin configuration.'); + } + $expiresIn = $response['httpResponse']['expires_in']; + if (!is_int($expiresIn)) { + $expiresIn = 200; + } + + $item->expiresAfter($expiresIn); + return $accessToken; + }); + } } diff --git a/src/ApiClient/PayPlugApiClientFactoryInterface.php b/src/ApiClient/PayPlugApiClientFactoryInterface.php new file mode 100644 index 00000000..12b96f2a --- /dev/null +++ b/src/ApiClient/PayPlugApiClientFactoryInterface.php @@ -0,0 +1,14 @@ +customerContext = $customerContext; + public function __construct( + private CustomerContextInterface $customerContext, + private PayplugFeatureChecker $payplugFeatureChecker, + ) { } public function isAllowed(PaymentMethodInterface $paymentMethod): bool @@ -26,16 +22,6 @@ public function isAllowed(PaymentMethodInterface $paymentMethod): bool return false; } - $gatewayConfiguration = $paymentMethod->getGatewayConfig(); - - if (!$gatewayConfiguration instanceof GatewayConfigInterface) { - return false; - } - - if (!\array_key_exists(PayPlugGatewayFactory::ONE_CLICK, $gatewayConfiguration->getConfig())) { - return false; - } - - return (bool) $gatewayConfiguration->getConfig()[PayPlugGatewayFactory::ONE_CLICK] ?? false; + return $this->payplugFeatureChecker->isOneClickEnabled($paymentMethod); } } diff --git a/src/Checker/CanSavePayplugPaymentMethodChecker.php b/src/Checker/CanSavePayplugPaymentMethodChecker.php new file mode 100644 index 00000000..7409fde5 --- /dev/null +++ b/src/Checker/CanSavePayplugPaymentMethodChecker.php @@ -0,0 +1,56 @@ +client->getAccount()['is_live']); + } + + public function isEnabled(string $factoryName, Collection $channels): bool + { + $paymentMethods = $this->client->getAccount()['payment_methods']; + $paymentMethodName = substr($factoryName, (int) (strpos($factoryName, '_', 0)) + 1); + + foreach ($paymentMethods as $key => $method) { + if ($key !== $paymentMethodName) { + continue; + } + + if (ApplePayGatewayFactory::FACTORY_NAME !== $factoryName) { + return $method['enabled']; + } + + return $this->isAllowedDomainNames($method, $channels); + } + + return false; + } + + private function isAllowedDomainNames(array $method, Collection $channels): bool + { + if (!$method['enabled'] || !array_key_exists('allowed_domain_names', $method) || $channels->isEmpty()) { + return false; + } + + foreach ($channels as $channel) { + if (!in_array($channel->getHostname(), $method['allowed_domain_names'], true)) { + return false; + } + } + + return true; + } +} diff --git a/src/Checker/OneyChecker.php b/src/Checker/OneyChecker.php index 79a36d56..a25acf6a 100644 --- a/src/Checker/OneyChecker.php +++ b/src/Checker/OneyChecker.php @@ -6,17 +6,16 @@ use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class OneyChecker implements OneyCheckerInterface { private const ONEY_PERMISSION_FIELD = 'can_use_oney'; - /** @var \PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface */ - private $client; - - public function __construct(PayPlugApiClientInterface $oneyClient) - { - $this->client = $oneyClient; + public function __construct( + #[Autowire('@payplug_sylius_payplug_plugin.api_client.oney')] + private PayPlugApiClientInterface $client, + ) { } public function isEnabled(): bool @@ -47,7 +46,7 @@ public function isNumberOfProductEligible(int $numberOfProduct): bool public function isCountryEligible(?string $shippingCountry, ?string $billingCountry): bool { - if ($shippingCountry === null || $billingCountry === null) { + if (null === $shippingCountry || null === $billingCountry) { return false; } @@ -57,11 +56,6 @@ public function isCountryEligible(?string $shippingCountry, ?string $billingCoun $allowedCountries = $this->client->getAccount()['configuration']['oney']['allowed_countries']; - if (!in_array($shippingCountry, $allowedCountries, true) || - !in_array($billingCountry, $allowedCountries, true)) { - return false; - } - - return true; + return in_array($shippingCountry, $allowedCountries, true) && in_array($billingCountry, $allowedCountries, true); } } diff --git a/src/Checker/OneyCheckerInterface.php b/src/Checker/OneyCheckerInterface.php index c39a5ed4..25374e86 100644 --- a/src/Checker/OneyCheckerInterface.php +++ b/src/Checker/OneyCheckerInterface.php @@ -9,17 +9,17 @@ interface OneyCheckerInterface public function isEnabled(): bool; /** - * For a given price, check if oney allow it + * For a given price, check if oney allow it. */ public function isPriceEligible(int $price, string $currency = 'EUR'): bool; /** - * For x products, check if oney allow it + * For x products, check if oney allow it. */ public function isNumberOfProductEligible(int $numberOfProduct): bool; /** - * Check if shipping and / or billing address is in France + * Check if shipping and / or billing address is in France. */ public function isCountryEligible(?string $shippingCountry, ?string $billingCountry): bool; } diff --git a/src/Checker/OneyOrderChecker.php b/src/Checker/OneyOrderChecker.php index 50813ddc..eb6cc4ee 100644 --- a/src/Checker/OneyOrderChecker.php +++ b/src/Checker/OneyOrderChecker.php @@ -9,19 +9,15 @@ final class OneyOrderChecker { - /** @var \PayPlug\SyliusPayPlugPlugin\Validator\OneyInvalidDataRetriever */ - private $invalidDataRetriever; - - public function __construct(OneyInvalidDataRetriever $invalidDataRetriever) + public function __construct(private OneyInvalidDataRetriever $invalidDataRetriever) { - $this->invalidDataRetriever = $invalidDataRetriever; } /** - * Validate if phone number are setted and are mobile, and if address mail don't contains + characters + * Validate if phone number are setted and are mobile, and if address mail don't contains + characters. */ public function isOrderInfoCorrect(OrderInterface $order): bool { - return \count($this->invalidDataRetriever->getForOrder($order)) === 0; + return [] === $this->invalidDataRetriever->getForOrder($order); } } diff --git a/src/Checker/PayplugFeatureChecker.php b/src/Checker/PayplugFeatureChecker.php new file mode 100644 index 00000000..99cbed3b --- /dev/null +++ b/src/Checker/PayplugFeatureChecker.php @@ -0,0 +1,42 @@ +getConfigCheckboxValue($paymentMethod, PayPlugGatewayFactory::DEFERRED_CAPTURE); + } + + public function isIntegratedPaymentEnabled(PaymentMethodInterface $paymentMethod): bool + { + return $this->getConfigCheckboxValue($paymentMethod, PayPlugGatewayFactory::INTEGRATED_PAYMENT); + } + + public function isOneClickEnabled(PaymentMethodInterface $paymentMethod): bool + { + return $this->getConfigCheckboxValue($paymentMethod, PayPlugGatewayFactory::ONE_CLICK); + } + + private function getConfigCheckboxValue(PaymentMethodInterface $paymentMethod, string $configKey): bool + { + $gatewayConfiguration = $paymentMethod->getGatewayConfig(); + + if (!$gatewayConfiguration instanceof GatewayConfigInterface) { + return false; + } + + if (!\array_key_exists($configKey, $gatewayConfiguration->getConfig())) { + return false; + } + + return (bool) ($gatewayConfiguration->getConfig()[$configKey] ?? false); + } +} diff --git a/src/Checker/PermissionCanSaveCardsChecker.php b/src/Checker/PermissionCanSaveCardsChecker.php index bfb06e02..03eb8adb 100644 --- a/src/Checker/PermissionCanSaveCardsChecker.php +++ b/src/Checker/PermissionCanSaveCardsChecker.php @@ -10,12 +10,8 @@ final class PermissionCanSaveCardsChecker { private const CAN_SAVE_CARDS_PERMISSION_FIELD = 'can_save_cards'; - /** @var PayPlugApiClientInterface */ - private $client; - - public function __construct(PayPlugApiClientInterface $apiClient) + public function __construct(private PayPlugApiClientInterface $client) { - $this->client = $apiClient; } public function isEnabled(): bool diff --git a/src/Cli/UpdatePaymentStateCommand.php b/src/Cli/UpdatePaymentStateCommand.php index acc7625a..413d9874 100644 --- a/src/Cli/UpdatePaymentStateCommand.php +++ b/src/Cli/UpdatePaymentStateCommand.php @@ -9,43 +9,28 @@ use PayPlug\SyliusPayPlugPlugin\Resolver\PaymentStateResolverInterface; use Psr\Log\LoggerInterface; use Sylius\Component\Core\Model\PaymentInterface; +use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\LockableTrait; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +#[AsCommand(name: 'payplug:update-payment-state', description: 'Updates the payments state.')] final class UpdatePaymentStateCommand extends Command { use LockableTrait; - /** @var PaymentRepositoryInterface */ - private $paymentRepository; - - /** @var PaymentStateResolverInterface */ - private $paymentStateResolver; - - /** @var LoggerInterface */ - private $logger; - public function __construct( - PaymentRepositoryInterface $paymentRepository, - PaymentStateResolverInterface $paymentStateResolver, - LoggerInterface $logger + private PaymentRepositoryInterface $paymentRepository, + private PaymentStateResolverInterface $paymentStateResolver, + private LoggerInterface $logger, ) { parent::__construct(); - - $this->paymentRepository = $paymentRepository; - $this->paymentStateResolver = $paymentStateResolver; - $this->logger = $logger; } protected function configure(): void { - $this - ->setName('payplug:update-payment-state') - ->setDescription('Updates the payments state.') - ->setHelp('This command allows you to update the payments state for PayPlug gateway.') - ; + $this->setHelp('This command allows you to update the payments state for PayPlug gateway.'); } /** diff --git a/src/Command/AbstractPayplugPaymentRequest.php b/src/Command/AbstractPayplugPaymentRequest.php new file mode 100644 index 00000000..fc600a04 --- /dev/null +++ b/src/Command/AbstractPayplugPaymentRequest.php @@ -0,0 +1,15 @@ +paymentRequestProvider->provide($capturePaymentRequest); + /** @var \Sylius\Component\Core\Model\PaymentInterface $payment */ + $payment = $paymentRequest->getPayment(); + $method = $payment->getMethod(); + if (null === $method) { + throw new \LogicException('Payment method is not set for the payment.'); + } + + if (PayPlugApiClientInterface::STATUS_CREATED === ($payment->getDetails()['status'] ?? null)) { + $paymentRequest->setResponseData([ + 'retry' => true, + 'message' => 'Payment already created', + 'payment_id' => $payment->getDetails()['payment_id'] ?? 'unknown', + 'redirect_url' => $payment->getDetails()['redirect_url'] ?? null, // @phpstan-ignore-line + ]); + + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + + return; + } + + $client = $this->apiClientFactory->createForPaymentMethod($method); + $data = $this->paymentDataCreator->create($payment)->getArrayCopy(); + + $returnUrl = $this->afterPayUrlProvider->getUrl($paymentRequest, UrlGeneratorInterface::ABSOLUTE_URL); + $data['hosted_payment'] = [ + 'return_url' => $returnUrl, + 'cancel_url' => $returnUrl . '?&' . http_build_query(['status' => PayPlugApiClientInterface::STATUS_CANCELED]), + ]; + + $notificationUrl = $this->urlGenerator->generate('sylius_payment_method_notify', ['code' => $payment->getMethod()?->getCode()], UrlGeneratorInterface::ABSOLUTE_URL); + $data['notification_url'] = $notificationUrl; + + $paymentRequest->setPayload($data); + + try { + $payplugPayment = $client->createPayment($data); + } catch (HttpException $exception) { + $paymentRequest->setResponseData(\json_decode($exception->getHttpResponse(), true)); // @phpstan-ignore-line + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_FAIL, + ); + + return; + } + $arrayPayplugPayment = (array) $payplugPayment; + $payment->setDetails([ + ...$payment->getDetails(), + 'status' => PayPlugApiClientInterface::STATUS_CREATED, + 'payment_id' => $payplugPayment->__get('id'), + 'payplug_response' => $arrayPayplugPayment, + 'redirect_url' => $payplugPayment->hosted_payment->payment_url, // @phpstan-ignore-line + ]); + + $paymentRequest->setResponseData(array_merge($arrayPayplugPayment, [ + 'payment_id' => $payplugPayment->__get('id'), + 'redirect_url' => $payplugPayment->hosted_payment->payment_url, // @phpstan-ignore-line + ])); + + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + } +} diff --git a/src/Command/Handler/NotifyPaymentRequestHandler.php b/src/Command/Handler/NotifyPaymentRequestHandler.php new file mode 100644 index 00000000..441b431a --- /dev/null +++ b/src/Command/Handler/NotifyPaymentRequestHandler.php @@ -0,0 +1,103 @@ +paymentRequestProvider->provide($notifyPaymentRequest); + /** @var PaymentInterface $payment */ + $payment = $paymentRequest->getPayment(); + + try { + $payload = $paymentRequest->getPayload(); + $content = $payload['http_request']['content'] ?? null; // @phpstan-ignore-line + if (!is_string($content) || '' === $content) { + throw new \LogicException('Invalid PayPlug notification payload.'); + } + + $method = $payment->getMethod(); + if (null === $method) { + throw new \LogicException('Payment method is not set for the payment.'); + } + + $client = $this->apiClientFactory->createForPaymentMethod($method); + $resource = $client->treat($content); + + if ($resource instanceof Payment && $payment->getState() === PaymentInterface::STATE_COMPLETED) { + // If the payment is already completed, we do not need to update it again + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + + return; + } + + $details = new \ArrayObject($payment->getDetails()); + $this->paymentNotificationHandler->treat($payment, $resource, $details); + $this->refundNotificationHandler->treat($payment, $resource, $details); + + $payment->setDetails($details->getArrayCopy()); + if ($resource instanceof Payment) { + $this->updatePaymentState($payment); + } + + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + } catch (\Throwable $e) { + $paymentRequest->setResponseData([ + 'error' => $e->getMessage(), + ]); + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_FAIL, + ); + } + } + + private function updatePaymentState(PaymentInterface $payment): void + { + match ($payment->getDetails()['status'] ?? '') { + PayPlugApiClientInterface::STATUS_ABORTED, PayPlugApiClientInterface::STATUS_CANCELED, PayPlugApiClientInterface::STATUS_CANCELED_BY_ONEY => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_CANCEL), + PayPlugApiClientInterface::STATUS_AUTHORIZED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_AUTHORIZE), + PayPlugApiClientInterface::STATUS_CAPTURED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_COMPLETE), + PayPlugApiClientInterface::FAILED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_FAIL), + default => throw new \LogicException(sprintf('Unknown payment status "%s".', $payment->getDetails()['status'] ?? '')), // @phpstan-ignore-line - getDetails() return mixed + }; + } +} diff --git a/src/Command/Handler/StatusPaymentRequestHandler.php b/src/Command/Handler/StatusPaymentRequestHandler.php new file mode 100644 index 00000000..1f2c47fe --- /dev/null +++ b/src/Command/Handler/StatusPaymentRequestHandler.php @@ -0,0 +1,112 @@ +paymentRequestProvider->provide($statusPaymentRequest); + /** @var \Sylius\Component\Core\Model\PaymentInterface $payment */ + $payment = $paymentRequest->getPayment(); + if ('' !== $statusPaymentRequest->getForcedStatus()) { + $this->handleForcedStatus($statusPaymentRequest, $paymentRequest); + + return; + } + $method = $payment->getMethod(); + if (null === $method) { + throw new \LogicException('Payment method is not set for the payment.'); + } + + // We don't have a forced status, so we retrieve the payment status from PayPlug + $client = $this->apiClientFactory->createForPaymentMethod($method); + /** @var null|string $payplugPaymentId */ + $payplugPaymentId = $payment->getDetails()['payment_id'] ?? null; + if (null === $payplugPaymentId) { + $this->logger->warning('No PayPlug payment ID found in payment details.', ['payment_id' => $payment->getId(), 'order_id' => $payment->getOrder()?->getId()]); + $payment->setDetails(['status' => PayPlugApiClientInterface::FAILED]); + $this->updatePaymentState($payment); + return; + } + + $payplugPayment = $client->retrieve($payplugPaymentId); + + $paymentRequest->setResponseData((array) $payplugPayment); + $details = new \ArrayObject($payment->getDetails()); + $this->paymentNotificationHandler->treat($payment, $payplugPayment, $details); + + $payment->setDetails($details->getArrayCopy()); + if ($payment->getState() !== PaymentInterface::STATE_COMPLETED) { + // If is already completed, do not try to update it again (updated by notification) + $this->updatePaymentState($payment); + } + + // Mark the PaymentRequest as completed + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + } + + private function handleForcedStatus( + StatusPaymentRequest $statusPaymentRequest, + PaymentRequestInterface $paymentRequest, + ): void { + $payment = $paymentRequest->getPayment(); + + $payment->setDetails([ + ...$payment->getDetails(), + 'status' => $statusPaymentRequest->getForcedStatus(), + ]); + + $this->updatePaymentState($payment); + + // Mark the PaymentRequest as completed + $this->stateMachine->apply( + $paymentRequest, + PaymentRequestTransitions::GRAPH, + PaymentRequestTransitions::TRANSITION_COMPLETE, + ); + } + + private function updatePaymentState(PaymentInterface $payment): void + { + match ($payment->getDetails()['status'] ?? '') { + PayPlugApiClientInterface::STATUS_ABORTED, PayPlugApiClientInterface::STATUS_CANCELED, PayPlugApiClientInterface::STATUS_CANCELED_BY_ONEY => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_CANCEL), + PayPlugApiClientInterface::STATUS_AUTHORIZED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_AUTHORIZE), + PayPlugApiClientInterface::STATUS_CAPTURED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_COMPLETE), + PayPlugApiClientInterface::FAILED => $this->stateMachine + ->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_FAIL), + default => throw new \LogicException(sprintf('Unknown payment status "%s".', $payment->getDetails()['status'] ?? '')), // @phpstan-ignore-line - getDetails() return mixed + }; + } +} diff --git a/src/Command/NotifyPaymentRequest.php b/src/Command/NotifyPaymentRequest.php new file mode 100644 index 00000000..50f7feff --- /dev/null +++ b/src/Command/NotifyPaymentRequest.php @@ -0,0 +1,9 @@ + PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_oney', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_bancontact', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_american_express', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +final class CapturePaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface +{ + public function supports(PaymentRequestInterface $paymentRequest): bool + { + return $paymentRequest->getAction() === PaymentRequestInterface::ACTION_CAPTURE; + } + + public function provide(PaymentRequestInterface $paymentRequest): object + { + if ($this->isAlreadyCreated($paymentRequest)) { + // The payment has already been created, let's use the offline capture request to be redirected to the thank-you page + return new OfflineCapturePaymentRequest($paymentRequest->getId()); + } + + return new CapturePaymentRequest($paymentRequest->getId()); + } + + private function isAlreadyCreated(PaymentRequestInterface $paymentRequest): bool + { + $payment = $paymentRequest->getPayment(); + $details = $payment->getDetails(); + if ( + isset($details['status'], $details['payment_id']) && + PayPlugApiClientInterface::STATUS_CREATED !== $details['status'] + ) { + return true; + } + + if ( + array_key_exists('status', $details) && + PayPlugApiClientInterface::STATUS_CAPTURED === $details['status'] + ) { + return true; + } + + return false; + } +} diff --git a/src/Command/Provider/NotifyPaymentRequestCommandProvider.php b/src/Command/Provider/NotifyPaymentRequestCommandProvider.php new file mode 100644 index 00000000..0311f69b --- /dev/null +++ b/src/Command/Provider/NotifyPaymentRequestCommandProvider.php @@ -0,0 +1,43 @@ + PaymentRequestInterface::ACTION_NOTIFY], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_oney', + ['action' => PaymentRequestInterface::ACTION_NOTIFY], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_bancontact', + ['action' => PaymentRequestInterface::ACTION_NOTIFY], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_american_express', + ['action' => PaymentRequestInterface::ACTION_NOTIFY], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay', + ['action' => PaymentRequestInterface::ACTION_NOTIFY], +)] +final class NotifyPaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface +{ + public function supports(PaymentRequestInterface $paymentRequest): bool + { + return $paymentRequest->getAction() === PaymentRequestInterface::ACTION_NOTIFY; + } + + public function provide(PaymentRequestInterface $paymentRequest): object + { + return new NotifyPaymentRequest($paymentRequest->getId()); + } +} diff --git a/src/Command/Provider/StatusPaymentRequestCommandProvider.php b/src/Command/Provider/StatusPaymentRequestCommandProvider.php new file mode 100644 index 00000000..e75804b0 --- /dev/null +++ b/src/Command/Provider/StatusPaymentRequestCommandProvider.php @@ -0,0 +1,54 @@ + PaymentRequestInterface::ACTION_STATUS], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_oney', + ['action' => PaymentRequestInterface::ACTION_STATUS], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_bancontact', + ['action' => PaymentRequestInterface::ACTION_STATUS], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_american_express', + ['action' => PaymentRequestInterface::ACTION_STATUS], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.command_provider.payplug_apple_pay', + ['action' => PaymentRequestInterface::ACTION_STATUS], +)] +final class StatusPaymentRequestCommandProvider implements PaymentRequestCommandProviderInterface +{ + public function __construct(private RequestStack $requestStack) + { + } + + public function supports(PaymentRequestInterface $paymentRequest): bool + { + return $paymentRequest->getAction() === PaymentRequestInterface::ACTION_STATUS; + } + + public function provide(PaymentRequestInterface $paymentRequest): object + { + $request = $this->requestStack->getCurrentRequest(); + if (null === $request) { + return new StatusPaymentRequest($paymentRequest->getId()); + } + $forcedStatus = $request->query->getString('status'); + + return new StatusPaymentRequest($paymentRequest->getId(), $forcedStatus); + } +} diff --git a/src/Command/StatusPaymentRequest.php b/src/Command/StatusPaymentRequest.php new file mode 100644 index 00000000..1c3692c3 --- /dev/null +++ b/src/Command/StatusPaymentRequest.php @@ -0,0 +1,22 @@ +forcedStatus; + } +} diff --git a/src/Console/Command/CaptureAuthorizedPaymentCommand.php b/src/Console/Command/CaptureAuthorizedPaymentCommand.php new file mode 100644 index 00000000..92e70baf --- /dev/null +++ b/src/Console/Command/CaptureAuthorizedPaymentCommand.php @@ -0,0 +1,77 @@ +addOption('days', 'd', InputOption::VALUE_OPTIONAL, 'Number of days to wait before capturing authorized payments', 6) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $days = \filter_var($input->getOption('days'), \FILTER_VALIDATE_INT); + if (false === $days) { + throw new \InvalidArgumentException('Invalid number of days provided.'); + } + + $payments = $this->paymentRepository->findAllAuthorizedOlderThanDays($days); + + if ($payments === []) { + $this->logger->debug('[Payplug] No authorized payments found.'); + } + + foreach ($payments as $i => $payment) { + $this->logger->info('[Payplug] Capturing payment {paymentId} (order #{orderNumber})', [ + 'paymentId' => $payment->getId(), + 'orderNumber' => $payment->getOrder()?->getNumber() ?? 'N/A', + ]); + $output->writeln(sprintf('Capturing payment %d (order #%s)', $payment->getId(), $payment->getOrder()?->getNumber() ?? 'N/A')); // @phpstan-ignore-line + + try { + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_COMPLETE); + } catch (\Throwable $e) { + $this->logger->critical('[Payplug] Error while capturing payment {paymentId}', [ + 'paymentId' => $payment->getId(), + 'exception' => $e->getMessage(), + ]); + + continue; + } + + if ($i % 10 === 0) { + $this->entityManager->flush(); + } + } + + $this->entityManager->flush(); + + return Command::SUCCESS; + } +} diff --git a/src/Const/Permission.php b/src/Const/Permission.php new file mode 100644 index 00000000..6e85236a --- /dev/null +++ b/src/Const/Permission.php @@ -0,0 +1,40 @@ +oneySimulationDataProvider = $oneySimulationDataProvider; - $this->cartContext = $cartContext; - $this->productVariantRepository = $productVariantRepository; - $this->cartFactory = $orderFactory; - $this->orderItemFactory = $orderItemFactory; - $this->orderModifier = $orderModifier; - $this->itemQuantityModifier = $itemQuantityModifier; - $this->oneyRulesExtension = $oneyRulesExtension; - $this->productRepository = $productRepository; } protected function createTempCart( @@ -76,10 +42,10 @@ protected function createTempCart( int $quantity, ChannelInterface $channel, string $localeCode, - string $currencyCode + string $currencyCode, ): OrderInterface { /** @var OrderInterface $tempCart */ - $tempCart = $this->cartFactory->createNew(); + $tempCart = $this->orderFactory->createNew(); $tempCart->setChannel($channel); $tempCart->setLocaleCode($localeCode); $tempCart->setCurrencyCode($currencyCode); diff --git a/src/Controller/CardController.php b/src/Controller/CardController.php index c3c9d600..d26770e0 100644 --- a/src/Controller/CardController.php +++ b/src/Controller/CardController.php @@ -4,64 +4,52 @@ namespace PayPlug\SyliusPayPlugPlugin\Controller; +use Doctrine\Persistence\ManagerRegistry; use Payplug\Exception\NotFoundException; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Entity\Card; +use PayPlug\SyliusPayPlugPlugin\Entity\CardsOwnerInterface; use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Customer\Context\CustomerContextInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Contracts\Translation\TranslatorInterface; +#[AsController] final class CardController extends AbstractController { - /** @var CustomerContextInterface */ - private $customerContext; - - /** @var EntityRepository */ - private $payplugCardRepository; - - /** @var FlashBagInterface */ - private $flashBag; - - /** @var TranslatorInterface */ - private $translator; - - /** @var PayPlugApiClientInterface */ - private $payPlugApiClient; - public function __construct( - CustomerContextInterface $customerContext, - EntityRepository $payplugCardRepository, - FlashBagInterface $flashBag, - TranslatorInterface $translator, - PayPlugApiClientInterface $payPlugApiClient + private CustomerContextInterface $customerContext, + private EntityRepository $payplugCardRepository, + private TranslatorInterface $translator, + #[Autowire('@payplug_sylius_payplug_plugin.api_client.payplug')] + private PayPlugApiClientInterface $payPlugApiClient, + private RequestStack $requestStack, + private ManagerRegistry $managerRegistry, ) { - $this->customerContext = $customerContext; - $this->payplugCardRepository = $payplugCardRepository; - $this->flashBag = $flashBag; - $this->translator = $translator; - $this->payPlugApiClient = $payPlugApiClient; } + #[Route(path: '/{_locale}/account/saved-cards', name: 'payplug_sylius_card_account_index', methods: ['GET'])] public function indexAction(): Response { $customer = $this->customerContext->getCustomer(); - if (!$customer instanceof CustomerInterface) { - return $this->render('@PayPlugSyliusPayPlugPlugin/card/index.html.twig', [ - 'savedCards' => [], - ]); + $savedCards = []; + if ($customer instanceof CardsOwnerInterface) { + $savedCards = $customer->getCards(); } - return $this->render('@PayPlugSyliusPayPlugPlugin/card/index.html.twig', [ - /** @phpstan-ignore-next-line */ - 'savedCards' => $customer->getCards(), + return $this->render('@PayPlugSyliusPayPlugPlugin/shop/saved_cards/index.html.twig', [ + 'savedCards' => $savedCards, ]); } + #[Route(path: '/{_locale}/account/saved-cards/delete/{id}', name: 'payplug_sylius_card_account_delete', methods: ['DELETE'])] public function deleteAction(int $id): Response { $customer = $this->customerContext->getCustomer(); @@ -76,7 +64,7 @@ public function deleteAction(int $id): Response return $this->redirectToRoute('payplug_sylius_card_account_index'); } - if (true === $this->isCardExpired($card)) { + if ($this->isCardExpired($card)) { $this->removeCard($card); return $this->redirectToRoute('payplug_sylius_card_account_index'); @@ -86,8 +74,8 @@ public function deleteAction(int $id): Response try { $this->payPlugApiClient->deleteCard($cardToken); - } catch (NotFoundException $e) { - $this->flashBag->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.ui.account.saved_cards.deleted_error')); + } catch (NotFoundException) { + $this->requestStack->getSession()->getFlashBag()->add('error', $this->translator->trans('payplug_sylius_payplug_plugin.ui.account.saved_cards.deleted_error')); return $this->redirectToRoute('payplug_sylius_card_account_index'); } @@ -99,11 +87,11 @@ public function deleteAction(int $id): Response private function removeCard(Card $card): void { - $entityManager = $this->getDoctrine()->getManager(); + $entityManager = $this->managerRegistry->getManager(); $entityManager->remove($card); $entityManager->flush(); - $this->flashBag->add('success', $this->translator->trans('payplug_sylius_payplug_plugin.ui.account.saved_cards.deleted_successfully')); + $this->requestStack->getSession()->getFlashBag()->add('success', $this->translator->trans('payplug_sylius_payplug_plugin.ui.account.saved_cards.deleted_successfully')); } private function isCardExpired(Card $card): bool @@ -112,13 +100,6 @@ private function isCardExpired(Card $card): bool $currentYear = $now->format('Y'); $expirationYear = (string) $card->getExpirationYear(); - if ( - ($currentYear < $expirationYear) || - ($currentYear === $expirationYear && $now->format('n') <= (string) $card->getExpirationMonth()) - ) { - return false; - } - - return true; + return $currentYear >= $expirationYear && !($currentYear === $expirationYear && $now->format('n') <= (string) $card->getExpirationMonth()); } } diff --git a/src/Controller/CompleteInfoController.php b/src/Controller/CompleteInfoController.php index f25f565a..77b07555 100644 --- a/src/Controller/CompleteInfoController.php +++ b/src/Controller/CompleteInfoController.php @@ -16,35 +16,36 @@ use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Routing\Attribute\Route; use Symfony\Component\Validator\Constraints\NotBlank; use Webmozart\Assert\Assert; +#[AsController] final class CompleteInfoController extends AbstractController { - /** @var \PayPlug\SyliusPayPlugPlugin\Validator\OneyInvalidDataRetriever */ - private $invalidDataRetriever; - - /** @var \Sylius\Component\Resource\Repository\RepositoryInterface */ - private $customerRepository; - public function __construct( - OneyInvalidDataRetriever $invalidDataRetriever, - RepositoryInterface $customerRepository + private OneyInvalidDataRetriever $invalidDataRetriever, + private RepositoryInterface $customerRepository, + private RepositoryInterface $orderRepository, ) { - $this->invalidDataRetriever = $invalidDataRetriever; - $this->customerRepository = $customerRepository; } + #[Route(path: '/{_locale}/payplug/oney_complete_info', name: 'payplug_sylius_oney_complete_info', methods: ['GET', 'POST'])] public function __invoke( Request $request, CartContextInterface $cartContext, - EntityManagerInterface $entityManager + EntityManagerInterface $entityManager, ): Response { - if (!$request->isXmlHttpRequest()) { - throw $this->createNotFoundException(); + $order = $cartContext->getCart(); + $tokenValue = $request->get('tokenValue'); + if ('' !== $tokenValue) { + $orderFromToken = $this->orderRepository->findOneBy(['tokenValue' => $request->get('tokenValue')]); + if ($orderFromToken instanceof OrderInterface) { + $order = $orderFromToken; + } } - $order = $cartContext->getCart(); Assert::isInstanceOf($order, OrderInterface::class); $data = $this->invalidDataRetriever->getForOrder($order); $form = $this->createFormForOrder($order, $data); @@ -72,7 +73,7 @@ public function __invoke( } return $this->render('@PayPlugSyliusPayPlugPlugin/form/complete_info_popin.html.twig', [ - 'form' => $form->createView(), + 'form' => $form, ]); } diff --git a/src/Controller/IntegratedPaymentController.php b/src/Controller/IntegratedPaymentController.php new file mode 100644 index 00000000..a5b53925 --- /dev/null +++ b/src/Controller/IntegratedPaymentController.php @@ -0,0 +1,101 @@ + $paymentMethodRepository + */ + public function __construct( + private CartContextInterface $cartContext, + private RepositoryInterface $paymentMethodRepository, + private OrderRepositoryInterface $orderRepository, + private PayPlugPaymentDataCreator $paymentDataCreator, + private PayPlugApiClientFactory $apiClientFactory, + private EntityManagerInterface $entityManager, + private LoggerInterface $logger, + ) { + } + + /** + * The InitPayment action is called when the user clicks on the "Pay" button from the integratedPayment iframe. + * + * The actual payment (ie latest in cart state) of the order is sent to Payplug, + * specifying the IntegratedPayment integration. + * + * @see https://docs.payplug.com/api/integratedref.html#trigger-a-payment + */ + #[Route(path: '/{_locale}/payplug/integrated-payment/init/{paymentMethodId}', name: 'payplug_sylius_integrated_payment_init', methods: ['GET', 'POST'])] + public function initPaymentAction(Request $request, int $paymentMethodId): Response + { + $paymentMethod = $this->paymentMethodRepository->find($paymentMethodId); + if (!$paymentMethod instanceof PaymentMethodInterface) { + throw $this->createNotFoundException(); + } + + $order = null; + if (\is_string($orderToken = $request->query->get('orderToken'))) { + $order = $this->orderRepository->findOneByTokenValue($orderToken); + } + if (!$order instanceof \Sylius\Component\Order\Model\OrderInterface) { + $order = $this->cartContext->getCart(); + } + if (!$order instanceof OrderInterface) { + throw $this->createNotFoundException('No order found'); + } + + $payment = $order->getLastPayment(); + if (!$payment instanceof PaymentInterface) { + throw $this->createNotFoundException('No payment available'); + } + + $payment->setMethod($paymentMethod); + $factoryName = $paymentMethod->getGatewayConfig()?->getFactoryName(); + if (PayPlugGatewayFactory::FACTORY_NAME !== $factoryName) { + throw new BadRequestHttpException('Unsupported payment method of Integrated Payment'); + } + + $paymentData = $this->paymentDataCreator->create($payment); + // Mandatory + $paymentData['integration'] = PayPlugApiClientInterface::INTEGRATED_PAYMENT_INTEGRATION; + $this->logger->debug('Payplug Payment data for creation', $paymentData->getArrayCopy()); + + $apiClient = $this->apiClientFactory->create($factoryName); + $payplugPayment = $apiClient->createPayment($paymentData->getArrayCopy()); + $this->logger->debug('PayPlug payment created', (array) $payplugPayment); + + $paymentData['payment_id'] = $payplugPayment->id; + $paymentData['is_live'] = $payplugPayment->is_live; + $payment->setDetails($paymentData->getArrayCopy()); + + $this->entityManager->flush(); + + return new JsonResponse([ + 'payment_id' => $payplugPayment->id, + ], Response::HTTP_CREATED); + } +} diff --git a/src/Controller/IpnAction.php b/src/Controller/IpnAction.php new file mode 100644 index 00000000..ee7ca7c5 --- /dev/null +++ b/src/Controller/IpnAction.php @@ -0,0 +1,104 @@ +getContent(); + + if (!is_string($input)) { + throw new LogicException('Input must be of type string.'); + } + + $content = json_decode($input, true); + $details = ArrayObject::ensureArrayObject($content); + + // if we are too fast canceling a payment before we got an answer from PayPlug gateway + if (null === $details['id']) { + return new JsonResponse(null, Response::HTTP_UNAUTHORIZED); + } + + $payment = $this->paymentRepository->findOneByPayPlugPaymentId($details['id']); + + if (null === $payment) { + return new JsonResponse(null, Response::HTTP_UNAUTHORIZED); + } + + $paymentMethod = $payment->getMethod(); + + Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class); + $gateway = $paymentMethod->getGatewayConfig(); + + Assert::isInstanceOf($gateway, GatewayConfigInterface::class); + $gatewayConfig = $gateway->getConfig(); + + if ( + !$paymentMethod->getGatewayConfig() instanceof GatewayConfigInterface || + !\in_array($factoryName = $paymentMethod->getGatewayConfig()->getFactoryName(), [ + PayPlugGatewayFactory::FACTORY_NAME, + OneyGatewayFactory::FACTORY_NAME, + BancontactGatewayFactory::FACTORY_NAME, + ApplePayGatewayFactory::FACTORY_NAME, + ], true) + ) { + return new JsonResponse(null, Response::HTTP_UNAUTHORIZED); + } + + $this->payPlugApiClient = $this->apiClientFactory->create($factoryName); + + try { + $resource = $this->payPlugApiClient->treat($input); + + $this->paymentNotificationHandler->treat($payment, $resource, $details); + $this->refundNotificationHandler->treat($payment, $resource, $details); + $this->entityManager->flush(); + } catch (PayplugException $exception) { + $details['status'] = PayPlugApiClientInterface::FAILED; + $this->logger->error('[PayPlug] Notify action', ['error' => $exception->getMessage()]); + } + + return new JsonResponse(); + } +} diff --git a/src/Controller/OneClickAction.php b/src/Controller/OneClickAction.php index 1f17f35b..166fc383 100644 --- a/src/Controller/OneClickAction.php +++ b/src/Controller/OneClickAction.php @@ -10,7 +10,7 @@ use Payum\Core\ApiAwareInterface; use Payum\Core\GatewayAwareInterface; use Payum\Core\GatewayAwareTrait; -use Payum\Core\Model\GatewayConfigInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; use Payum\Core\Payum; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; @@ -19,30 +19,26 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Routing\Attribute\Route; +/** + * @deprecated - Used by payum + */ +#[AsController] class OneClickAction extends AbstractController implements GatewayAwareInterface, ApiAwareInterface { - use GatewayAwareTrait, ApiAwareTrait; - - /** @var PaymentRepositoryInterface */ - private $paymentRepository; - - /** @var Payum */ - private $payum; - - /** @var PayPlugApiClientFactory */ - private $payPlugApiClientFactory; + use GatewayAwareTrait; + use ApiAwareTrait; public function __construct( - PaymentRepositoryInterface $paymentRepository, - Payum $payum, - PayPlugApiClientFactory $payPlugApiClientFactory + private PaymentRepositoryInterface $paymentRepository, + private Payum $payum, + private PayPlugApiClientFactory $payPlugApiClientFactory, ) { - $this->paymentRepository = $paymentRepository; - $this->payum = $payum; - $this->payPlugApiClientFactory = $payPlugApiClientFactory; } + #[Route(path: '/{_locale}/payment/capture/{payum_token}/1-click-checkup', name: 'payplug_sylius_oneclick_verification', methods: ['GET'])] public function __invoke(Request $request): Response { $token = $this->payum->getHttpRequestVerifier()->verify($request); @@ -55,16 +51,19 @@ public function __invoke(Request $request): Response /** @var GatewayConfigInterface $paymentGateway */ $paymentGateway = $paymentMethod->getGatewayConfig(); + $gatewayName = $paymentGateway->getGatewayName(); + if (null === $gatewayName) { + throw new \InvalidArgumentException('Payment gateway name cannot be null'); + } $captureToken = $this->payum->getTokenFactory()->createCaptureToken( - $paymentGateway->getGatewayName(), + $gatewayName, $payment, 'sylius_shop_order_thank_you', - [] + [], ); - $secretKey = $paymentGateway->getConfig()['secretKey']; - $this->payPlugApiClient = $this->payPlugApiClientFactory->create(PayPlugGatewayFactory::FACTORY_NAME, $secretKey); + $this->payPlugApiClient = $this->payPlugApiClientFactory->createForPaymentMethod($paymentMethod); $resource = $this->payPlugApiClient->retrieve((string) $payment->getDetails()['payment_id']); //if is_paid is true, you can consider the payment as being fully paid, @@ -73,7 +72,8 @@ public function __invoke(Request $request): Response } //if both fields authorization and authorized_at are present and filled, the authorization was successful - if ($resource->__isset('authorization') && + if ( + $resource->__isset('authorization') && $resource->__isset('authorized_at') && null !== $resource->__get('authorization') && null !== $resource->__get('authorized_at') diff --git a/src/Controller/OneyIsProductEligible.php b/src/Controller/OneyIsProductEligible.php index 57eb435c..616760e7 100644 --- a/src/Controller/OneyIsProductEligible.php +++ b/src/Controller/OneyIsProductEligible.php @@ -9,10 +9,14 @@ use Sylius\Component\Core\Model\ProductVariantInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Routing\Attribute\Route; use Webmozart\Assert\Assert; +#[AsController] final class OneyIsProductEligible extends AbstractOneyController { + #[Route(path: '/{_locale}/payplug/oney/is-product-eligible', name: 'payplug_sylius_oney_is_product_eligible', methods: ['GET'])] public function __invoke(Request $request): JsonResponse { /** @var OrderInterface $cart */ @@ -33,7 +37,7 @@ public function __invoke(Request $request): JsonResponse private function isProductEligible( OrderInterface $cart, string $productVariantCode, - int $quantity + int $quantity, ): bool { $productVariant = $this->productVariantRepository->findOneBy(['code' => $productVariantCode]); Assert::isInstanceOf($productVariant, ProductVariantInterface::class); @@ -49,7 +53,7 @@ private function isProductEligible( $quantity, $channel, $cart->getLocaleCode(), - $cart->getCurrencyCode() + $cart->getCurrencyCode(), ); return $this->oneyRulesExtension->isCartEligible($tempCart); diff --git a/src/Controller/OneySimulationPopin.php b/src/Controller/OneySimulationPopin.php index ac866bef..3bb4aa0b 100644 --- a/src/Controller/OneySimulationPopin.php +++ b/src/Controller/OneySimulationPopin.php @@ -9,10 +9,14 @@ use Sylius\Component\Core\Model\ProductVariantInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Attribute\AsController; +use Symfony\Component\Routing\Attribute\Route; use Webmozart\Assert\Assert; +#[AsController] final class OneySimulationPopin extends AbstractOneyController { + #[Route(path: '/{_locale}/payplug/oney_popin', name: 'payplug_sylius_oney_simulation_popin', methods: ['GET'])] public function __invoke(Request $request): Response { /** @var OrderInterface $cart */ @@ -28,11 +32,11 @@ public function __invoke(Request $request): Response $simulationData = $this->oneySimulationDataProvider->getForCart($cart); return $this->render( - '@PayPlugSyliusPayPlugPlugin/oney/popin.html.twig', + '@PayPlugSyliusPayPlugPlugin/shop/oney/popin.html.twig', [ 'data' => $simulationData, 'ineligibilityData' => $this->oneyRulesExtension->getReasonsOfIneligibility($cart), - ] + ], ); } @@ -42,7 +46,7 @@ public function __invoke(Request $request): Response private function renderSimulateForProductVariant( OrderInterface $cart, string $productVariantCode, - int $quantity + int $quantity, ): Response { $productVariant = $this->productVariantRepository->findOneBy(['code' => $productVariantCode]); Assert::isInstanceOf($productVariant, ProductVariantInterface::class); @@ -58,17 +62,17 @@ private function renderSimulateForProductVariant( $quantity, $channel, $cart->getLocaleCode(), - $cart->getCurrencyCode() + $cart->getCurrencyCode(), ); $simulationData = $this->oneySimulationDataProvider->getForCart($tempCart); return $this->render( - '@PayPlugSyliusPayPlugPlugin/oney/popin.html.twig', + '@PayPlugSyliusPayPlugPlugin/shop/oney/popin.html.twig', [ 'data' => $simulationData, 'ineligibilityData' => $this->oneyRulesExtension->getReasonsOfIneligibility($tempCart), - ] + ], ); } } diff --git a/src/Controller/OrderController.php b/src/Controller/OrderController.php new file mode 100644 index 00000000..7c70250e --- /dev/null +++ b/src/Controller/OrderController.php @@ -0,0 +1,385 @@ + [ + 'flash' => false, + ], + ], + methods: ['GET', 'POST'], + )] + public function initiateApplePaySessionAction(Request $request): Response + { + $configuration = $this->requestConfigurationFactory->create($this->metadata, $request); + $this->isGrantedOr403($configuration, ResourceActions::UPDATE); + + /** @var OrderInterface $resource */ + $resource = $this->findOr404($configuration); + + if (OrderPaymentStates::STATE_PAID === $resource->getPaymentState()) { + throw new AccessDeniedException(); + } + + /** @var ResourceControllerEvent $event */ + $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource); + + if ($event->isStopped() && !$configuration->isHtmlRequest()) { + throw new HttpException($event->getErrorCode(), $event->getMessage()); + } + + if ($event->isStopped()) { + $eventResponse = $event->getResponse(); + if (null !== $eventResponse) { + return $eventResponse; + } + + return new JsonResponse([], Response::HTTP_BAD_REQUEST); + } + + try { + $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource); + + $postEventResponse = $postEvent->getResponse(); + + if ($postEventResponse instanceof \Symfony\Component\HttpFoundation\Response) { + return $postEventResponse; + } + + $initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource); + $initializeEventResponse = $initializeEvent->getResponse(); + + if ($initializeEventResponse instanceof \Symfony\Component\HttpFoundation\Response) { + return $initializeEventResponse; + } + + if ($this->stateMachineAbstraction->can($resource, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT)) { + $this->stateMachineAbstraction->apply($resource, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_SELECT_PAYMENT); + } + + $payment = $this->applePayPaymentProvider->provide($request, $resource); + + $this->logger->info('[Payplug] ApplePay payment', ['payment' => $payment, 'details' => $payment->getDetails()]); + $this->manager->flush(); + + return new JsonResponse([ + 'success' => true, + 'merchant_session' => $payment->getDetails()['merchant_session'], + ]); + } catch (UpdateHandlingException $exception) { + $this->logger->error('Could update ApplePay order', [ + 'order_id' => $resource->getId(), + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ]); + + return new JsonResponse([], Response::HTTP_BAD_REQUEST); + } catch (\Exception) { + try { + $this->applePayPaymentProvider->cancel($resource); + $this->manager->flush(); + } catch (\Throwable $throwable) { + $this->logger->error('Could not cancel ApplePay payment', [ + 'order_id' => $resource->getId(), + 'code' => $throwable->getCode(), + 'message' => $throwable->getMessage(), + 'trace' => $throwable->getTraceAsString(), + ]); + } + + $request->getSession()->getFlashBag()->add('error', 'sylius.payment.cancelled'); + $dataResponse = []; + $redirect = $this->getApplePayNextRoute($resource); + $dataResponse['returnUrl'] = $redirect->getTargetUrl(); + $dataResponse['responseToApple'] = ['status' => self::APPLE_ERROR_RESPONSE_CODE]; + + $response = [ + 'success' => false, + 'data' => $dataResponse, + ]; + + return new JsonResponse($response, Response::HTTP_OK); + } + } + + #[Route( + path: '/payplug/apple-pay/complete/{id}', + name: 'payplug_shop_checkout_apple_confirm', + options: [ + '_sylius' => [ + 'flash' => false, + ], + ], + methods: ['GET', 'POST'], + )] + public function confirmApplePayPaymentAction(Request $request): Response + { + $configuration = $this->requestConfigurationFactory->create($this->metadata, $request); + $this->isGrantedOr403($configuration, ResourceActions::UPDATE); + + /** @var OrderInterface $order */ + $order = $this->findOr404($configuration); + /** @var ResourceControllerEvent $event */ + $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $order); + if ($event->isStopped() && !$configuration->isHtmlRequest()) { + throw new HttpException($event->getErrorCode(), $event->getMessage()); + } + if ($event->isStopped()) { + $eventResponse = $event->getResponse(); + if (null !== $eventResponse) { + return $eventResponse; + } + return new JsonResponse([], Response::HTTP_BAD_REQUEST); + } + + try { + $lastPayment = $this->applePayPaymentProvider->patch($request, $order); + if (PaymentInterface::STATE_COMPLETED !== $lastPayment->getState()) { + throw new PaymentNotCompletedException(); + } + } catch (\Exception | PaymentNotCompletedException $exception) { + $request->getSession()->getFlashBag()->add('error', 'sylius.payment.cancelled'); + $redirect = $this->getApplePayNextRoute($order); + + $dataResponse = []; + $dataResponse['returnUrl'] = $redirect->getTargetUrl(); + $dataResponse['responseToApple'] = ['status' => self::APPLE_ERROR_RESPONSE_CODE]; + $dataResponse['errors'] = 'Payment not completed'; + $dataResponse['message'] = $exception->getMessage(); + + $this->logger->error('Could not complete ApplePay payment', ['exception' => $exception, 'data_response' => $dataResponse]); + + $response = [ + 'success' => false, + 'data' => $dataResponse, + ]; + + return new JsonResponse($response, Response::HTTP_BAD_REQUEST); + } + + $this->manager->flush(); + + $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $order); + + $postEventResponse = $postEvent->getResponse(); + + if ($postEventResponse instanceof \Symfony\Component\HttpFoundation\Response) { + return $postEventResponse; + } + + if ($this->stateMachineAbstraction->can($order, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_COMPLETE)) { + $this->stateMachineAbstraction->apply($order, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_COMPLETE); + } + + $this->manager->flush(); + + $request->getSession()->set('sylius_order_id', $order->getId()); + $dataResponse = []; + $redirect = $this->redirectToRoute('sylius_shop_order_thank_you', ['_locale' => $order->getLocaleCode()]); + $dataResponse['returnUrl'] = $redirect->getTargetUrl(); + $dataResponse['responseToApple'] = ['status' => self::APPLE_SUCCESS_RESPONSE_CODE]; + + $response = [ + 'success' => true, + 'data' => $dataResponse, + ]; + + return new JsonResponse($response, Response::HTTP_OK); + } + + #[Route( + path: '/payplug/apple-pay/cancel/{id}', + name: 'payplug_shop_checkout_apple_cancel', + options: [ + '_sylius' => [ + 'flash' => false, + ], + ], + methods: ['GET', 'POST'], + )] + public function cancelApplePaySessionAction(Request $request): Response + { + $configuration = $this->requestConfigurationFactory->create($this->metadata, $request); + + $this->isGrantedOr403($configuration, ResourceActions::UPDATE); + + /** @var OrderInterface $resource */ + $resource = $this->findOr404($configuration); + $lock = $this->lockFactory->createLock('apple_pay_cancel' . $resource->getId()); + $lock->acquire(true); + + /** @var ResourceControllerEvent $event */ + $event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource); + + if ($event->isStopped() && !$configuration->isHtmlRequest()) { + throw new HttpException($event->getErrorCode(), $event->getMessage()); + } + + if ($event->isStopped()) { + $eventResponse = $event->getResponse(); + if (null !== $eventResponse) { + return $eventResponse; + } + + return new JsonResponse([], Response::HTTP_BAD_REQUEST); + } + + try { + $this->resourceUpdateHandler->handle($resource, $configuration, $this->manager); + + $postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource); + + $postEventResponse = $postEvent->getResponse(); + + if ($postEventResponse instanceof \Symfony\Component\HttpFoundation\Response) { + return $postEventResponse; + } + + $initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource); + + $initializeEventResponse = $initializeEvent->getResponse(); + + if ($initializeEventResponse instanceof \Symfony\Component\HttpFoundation\Response) { + return $initializeEventResponse; + } + + try { + $this->applePayPaymentProvider->cancel($resource); + $this->manager->flush(); + } catch (\Throwable $throwable) { + $this->logger->error('Could not cancel ApplePay payment', [ + 'order_id' => $resource->getId(), + 'code' => $throwable->getCode(), + 'message' => $throwable->getMessage(), + 'trace' => $throwable->getTraceAsString(), + ]); + } + + if ($this->stateMachineAbstraction->can($resource, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING)) { + $this->stateMachineAbstraction->apply($resource, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_SELECT_SHIPPING); + } + $this->manager->flush(); + + $request->getSession()->getFlashBag()->add('error', 'sylius.payment.cancelled'); + + $dataResponse = []; + $redirect = $this->getApplePayNextRoute($resource); + + $dataResponse['returnUrl'] = $redirect->getTargetUrl(); + $dataResponse['responseToApple'] = ['status' => self::APPLE_SUCCESS_RESPONSE_CODE]; + + $response = [ + 'success' => true, + 'data' => $dataResponse, + ]; + + $lock->release(); + + return new JsonResponse($response); + } catch (UpdateHandlingException $exception) { + $this->logger->error('Could update ApplePay order', [ + 'order_id' => $resource->getId(), + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ]); + + return new JsonResponse([], Response::HTTP_BAD_REQUEST); + } catch (\Exception $exception) { + $this->logger->error('Could not cancel ApplePay payment', [ + 'order_id' => $resource->getId(), + 'code' => $exception->getCode(), + 'message' => $exception->getMessage(), + 'trace' => $exception->getTraceAsString(), + ]); + + $request->getSession()->getFlashBag()->add('error', 'sylius.payment.cancelled'); + + $dataResponse = []; + + $redirect = $this->getApplePayNextRoute($resource); + + $dataResponse['returnUrl'] = $redirect->getTargetUrl(); + $dataResponse['responseToApple'] = ['status' => self::APPLE_ERROR_RESPONSE_CODE]; + + $response = [ + 'success' => false, + 'data' => $dataResponse, + ]; + + return new JsonResponse($response, Response::HTTP_OK); + } + } + + private function getApplePayNextRoute(OrderInterface $resource): RedirectResponse + { + $redirect = $this->redirectToRoute('sylius_shop_checkout_select_payment', ['_locale' => $resource->getLocaleCode()]); + + if (OrderCheckoutStates::STATE_COMPLETED === $resource->getCheckoutState()) { + $redirect = $this->redirectToRoute('sylius_shop_order_show', [ + 'tokenValue' => $resource->getTokenValue(), + '_locale' => $resource->getLocaleCode(), + ]); + } + + if (OrderInterface::STATE_NEW === $resource->getState()) { + $redirect = $this->redirectToRoute('sylius_shop_order_show', [ + 'tokenValue' => $resource->getTokenValue(), + '_locale' => $resource->getLocaleCode(), + ]); + } + + $this->logger->debug('[Payplug] Redirect', ['redirect' => $redirect, 'targetUrl' => $redirect->getTargetUrl()]); + + return $redirect; + } +} diff --git a/src/Creator/PayPlugPaymentDataCreator.php b/src/Creator/PayPlugPaymentDataCreator.php new file mode 100644 index 00000000..e9e32322 --- /dev/null +++ b/src/Creator/PayPlugPaymentDataCreator.php @@ -0,0 +1,358 @@ +getOrder(); + + /** @var CustomerInterface $customer */ + $customer = $order->getCustomer(); + + /** @var ArrayObject $details */ + $details = new ArrayObject(); + $details['amount'] = $payment->getAmount(); + $details['currency'] = $payment->getCurrencyCode(); + + $details['metadata'] = [ + 'customer_id' => $customer->getId(), + 'order_number' => $order->getNumber() ?? $order->getTokenValue() ?? $order->getId(), + ]; + + if ([] !== $context) { + $details['payment_context'] = $context; + } + + // DSP2 fields + /** @var AddressInterface $shipping */ + $shipping = $order->getShippingAddress(); + /** @var AddressInterface $billing */ + $billing = $order->getBillingAddress(); + + $deliveryType = $shipping->getId() === $billing->getId( + ) ? self::DELIVERY_TYPE_BILLING : self::DELIVERY_TYPE_NEW; + + $this->addBillingInfo($billing, $customer, $order, $details); + $this->addShippingInfo($shipping, $customer, $order, $deliveryType, $details); + + $paymentMethod = $payment->getMethod(); + $gatewayFactoryName = $paymentMethod?->getGatewayConfig()?->getFactoryName(); + + if ( + PayPlugGatewayFactory::FACTORY_NAME === $gatewayFactoryName && + $paymentMethod instanceof PaymentMethodInterface + ) { + $details['allow_save_card'] = false; + $details = $this->alterPayPlugDetailsForOneClick($paymentMethod, $details); + $details = $this->alterPayPlugDetailsForDeferredCapture($paymentMethod, $details); + } + + if (OneyGatewayFactory::FACTORY_NAME === $gatewayFactoryName) { + $details = $this->alterOneyDetails($details); + $details->offsetSet('payment_context', $this->getCartContext($order)); + } + + $this->addPaymentMethodFieldToDetails($details, $gatewayFactoryName ?? ''); + + return $details; + } + + public function formatNumber(string $phoneNumber, ?string $isoCode): array + { + try { + $phoneNumberUtil = PhoneNumberUtil::getInstance(); + $parsed = $phoneNumberUtil->parse($phoneNumber, $isoCode); + + if (!$phoneNumberUtil->isValidNumber($parsed)) { + return [ + 'phone' => null, + 'is_mobile' => null, + ]; + } + + $formatted = $phoneNumberUtil->format($parsed, PhoneNumberFormat::E164); + + return [ + 'phone' => $formatted, + 'is_mobile' => PhoneNumberType::MOBILE === $phoneNumberUtil->getNumberType($parsed), + ]; + } catch (NumberParseException) { + return [ + 'phone' => null, + 'is_mobile' => null, + ]; + } + } + + private function formatTitle(CustomerInterface $customer): ?string + { + $gender = $customer->getGender(); + + return 'm' === $gender ? 'mr' : ('f' === $gender ? 'mrs' : null); + } + + private function formatLanguageCode(?string $languageCode): ?string + { + if (null === $languageCode) { + return null; + } + + $parse = explode('_', $languageCode); + + return strtolower($parse[0]); + } + + private function loadPhoneNumbers( + ?array $phoneData, + ?string &$mobilePhone = null, + ?string &$landingPhone = null, + ): void { + if (null === $phoneData) { + return; + } + if (!isset($phoneData['phone'], $phoneData['is_mobile'])) { + return; + } + if (true === $phoneData['is_mobile']) { + $mobilePhone = $phoneData['phone']; + } + if (true !== $phoneData['is_mobile']) { + $landingPhone = $phoneData['phone']; + } + } + + private function addBillingInfo( + AddressInterface $billing, + CustomerInterface $customer, + OrderInterface $order, + ArrayObject &$details, + ): void { + //Sylius does not require any phone number so we have to considere it null + $billingPhone = null !== $billing->getPhoneNumber() ? $this->formatNumber( + $billing->getPhoneNumber(), + $billing->getCountryCode(), + ) : null; + $this->loadPhoneNumbers($billingPhone, $billingMobilePhone, $billingLandingPhone); + + $details['billing'] = [ + 'title' => $this->formatTitle($customer), + 'first_name' => $billing->getFirstName(), + 'last_name' => $billing->getLastName(), + 'company_name' => $billing->getCompany(), + 'email' => $customer->getEmail(), + 'mobile_phone_number' => $billingMobilePhone, + 'landline_phone_number' => $billingLandingPhone, + 'address1' => $billing->getStreet(), + 'address2' => null, + 'postcode' => $billing->getPostcode(), + 'city' => $billing->getCity(), + 'state' => $billing->getProvinceName(), + 'country' => $billing->getCountryCode(), + 'language' => $this->formatLanguageCode($order->getLocaleCode()), + ]; + } + + private function addShippingInfo( + AddressInterface $shipping, + CustomerInterface $customer, + OrderInterface $order, + string $deliveryType, + ArrayObject &$details, + ): void { + $shippingPhone = null !== $shipping->getPhoneNumber() ? $this->formatNumber( + $shipping->getPhoneNumber(), + $shipping->getCountryCode(), + ) : null; + $this->loadPhoneNumbers($shippingPhone, $shippingMobilePhone, $shippingLandingPhone); + + $details['shipping'] = [ + 'title' => $this->formatTitle($customer), + 'first_name' => $shipping->getFirstName(), + 'last_name' => $shipping->getLastName(), + 'company_name' => $shipping->getCompany(), + 'email' => $customer->getEmail(), + 'mobile_phone_number' => $shippingMobilePhone, + 'landline_phone_number' => $shippingLandingPhone, + 'address1' => $shipping->getStreet(), + 'address2' => null, + 'postcode' => $shipping->getPostcode(), + 'city' => $shipping->getCity(), + 'state' => $shipping->getProvinceName(), + 'country' => $shipping->getCountryCode(), + 'language' => $this->formatLanguageCode($order->getLocaleCode()), + 'delivery_type' => $deliveryType, + ]; + } + + private function alterPayPlugDetailsForOneClick( + PaymentMethodInterface $paymentMethod, + ArrayObject $details, + ): ArrayObject { + if (!$this->canSaveCardChecker->isAllowed($paymentMethod)) { + return $details; + } + + /** @var string|null $cardId */ + $cardId = $this->requestStack->getSession()->get('payplug_payment_method'); + + if ( + (null === $cardId || self::PAYPLUG_CARD_ID_OTHER === $cardId) && $this->canSaveCardChecker->isAllowed( + $paymentMethod, + ) + ) { + $details['allow_save_card'] = true; + + return $details; + } + + if (null === $cardId) { + return $details; + } + + $card = $this->payplugCardRepository->find($cardId); + + if (!$card instanceof Card) { + return $details; + } + + $details['payment_method'] = $card->getExternalId(); + $details['initiator'] = 'PAYER'; + + return $details; + } + + private function alterPayPlugDetailsForDeferredCapture( + PaymentMethodInterface $paymentMethod, + ArrayObject $details, + ): ArrayObject { + if (!$this->payplugFeatureChecker->isDeferredCaptureEnabled($paymentMethod)) { + return $details; + } + + $details['authorized_amount'] = $details['amount']; + unset($details['amount']); + + return $details; + } + + private function alterOneyDetails(ArrayObject $details): ArrayObject + { + $details['payment_method'] = $this->requestStack->getSession()->get('oney_payment_method', 'oney_x3_with_fees'); + $details['auto_capture'] = true; + $details['authorized_amount'] = $details['amount']; + unset($details['amount']); + + $billing = $details['billing']; + if (null === $billing['company_name']) { + $billing['company_name'] = sprintf('%s %s', $billing['first_name'], $billing['last_name']); + } + $details['billing'] = $billing; + + $shipping = $details['shipping']; + if (null === $shipping['company_name']) { + $shipping['company_name'] = sprintf('%s %s', $shipping['first_name'], $shipping['last_name']); + } + $details['shipping'] = $shipping; + + return $details; + } + + private function getCartContext(OrderInterface $order): array + { + /** @var Shipment $shipment */ + $shipment = $order->getShipments()->current(); + + $expectedDeliveryDate = (new DateTime())->add(new DateInterval('P7D'))->format('Y-m-d'); + $deliveryType = $this->retrieveDeliveryType(); + $data = []; + + foreach ($order->getItems() as $orderItem) { + $data[] = [ + 'delivery_label' => (null !== $shipment->getMethod()) ? $shipment->getMethod()->getName() : 'none', + 'delivery_type' => $deliveryType, + 'expected_delivery_date' => $expectedDeliveryDate, + 'merchant_item_id' => (null !== $orderItem->getVariant()) ? $orderItem->getVariant()->getCode( + ) : 'none', + 'brand' => $orderItem->getProductName(), + 'name' => $orderItem->getProductName() . ' ' . $orderItem->getVariantName(), + 'total_amount' => $orderItem->getTotal(), + 'price' => $orderItem->getUnitPrice(), + 'quantity' => $orderItem->getQuantity(), + ]; + } + + return ['cart' => $data]; + } + + /** + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + private function retrieveDeliveryType(): string + { + // Possible delivery type : [storepickup, networkpickup, travelpickup, carrier, edelivery] + return 'storepickup'; + } + + private function addPaymentMethodFieldToDetails(ArrayObject $details, string $gatewayFactoryName): ArrayObject + { + $paymentMethods = [ + BancontactGatewayFactory::FACTORY_NAME => BancontactGatewayFactory::PAYMENT_METHOD_BANCONTACT, + ApplePayGatewayFactory::FACTORY_NAME => ApplePayGatewayFactory::PAYMENT_METHOD_APPLE_PAY, + AmericanExpressGatewayFactory::FACTORY_NAME => AmericanExpressGatewayFactory::PAYMENT_METHOD_AMERICAN_EXPRESS, + ]; + // match function is only supported by php 8. so can not use it here. + foreach ($paymentMethods as $name => $method) { + if ($gatewayFactoryName !== $name) { + continue; + } + $details['payment_method'] = $method; + } + + return $details; + } +} diff --git a/src/Creator/RefundUnitsCommandCreatorDecorator.php b/src/Creator/RefundUnitsCommandCreatorDecorator.php index cf763283..396ac3ac 100644 --- a/src/Creator/RefundUnitsCommandCreatorDecorator.php +++ b/src/Creator/RefundUnitsCommandCreatorDecorator.php @@ -7,138 +7,101 @@ use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Payment\Repository\PaymentMethodRepositoryInterface; use Sylius\RefundPlugin\Command\RefundUnits; -use Sylius\RefundPlugin\Creator\RefundUnitsCommandCreatorInterface; +use Sylius\RefundPlugin\Converter\Request\RequestToRefundUnitsConverterInterface; +use Sylius\RefundPlugin\Creator\RequestCommandCreatorInterface; use Sylius\RefundPlugin\Exception\InvalidRefundAmount; +use Sylius\RefundPlugin\Model\UnitRefundInterface; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\Translation\TranslatorInterface; use Webmozart\Assert\Assert; -class RefundUnitsCommandCreatorDecorator implements RefundUnitsCommandCreatorInterface +#[AsDecorator('sylius_refund.creator.request_command')] +class RefundUnitsCommandCreatorDecorator implements RequestCommandCreatorInterface { - private const MINIMUM_REFUND_AMOUNT = 0.10; - - /** @var RefundUnitsCommandCreatorInterface */ - private $decorated; - - /** @var PaymentMethodRepositoryInterface */ - private $paymentMethodRepository; - - /** @var OrderRepositoryInterface */ - private $orderRepository; - - /** @var TranslatorInterface */ - private $translator; - - /** @var PayPlugApiClientInterface */ - private $oneyClient; + private const MINIMUM_REFUND_AMOUNT = 10; + private const SUPPORTED_METHODS = [ + PayPlugGatewayFactory::FACTORY_NAME, + OneyGatewayFactory::FACTORY_NAME + ]; public function __construct( - RefundUnitsCommandCreatorInterface $decorated, - PaymentMethodRepositoryInterface $paymentMethodRepository, - OrderRepositoryInterface $orderRepository, - TranslatorInterface $translator, - PayPlugApiClientInterface $oneyClient + #[AutowireDecorated] + private RequestCommandCreatorInterface $decorated, + #[Autowire('@sylius_refund.converter.request_to_refund_units')] + private RequestToRefundUnitsConverterInterface $requestToRefundUnitsConverter, + private PaymentMethodRepositoryInterface $paymentMethodRepository, + private OrderRepositoryInterface $orderRepository, + private TranslatorInterface $translator, + #[Autowire('@payplug_sylius_payplug_plugin.api_client.oney')] + private PayPlugApiClientInterface $oneyClient, ) { - $this->decorated = $decorated; - $this->paymentMethodRepository = $paymentMethodRepository; - $this->orderRepository = $orderRepository; - $this->translator = $translator; - $this->oneyClient = $oneyClient; } - public function fromRequest(Request $request): RefundUnits + /** + * @return RefundUnits + */ + public function fromRequest(Request $request): object { Assert::true($request->attributes->has('orderNumber'), 'Refunded order number not provided'); - - $units = $this->filterEmptyRefundUnits( - $request->request->has('sylius_refund_units') ? $request->request->all()['sylius_refund_units'] : [] - ); - $shipments = $this->filterEmptyRefundUnits( - $request->request->has('sylius_refund_shipments') ? $request->request->all()['sylius_refund_shipments'] : [] - ); - - if (count($units) === 0 && count($shipments) === 0) { - throw InvalidRefundAmount::withValidationConstraint( - $this->translator->trans('sylius_refund.at_least_one_unit_should_be_selected_to_refund') - ); + $units = $this->requestToRefundUnitsConverter->convert($request); + if ([] === $units) { + throw InvalidRefundAmount::withValidationConstraint('sylius_refund.at_least_one_unit_should_be_selected_to_refund'); } - /** @var int $paymentMethodId */ - $paymentMethodId = $request->request->get('sylius_refund_payment_method'); + $paymentMethodId = $request->request->getInt('sylius_refund_payment_method'); + if (0 === $paymentMethodId) { + return $this->decorated->fromRequest($request); // @phpstan-ignore-line + } /** @var PaymentMethodInterface $paymentMethod */ $paymentMethod = $this->paymentMethodRepository->find($paymentMethodId); - - /** @var GatewayConfigInterface $gateway */ $gateway = $paymentMethod->getGatewayConfig(); - - if ($gateway->getFactoryName() !== PayPlugGatewayFactory::FACTORY_NAME && - $gateway->getFactoryName() !== OneyGatewayFactory::FACTORY_NAME) { - return $this->decorated->fromRequest($request); + if (!\in_array($gateway?->getFactoryName(), self::SUPPORTED_METHODS, true)) { + return $this->decorated->fromRequest($request); // @phpstan-ignore-line } - if ($gateway->getFactoryName() === OneyGatewayFactory::FACTORY_NAME) { + if (OneyGatewayFactory::FACTORY_NAME === $gateway->getFactoryName()) { + $orderNumber = $request->attributes->get('orderNumber'); + Assert::string($orderNumber); + /** @var OrderInterface|null $order */ - $order = $this->orderRepository->findOneByNumber($request->get('orderNumber')); + $order = $this->orderRepository->findOneByNumber($orderNumber); Assert::isInstanceOf($order, OrderInterface::class); $this->canOneyRefundBeMade($order); } - $totalRefundRequest = $this->getTotalRefundAmount($units, $shipments); - + $totalRefundRequest = $this->getTotalRefundAmount($units); if ($totalRefundRequest < self::MINIMUM_REFUND_AMOUNT) { - throw InvalidRefundAmount::withValidationConstraint( - $this->translator->trans('payplug_sylius_payplug_plugin.ui.refund_minimum_amount_requirement_not_met') - ); + throw InvalidRefundAmount::withValidationConstraint($this->translator->trans('payplug_sylius_payplug_plugin.ui.refund_minimum_amount_requirement_not_met')); } - return $this->decorated->fromRequest($request); + return $this->decorated->fromRequest($request); // @phpstan-ignore-line } - private function getTotalRefundAmount(array $units, array $shipments): float + /** + * @param array $units + */ + private function getTotalRefundAmount(array $units): int { $total = 0; foreach ($units as $unit) { - $total += $this->getAmount($unit) ?? 0; - } - - foreach ($shipments as $unit) { - $total += $this->getAmount($unit) ?? 0; + $total += $unit->total(); } return $total; } - private function filterEmptyRefundUnits(array $units): array - { - return array_filter($units, function (array $refundUnit): bool { - return - (isset($refundUnit['amount']) && $refundUnit['amount'] !== '') - || isset($refundUnit['full']) - ; - }); - } - - private function getAmount(array $unit): ?float - { - if (isset($unit['full'])) { - return null; - } - - Assert::keyExists($unit, 'amount'); - - return (float) $unit['amount']; - } - private function canOneyRefundBeMade(OrderInterface $order): void { $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); @@ -148,13 +111,13 @@ private function canOneyRefundBeMade(OrderInterface $order): void $now = new \DateTime(); - if ($now->getTimestamp() < $data->refundable_until && - $now->getTimestamp() > $data->refundable_after) { + if ( + $now->getTimestamp() < $data->refundable_until && + $now->getTimestamp() > $data->refundable_after + ) { return; } - throw InvalidRefundAmount::withValidationConstraint( - $this->translator->trans('payplug_sylius_payplug_plugin.ui.oney_transaction_less_than_forty_eight_hours') - ); + throw InvalidRefundAmount::withValidationConstraint($this->translator->trans('payplug_sylius_payplug_plugin.ui.oney_transaction_less_than_forty_eight_hours')); } } diff --git a/src/DependencyInjection/PayPlugSyliusPayPlugExtension.php b/src/DependencyInjection/PayPlugSyliusPayPlugExtension.php index 29d281db..d22ef359 100644 --- a/src/DependencyInjection/PayPlugSyliusPayPlugExtension.php +++ b/src/DependencyInjection/PayPlugSyliusPayPlugExtension.php @@ -10,6 +10,7 @@ use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; +use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; final class PayPlugSyliusPayPlugExtension extends Extension implements PrependExtensionInterface { @@ -18,33 +19,43 @@ final class PayPlugSyliusPayPlugExtension extends Extension implements PrependEx /** * @inheritdoc */ - public function load(array $config, ContainerBuilder $container): void + public function load(array $configs, ContainerBuilder $container): void { - $loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__) . '/Resources/config')); + $ymlloader = new YamlFileLoader($container, new FileLocator(dirname(__DIR__, 2) . '/config')); + $xmlloader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__, 2) . '/config/services')); - $loader->load('services.xml'); + $ymlloader->load('services.yaml'); + $xmlloader->load('client.xml'); } public function prepend(ContainerBuilder $container): void + { + $this->prependTwigExtension($container); + $this->prependDoctrineMigrations($container); + $this->prependMonologExtension($container); + } + + private function prependTwigExtension(ContainerBuilder $container): void { if (!$container->hasExtension('twig')) { return; } - $viewsPath = dirname(__DIR__) . '/Resources/views/'; - // This add our override in twig paths with correct namespace. No need for final user to copy it - $paths = [ - $viewsPath . 'SyliusShopBundle' => 'SyliusShop', - $viewsPath . 'SyliusAdminBundle' => 'SyliusAdmin', - $viewsPath . 'SyliusUiBundle' => 'SyliusUi', - ]; - $container->prependExtensionConfig('twig', [ - 'paths' => $paths, - 'form_themes' => ['@PayPlugSyliusPayPlugPlugin/form/form_gateway_config_row.html.twig'], + 'form_themes' => [ + '@PayPlugSyliusPayPlugPlugin/form/form_gateway_config_row.html.twig', + '@PayPlugSyliusPayPlugPlugin/form/sylius_checkout_select_payment_row.html.twig', + ], ]); + } - $this->prependDoctrineMigrations($container); + public function prependMonologExtension(ContainerBuilder $container): void + { + if ($container->hasExtension('monolog')) { + $container->prependExtensionConfig('monolog', [ + 'channels' => ['payplug'], + ]); + } } protected function getMigrationsNamespace(): string @@ -54,7 +65,7 @@ protected function getMigrationsNamespace(): string protected function getMigrationsDirectory(): string { - return '@PayPlugSyliusPayPlugPlugin/Migrations'; + return '@PayPlugSyliusPayPlugPlugin/migrations'; } protected function getNamespacesOfMigrationsExecutedBefore(): array diff --git a/src/Entity/Card.php b/src/Entity/Card.php index eea58b1f..147bdaeb 100644 --- a/src/Entity/Card.php +++ b/src/Entity/Card.php @@ -4,79 +4,111 @@ namespace PayPlug\SyliusPayPlugPlugin\Entity; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; +use Sylius\Component\Customer\Model\CustomerInterface; use Sylius\Component\Resource\Model\ResourceInterface; /** * @ORM\Entity() + * * @ORM\Table("payplug_cards") */ +#[ORM\Entity] +#[ORM\Table(name: 'payplug_cards')] class Card implements ResourceInterface { /** * @var int + * * @ORM\Id() + * * @ORM\GeneratedValue() + * * @ORM\Column(type="integer") */ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: Types::INTEGER)] private $id; /** * @var string + * * @ORM\Column(name="external_id", type="string", nullable=false) */ + #[ORM\Column(name: 'external_id', type: Types::STRING, nullable: false)] private $externalId; /** * @var string + * * @ORM\Column(name="last4", type="string") */ + #[ORM\Column(name: 'last4', type: Types::STRING)] private $last4; /** * @var string + * * @ORM\Column(name="country", type="string") */ + #[ORM\Column(name: 'country', type: Types::STRING)] private $countryCode; /** * @var int + * * @ORM\Column(name="exp_month", type="integer") */ + #[ORM\Column(name: 'exp_month', type: Types::INTEGER)] private $expirationMonth; /** * @var int + * * @ORM\Column(name="exp_year", type="integer") */ + #[ORM\Column(name: 'exp_year', type: Types::INTEGER)] private $expirationYear; /** * @var string + * * @ORM\Column(name="brand", type="string") */ + #[ORM\Column(name: 'brand', type: Types::STRING)] private $brand; /** * @var bool + * * @ORM\Column(name="is_live", type="boolean") */ + #[ORM\Column(name: 'is_live', type: Types::BOOLEAN)] private $isLive; /** * @var CustomerInterface + * * @ORM\ManyToOne(targetEntity=\Sylius\Component\Customer\Model\CustomerInterface::class, inversedBy="cards") + * * @ORM\JoinColumn(nullable=false) */ + #[ORM\ManyToOne(targetEntity: CustomerInterface::class, inversedBy: 'cards')] + #[ORM\JoinColumn(nullable: false)] private $customer; /** * @var \Sylius\Component\Core\Model\PaymentMethodInterface + * * @ORM\ManyToOne(targetEntity=\Sylius\Component\Core\Model\PaymentMethodInterface::class, inversedBy="cards") + * * @ORM\JoinColumn(nullable=false) */ + #[ORM\ManyToOne(targetEntity: PaymentMethodInterface::class, inversedBy: 'cards')] + #[ORM\JoinColumn(nullable: false)] private $paymentMethod; public function getId(): int diff --git a/src/Entity/CardsOwnerInterface.php b/src/Entity/CardsOwnerInterface.php new file mode 100644 index 00000000..996e1975 --- /dev/null +++ b/src/Entity/CardsOwnerInterface.php @@ -0,0 +1,17 @@ + + */ + public function getCards(): Collection; + + public function addCard(Card $card): self; +} diff --git a/src/Entity/RefundHistory.php b/src/Entity/RefundHistory.php index 1219f7f4..6928ee08 100644 --- a/src/Entity/RefundHistory.php +++ b/src/Entity/RefundHistory.php @@ -7,6 +7,7 @@ use DateTime; use DateTimeImmutable; use DateTimeInterface; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Resource\Model\ResourceInterface; @@ -15,54 +16,79 @@ /** * @ORM\Entity() + * * @ORM\Table("payplug_refund_history") */ +#[ORM\Entity] +#[ORM\Table(name: 'payplug_refund_history')] class RefundHistory implements ResourceInterface { /** * @var int + * * @ORM\Id() + * * @ORM\GeneratedValue() + * * @ORM\Column(type="integer") */ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: Types::INTEGER)] private $id; /** * @var RefundPayment|null + * * @ORM\OneToOne(targetEntity="Sylius\RefundPlugin\Entity\RefundPayment") + * * @ORM\JoinColumn(name="refund_payment_id", nullable=true) */ + #[ORM\OneToOne(targetEntity: RefundPayment::class)] + #[ORM\JoinColumn(name: 'refund_payment_id', nullable: true)] private $refundPayment; /** * @var string|null + * * @ORM\Column(type="string", nullable=true) */ + #[ORM\Column(type: Types::STRING, nullable: true)] private $externalId; /** * @var PaymentInterface|null - * @ORM\ManyToOne(targetEntity="\Sylius\Component\Core\Model\Payment") + * + * @ORM\ManyToOne(targetEntity="\Sylius\Component\Core\Model\PaymentInterface", inversedBy="refundHistories") + * * @ORM\JoinColumn(name="payment_id", referencedColumnName="id", nullable=true, onDelete="SET NULL") */ + #[ORM\ManyToOne(targetEntity: PaymentInterface::class, inversedBy: 'refundHistories')] + #[ORM\JoinColumn(name: 'payment_id', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')] private $payment; /** * @var int + * * @ORM\Column(type="integer", nullable=true) */ + #[ORM\Column(type: Types::INTEGER, nullable: true)] private $value; /** * @var bool + * * @ORM\Column(type="boolean") */ + #[ORM\Column(type: Types::BOOLEAN)] private $processed = false; /** * @var DateTimeInterface + * * @ORM\Column(type="datetime") */ + #[ORM\Column(type: Types::DATETIME_MUTABLE)] private $createdAt; public function __construct() diff --git a/src/Entity/Traits/CustomerTrait.php b/src/Entity/Traits/CustomerTrait.php index 669f24d6..7d3ae3dd 100644 --- a/src/Entity/Traits/CustomerTrait.php +++ b/src/Entity/Traits/CustomerTrait.php @@ -5,6 +5,7 @@ namespace PayPlug\SyliusPayPlugPlugin\Entity\Traits; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Entity\Card; @@ -12,23 +13,23 @@ trait CustomerTrait { /** * @ORM\OneToMany(targetEntity=Card::class, mappedBy="customer", orphanRemoval=true) + * * @ORM\OrderBy({"id" = "DESC"}) */ + #[ORM\OneToMany(targetEntity: Card::class, mappedBy: 'customer', orphanRemoval: true)] + #[ORM\OrderBy(['id' => 'DESC'])] protected $cards; /** - * @return Collection|Card[] + * @return Collection */ public function getCards(): Collection { return $this->cards->filter(function (Card $card): bool { - $secretKeyPrefix = \substr($card->getPaymentMethod()->getGatewayConfig()->getConfig()['secretKey'], 0, 7); - if (($card->isLive() && $secretKeyPrefix === PayPlugApiClientInterface::LIVE_KEY_PREFIX) || - (!$card->isLive() && $secretKeyPrefix === PayPlugApiClientInterface::TEST_KEY_PREFIX)) { - return true; - } + $isLivePaymentMethod = $card->getPaymentMethod()->getGatewayConfig()?->getConfig()['live'] ?? false; - return false; + return ($card->isLive() && true === $isLivePaymentMethod) || + (!$card->isLive() && false === $isLivePaymentMethod); }); } diff --git a/src/Entity/Traits/PaymentMethodTrait.php b/src/Entity/Traits/PaymentMethodTrait.php index 893a106d..a5a6c862 100644 --- a/src/Entity/Traits/PaymentMethodTrait.php +++ b/src/Entity/Traits/PaymentMethodTrait.php @@ -5,12 +5,14 @@ namespace PayPlug\SyliusPayPlugPlugin\Entity\Traits; use Doctrine\Common\Collections\Collection; +use Doctrine\ORM\Mapping as ORM; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Entity\Card; trait PaymentMethodTrait { /** @ORM\OneToMany(targetEntity=Card::class, mappedBy="paymentMethod", orphanRemoval=true) */ + #[ORM\OneToMany(targetEntity: Card::class, mappedBy: 'paymentMethod', orphanRemoval: true)] protected $cards; /** @@ -19,13 +21,10 @@ trait PaymentMethodTrait public function getCards(): Collection { return $this->cards->filter(function (Card $card): bool { - $secretKeyPrefix = \substr($card->getPaymentMethod()->getGatewayConfig()->getConfig()['secretKey'], 0, 7); - if (($card->isLive() && $secretKeyPrefix === PayPlugApiClientInterface::LIVE_KEY_PREFIX) || - (!$card->isLive() && $secretKeyPrefix === PayPlugApiClientInterface::TEST_KEY_PREFIX)) { - return true; - } + $isLivePaymentMethod = $card->getPaymentMethod()->getGatewayConfig()?->getConfig()['live'] ?? false; - return false; + return ($card->isLive() && true === $isLivePaymentMethod) || + (!$card->isLive() && false === $isLivePaymentMethod); }); } diff --git a/src/Entity/Traits/PaymentTrait.php b/src/Entity/Traits/PaymentTrait.php new file mode 100644 index 00000000..16bd7acb --- /dev/null +++ b/src/Entity/Traits/PaymentTrait.php @@ -0,0 +1,15 @@ +setAttribute('type', 'link') ->setLabel('payplug_sylius_payplug_plugin.ui.account.saved_cards.title') - ->setLabelAttribute('icon', 'credit card') + ->setLabelAttribute('icon', 'tabler:credit-card') ; } } diff --git a/src/EventListener/PostSavePaymentMethodEventListener.php b/src/EventListener/PostSavePaymentMethodEventListener.php new file mode 100644 index 00000000..59657705 --- /dev/null +++ b/src/EventListener/PostSavePaymentMethodEventListener.php @@ -0,0 +1,109 @@ +getSubject(); + if (!$paymentMethod instanceof PaymentMethodInterface) { + return; + } + + if (false === $this->isPayplugPaymentMethod($paymentMethod)) { + return; + } + + $this->startOAuth($paymentMethod, $event); + } + + public function onUpdate(ResourceControllerEvent $event): void + { + $paymentMethod = $event->getSubject(); + if (!$paymentMethod instanceof PaymentMethodInterface) { + return; + } + + if (false === $this->isPayplugPaymentMethod($paymentMethod)) { + return; + } + + $request = $this->requestStack->getCurrentRequest(); + if (null === $request) { + return; + } + + $isRenewal = $request->request->all('sylius_admin_payment_method')['gatewayConfig']['config']['renew_oauth'] ?? false; // @phpstan-ignore-line + $isRenewal = \filter_var($isRenewal, \FILTER_VALIDATE_BOOLEAN); + if (true !== $isRenewal) { + // No need to renew the oauth token, let's validate the payment method with already existing config + $this->paymentMethodValidator->process($paymentMethod); + + return; + } + + $this->startOAuth($paymentMethod, $event); + } + + private function startOAuth(PaymentMethodInterface $paymentMethod, ResourceControllerEvent $event): void + { + $request = $this->requestStack->getCurrentRequest(); + if (null === $request) { + // Should never happen + return; + } + try { + $request->getSession()->set('payplug_sylius_oauth_payment_method_id', $paymentMethod->getId()); + $setupRedirection = $this->router->generate('payplug_sylius_admin_auth_setup_redirection', referenceType: RouterInterface::ABSOLUTE_URL); + $oauthCallback = $this->router->generate('payplug_sylius_admin_auth_oauth_callback', referenceType: RouterInterface::ABSOLUTE_URL); + + /** + * @var string $payplugRedirectUrl + * @phpstan-ignore-next-line -- Error of return type in Payplug SDK + */ + $payplugRedirectUrl = Authentication::getRegisterUrl($setupRedirection, $oauthCallback); + $event->setResponse(new RedirectResponse($payplugRedirectUrl)); + } catch (\Throwable $e) { + $this->logger->critical('Error while starting Payplug OAuth process', ['message' => $e->getMessage(), 'exception' => $e]); + $request->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.admin.oauth_setup_error'); + } + } + + private function isPayplugPaymentMethod(PaymentMethodInterface $paymentMethod): bool + { + $gateway = $paymentMethod->getGatewayConfig(); + if (null === $gateway) { + return false; + } + $factoryName = $gateway->getFactoryName(); + if (null === $factoryName) { + return false; + } + + return \str_contains($factoryName, 'payplug'); + } +} diff --git a/src/EventSubscriber/DisplayOneyGatewayFormEventSubscriber.php b/src/EventSubscriber/DisplayOneyGatewayFormEventSubscriber.php deleted file mode 100644 index 0e275502..00000000 --- a/src/EventSubscriber/DisplayOneyGatewayFormEventSubscriber.php +++ /dev/null @@ -1,69 +0,0 @@ -flashBag = $flashBag; - $this->paymentMethodRepository = $paymentMethodRepository; - $this->oneyChecker = $oneyChecker; - } - - public static function getSubscribedEvents(): array - { - return [ - 'kernel.controller' => 'handle', - ]; - } - - public function handle(KernelEvent $event): void - { - if ($event->getRequest()->attributes->get('_route') !== 'sylius_admin_payment_method_update') { - return; - } - - /** @var \Sylius\Component\Core\Model\PaymentMethod|null $subject */ - $subject = $this->paymentMethodRepository->find($event->getRequest()->attributes->get('id')); - if (null === $subject) { - return; - } - - if (false === $subject->isEnabled() || - null === $subject->getGatewayConfig() || - OneyGatewayFactory::FACTORY_NAME !== $subject->getGatewayConfig()->getFactoryName()) { - return; - } - - if (true === $this->oneyChecker->isEnabled()) { - // Oney still enabled, do nothing - return; - } - - $this->flashBag->add('error', 'payplug_sylius_payplug_plugin.error.oney_not_enabled'); - $subject->disable(); - $this->paymentMethodRepository->add($subject); - } -} diff --git a/src/EventSubscriber/PostPaymentSelectEventSubscriber.php b/src/EventSubscriber/PostPaymentSelectEventSubscriber.php new file mode 100644 index 00000000..9991e0b3 --- /dev/null +++ b/src/EventSubscriber/PostPaymentSelectEventSubscriber.php @@ -0,0 +1,139 @@ + 'alterRequestConfigurationForIntegratedPayment', + 'sylius.order.post_payment' => 'handle', + 'sylius.order.post_update' => 'handle', + ]; + } + + public function alterRequestConfigurationForIntegratedPayment(RequestEvent $event): void + { + $request = $event->getRequest(); + if (!$this->hasToken($request) || self::CHECKOUT_ROUTE !== $request->attributes->get('_route')) { + return; + } + if (!$request->attributes->has('_sylius')) { + return; + } + + $syliusRequestConfig = $request->attributes->get('_sylius'); + if (!\is_array($syliusRequestConfig)) { + return; + } + + $syliusRequestConfig['redirect'] = [ + 'route' => 'sylius_shop_order_pay', + 'parameters' => ['tokenValue' => 'resource.tokenValue'], + ]; + + $request->attributes->set('_sylius', $syliusRequestConfig); + } + + public function handle(ResourceControllerEvent $resourceControllerEvent): void + { + $request = $this->requestStack->getCurrentRequest(); + if (!$request instanceof \Symfony\Component\HttpFoundation\Request) { + return; + } + + if (!\in_array($request->attributes->get('_route'), [self::CHECKOUT_ROUTE, self::UPDATE_ORDER_PAYMENT_ROUTE], true)) { + return; + } + + /** @var \Sylius\Component\Core\Model\OrderInterface $order */ + $order = $resourceControllerEvent->getSubject(); + $lastPayment = $order->getLastPayment(); + if (null === $lastPayment) { + return; + } + + if (!$this->hasToken($request)) { + return; + } + $this->handleToken($resourceControllerEvent, $request, $lastPayment); + } + + private function handleToken( + ResourceControllerEvent $resourceControllerEvent, + Request $request, + PaymentInterface $lastPayment, + ): void { + $token = $this->getToken($request); + + $lastPayment->setDetails(\array_merge( + $lastPayment->getDetails(), + [ + 'payment_id' => $token, + 'status' => PaymentInterface::STATE_PROCESSING, + ], + )); + + $resource = $resourceControllerEvent->getSubject(); + Assert::isInstanceOf($resource, ResourceInterface::class); + + $this->applyToComplete($lastPayment->getOrder() ?? throw new \LogicException('Order not found for payment')); + } + + private function hasToken(Request $request): bool + { + if (!$request->request->has(self::TOKEN_FIELD)) { + return false; + } + + $token = $this->getToken($request); + + return '' !== $token; + } + + private function getToken(Request $request): string + { + $token = $request->request->get(self::TOKEN_FIELD); + Assert::string($token); + + return $token; + } + + private function applyToComplete(OrderInterface $order): void + { + if ($this->stateMachine->can($order, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_COMPLETE)) { + $this->stateMachine->apply($order, OrderCheckoutTransitions::GRAPH, OrderCheckoutTransitions::TRANSITION_COMPLETE); + } + + $this->entityManager->flush(); + } +} diff --git a/src/Exception/GatewayConfigurationException.php b/src/Exception/GatewayConfigurationException.php new file mode 100644 index 00000000..69f21e43 --- /dev/null +++ b/src/Exception/GatewayConfigurationException.php @@ -0,0 +1,9 @@ +session = $session; - $this->translator = $translator; - $this->orderChecker = $orderChecker; } /** * @inheritdoc */ - public function buildForm(FormBuilderInterface $builder, array $options): void - { + public function buildForm( + FormBuilderInterface $builder, + array $options, + ): void { $builder ->add('oney_payment_choice', ChoiceType::class, [ 'mapped' => false, - 'choices' => [ - '3x' => 'oney_x3_with_fees', - '4x' => 'oney_x4_with_fees', - ], + 'block_prefix' => 'oney_payment_choice', + 'choices' => $this->oneySupportedPaymentChoiceProvider->getSupportedPaymentChoices(true), ]) ->add('payplug_card_choice', TextType::class, [ 'mapped' => false, @@ -60,12 +50,11 @@ public function buildForm(FormBuilderInterface $builder, array $options): void ]) ->addEventListener(FormEvents::PRE_SET_DATA, function (): void { // Remove on preset data, it'll be readded if needed in post_submit - $this->session->remove('oney_has_error'); - $this->session->remove('payplug_payment_method'); + $this->requestStack->getSession()->remove('payplug_payment_method'); }) ->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event): void { - if ($this->session->has('oney_payment_method')) { - $event->getForm()->get('oney_payment_choice')->setData($this->session->get('oney_payment_method')); + if ($this->requestStack->getSession()->has('oney_payment_method')) { + $event->getForm()->get('oney_payment_choice')->setData($this->requestStack->getSession()->get('oney_payment_method')); } }) ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event): void { @@ -76,20 +65,24 @@ public function buildForm(FormBuilderInterface $builder, array $options): void return; } - if (PayPlugGatewayFactory::FACTORY_NAME === $paymentMethod->getGatewayConfig()->getFactoryName() && - (false === $event->getForm()->has('payplug_card_choice') || null === $event->getForm()->get('payplug_card_choice')->getData())) { + if ( + PayPlugGatewayFactory::FACTORY_NAME === $paymentMethod->getGatewayConfig()->getFactoryName() && + (false === $event->getForm()->has('payplug_card_choice') || null === $event->getForm()->get('payplug_card_choice')->getData()) + ) { return; } if (PayPlugGatewayFactory::FACTORY_NAME === $paymentMethod->getGatewayConfig()->getFactoryName() && null !== $event->getForm()->get('payplug_card_choice')->getData()) { $payplugCardId = $event->getForm()->get('payplug_card_choice')->getData(); - $this->session->set('payplug_payment_method', $payplugCardId); + $this->requestStack->getSession()->set('payplug_payment_method', $payplugCardId); return; } - if (OneyGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName() || - false === $event->getForm()->has('oney_payment_choice')) { + if ( + OneyGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName() || + false === $event->getForm()->has('oney_payment_choice') + ) { return; } @@ -103,22 +96,22 @@ public function buildForm(FormBuilderInterface $builder, array $options): void $errors = []; if (!$this->orderChecker->isOrderInfoCorrect($order)) { $errors[] = new FormError( - $this->translator->trans('payplug_sylius_payplug_plugin.form.oney_error') + $this->translator->trans('payplug_sylius_payplug_plugin.form.oney_error'), ); } // Possible other checks here - if (\count($errors) > 0) { + if ($errors !== []) { \array_walk($errors, static function (FormError $error) use ($event): void { - $event->getForm()->addError($error); + $event->getForm()->get('method')->addError($error); }); - $this->session->set('oney_has_error', true); + $this->requestStack->getSession()->getFlashBag()->add('oney_has_error', true); // @phpstan-ignore-line return; } $data = $event->getForm()->get('oney_payment_choice')->getData(); - $this->session->set('oney_payment_method', $data); + $this->requestStack->getSession()->set('oney_payment_method', $data); }) ; } diff --git a/src/Gateway/AbstractGatewayFactory.php b/src/Gateway/AbstractGatewayFactory.php index ed40c9b7..8d7f4d11 100644 --- a/src/Gateway/AbstractGatewayFactory.php +++ b/src/Gateway/AbstractGatewayFactory.php @@ -25,7 +25,7 @@ protected function populateConfig(ArrayObject $config): void 'payum.http_client' => '@payplug_sylius_payplug_plugin.api_client.payplug', ]); - if (false !== (bool) $config['payum.api']) { + if ((bool) $config['payum.api']) { return; } diff --git a/src/Gateway/AmericanExpressGatewayFactory.php b/src/Gateway/AmericanExpressGatewayFactory.php new file mode 100644 index 00000000..4e20cfe8 --- /dev/null +++ b/src/Gateway/AmericanExpressGatewayFactory.php @@ -0,0 +1,21 @@ + [ + 'min_amount' => 100, + 'max_amount' => 2000000, + ], + ]; +} diff --git a/src/Gateway/ApplePayGatewayFactory.php b/src/Gateway/ApplePayGatewayFactory.php new file mode 100644 index 00000000..8ee80585 --- /dev/null +++ b/src/Gateway/ApplePayGatewayFactory.php @@ -0,0 +1,21 @@ + [ + 'min_amount' => 100, + 'max_amount' => 2000000, + ], + ]; +} diff --git a/src/Gateway/BancontactGatewayFactory.php b/src/Gateway/BancontactGatewayFactory.php new file mode 100644 index 00000000..287673c2 --- /dev/null +++ b/src/Gateway/BancontactGatewayFactory.php @@ -0,0 +1,21 @@ + [ + 'min_amount' => 100, + 'max_amount' => 2000000, + ], + ]; +} diff --git a/src/Gateway/Form/Extension/OneyGatewayConfigurationTypeExtension.php b/src/Gateway/Form/Extension/OneyGatewayConfigurationTypeExtension.php new file mode 100644 index 00000000..31bd1886 --- /dev/null +++ b/src/Gateway/Form/Extension/OneyGatewayConfigurationTypeExtension.php @@ -0,0 +1,42 @@ +add(OneyGatewayFactory::FEES_FOR, ChoiceType::class, [ + 'label' => 'payplug_sylius_payplug_plugin.ui.oney_gateway_config.fees_for.title', + 'choices' => [ + 'payplug_sylius_payplug_plugin.ui.oney_gateway_config.fees_for.client' => 'client', + 'payplug_sylius_payplug_plugin.ui.oney_gateway_config.fees_for.merchant' => 'merchant', + ], + 'expanded' => true, + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + 'constraints' => [ + new NotBlank([]), + ], + ]) + ; + } + + public static function getExtendedTypes(): iterable + { + return [OneyGatewayConfigurationType::class]; + } +} diff --git a/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php b/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php new file mode 100644 index 00000000..a6c47a2a --- /dev/null +++ b/src/Gateway/Form/Extension/PayPlugGatewayConfigurationTypeExtension.php @@ -0,0 +1,62 @@ +add(PayPlugGatewayFactory::ONE_CLICK, CheckboxType::class, [ + 'block_name' => 'payplug_checkbox', + 'label' => 'payplug_sylius_payplug_plugin.form.one_click_enable', + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + 'help' => 'payplug_sylius_payplug_plugin.form.one_click_help', + 'help_html' => true, + 'required' => false, + ]) + ->add(PayPlugGatewayFactory::INTEGRATED_PAYMENT, CheckboxType::class, [ + 'block_name' => 'payplug_checkbox', + 'label' => 'payplug_sylius_payplug_plugin.form.integrated_payment_enable', + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + 'required' => false, + ]) + ->add(PayPlugGatewayFactory::DEFERRED_CAPTURE, CheckboxType::class, [ + 'block_name' => 'payplug_checkbox', + 'label' => 'payplug_sylius_payplug_plugin.form.deferred_capture_enable', + 'validation_groups' => AbstractGatewayConfigurationType::VALIDATION_GROUPS, + 'help' => 'payplug_sylius_payplug_plugin.form.deferred_capture_help', + 'help_html' => true, + 'required' => false, + ]) + ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { + $data = $event->getData(); + // phpstan check + if (!is_array($data)) { + return; + } + $data['payum.http_client'] = '@payplug_sylius_payplug_plugin.api_client.payplug'; + $event->setData($data); + }) + ; + } + + public static function getExtendedTypes(): iterable + { + return [PayPlugGatewayConfigurationType::class]; + } +} diff --git a/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php b/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php index d2d31a35..da325b82 100644 --- a/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php +++ b/src/Gateway/Form/Type/AbstractGatewayConfigurationType.php @@ -4,46 +4,104 @@ namespace PayPlug\SyliusPayPlugPlugin\Gateway\Form\Type; +use Doctrine\Common\Collections\Collection; +use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface; +use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormError; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Contracts\Translation\TranslatorInterface; class AbstractGatewayConfigurationType extends AbstractType { - /** @var TranslatorInterface */ - protected $translator; + public const VALIDATION_GROUPS = ['Default', 'sylius']; - /** @var FlashBagInterface */ - protected $flashBag; + protected string $gatewayFactoryTitle = ''; + protected string $gatewayFactoryName = ''; - /** @var RepositoryInterface */ - private $gatewayConfigRepository; + protected string $gatewayBaseCurrencyCode = PayPlugGatewayFactory::BASE_CURRENCY_CODE; public function __construct( - TranslatorInterface $translator, - FlashBagInterface $flashBag, - RepositoryInterface $gatewayConfigRepository + protected TranslatorInterface $translator, + private RepositoryInterface $gatewayConfigRepository, + protected RequestStack $requestStack, ) { - $this->translator = $translator; - $this->flashBag = $flashBag; - $this->gatewayConfigRepository = $gatewayConfigRepository; } - protected function canBeCreated(string $factoryName): bool + /** + * @inheritdoc + */ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('live', CheckboxType::class, [ + 'block_name' => 'payplug_checkbox', + 'label' => 'payplug_sylius_payplug_plugin.ui.live', + 'help' => 'payplug_sylius_payplug_plugin.ui.live_help', + 'help_html' => true, + 'required' => false, + ]) + ->add('renew_oauth', CheckboxType::class, [ + 'label' => 'payplug_sylius_payplug_plugin.ui.renew_oauth', + 'help' => 'payplug_sylius_payplug_plugin.ui.renew_oauth_help', + 'help_html' => true, + 'mapped' => false, + 'required' => false, + ]) + ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { + $this->checkCreationRequirements( + $this->gatewayFactoryTitle, + $this->gatewayFactoryName, + $event->getForm(), + ); + + /** @phpstan-ignore-next-line */ + $formChannels = $event->getForm()->getParent()->getParent()->get('channels'); + $dataFormChannels = $formChannels->getData(); + if (!$dataFormChannels instanceof Collection) { + return; + } + /** @var ChannelInterface $dataFormChannel */ + foreach ($dataFormChannels as $key => $dataFormChannel) { + $baseCurrency = $dataFormChannel->getBaseCurrency(); + if (null === $baseCurrency) { + continue; + } + $baseCurrencyCode = $baseCurrency->getCode(); + if ($this->gatewayBaseCurrencyCode !== $baseCurrencyCode) { + $message = $this->translator->trans( + 'payplug_sylius_payplug_plugin.form.base_currency_not_euro', + [ + '#channel_code#' => $dataFormChannel->getCode(), + '#payment_method#' => $this->gatewayFactoryTitle, + ], + ); + $formChannels->get((string) $key)->addError(new FormError($message)); + $this->requestStack->getSession()->getFlashBag()->add('error', $message); + } + } + }) + ; + } + + private function canBeCreated(string $factoryName): bool { $alreadyExists = $this->gatewayConfigRepository->findOneBy(['factoryName' => $factoryName]); return !$alreadyExists instanceof GatewayConfigInterface; } - protected function checkCreationRequirements( + private function checkCreationRequirements( string $factoryTitle, string $factoryName, - FormInterface $form + FormInterface $form, ): void { /** @phpstan-ignore-next-line */ $paymentMethod = $form->getParent()->getParent()->getData(); @@ -57,7 +115,7 @@ protected function checkCreationRequirements( } $message = $this->translator->trans('payplug_sylius_payplug_plugin.form.only_one_gateway_allowed', ['%gateway_title%' => $factoryTitle]); - /** @phpstan-ignore-next-line */ + /* @phpstan-ignore-next-line */ $form->getParent()->getParent()->get('enabled')->addError(new FormError($message)); } } diff --git a/src/Gateway/Form/Type/AmericanExpressGatewayConfigurationType.php b/src/Gateway/Form/Type/AmericanExpressGatewayConfigurationType.php new file mode 100644 index 00000000..4387942b --- /dev/null +++ b/src/Gateway/Form/Type/AmericanExpressGatewayConfigurationType.php @@ -0,0 +1,25 @@ + 'payplug_american_express', + 'label' => 'payplug_sylius_payplug_plugin.ui.american_express_gateway_label', + 'priority' => 70, + ], +)] +final class AmericanExpressGatewayConfigurationType extends AbstractGatewayConfigurationType +{ + protected string $gatewayFactoryTitle = AmericanExpressGatewayFactory::FACTORY_TITLE; + + protected string $gatewayFactoryName = AmericanExpressGatewayFactory::FACTORY_NAME; + + protected string $gatewayBaseCurrencyCode = AmericanExpressGatewayFactory::BASE_CURRENCY_CODE; +} diff --git a/src/Gateway/Form/Type/ApplePayGatewayConfigurationType.php b/src/Gateway/Form/Type/ApplePayGatewayConfigurationType.php new file mode 100644 index 00000000..1f3da3ec --- /dev/null +++ b/src/Gateway/Form/Type/ApplePayGatewayConfigurationType.php @@ -0,0 +1,25 @@ + 'payplug_apple_pay', + 'label' => 'payplug_sylius_payplug_plugin.ui.apple_pay_gateway_label', + 'priority' => 70, + ], +)] +final class ApplePayGatewayConfigurationType extends AbstractGatewayConfigurationType +{ + protected string $gatewayFactoryTitle = ApplePayGatewayFactory::FACTORY_TITLE; + + protected string $gatewayFactoryName = ApplePayGatewayFactory::FACTORY_NAME; + + protected string $gatewayBaseCurrencyCode = ApplePayGatewayFactory::BASE_CURRENCY_CODE; +} diff --git a/src/Gateway/Form/Type/BancontactGatewayConfigurationType.php b/src/Gateway/Form/Type/BancontactGatewayConfigurationType.php new file mode 100644 index 00000000..25eac35b --- /dev/null +++ b/src/Gateway/Form/Type/BancontactGatewayConfigurationType.php @@ -0,0 +1,25 @@ + 'payplug_bancontact', + 'label' => 'payplug_sylius_payplug_plugin.ui.bancontact_gateway_label', + 'priority' => 80, + ], +)] +final class BancontactGatewayConfigurationType extends AbstractGatewayConfigurationType +{ + protected string $gatewayFactoryTitle = BancontactGatewayFactory::FACTORY_TITLE; + + protected string $gatewayFactoryName = BancontactGatewayFactory::FACTORY_NAME; + + protected string $gatewayBaseCurrencyCode = BancontactGatewayFactory::BASE_CURRENCY_CODE; +} diff --git a/src/Gateway/Form/Type/OneyGatewayConfigurationType.php b/src/Gateway/Form/Type/OneyGatewayConfigurationType.php index 6eaa2aa7..fd548251 100644 --- a/src/Gateway/Form/Type/OneyGatewayConfigurationType.php +++ b/src/Gateway/Form/Type/OneyGatewayConfigurationType.php @@ -5,69 +5,21 @@ namespace PayPlug\SyliusPayPlugPlugin\Gateway\Form\Type; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; -use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsOneyEnabled; -use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsPayPlugSecretKeyValid; -use Sylius\Component\Core\Model\ChannelInterface; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormError; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +#[AutoconfigureTag( + 'sylius.gateway_configuration_type', + [ + 'type' => 'payplug_oney', + 'label' => 'payplug_sylius_payplug_plugin.ui.oney_gateway_label', + 'priority' => 90, + ], +)] final class OneyGatewayConfigurationType extends AbstractGatewayConfigurationType { - /** - * @inheritdoc - */ - public function buildForm(FormBuilderInterface $builder, array $options): void - { - $validationGroups = ['Default', 'sylius']; + protected string $gatewayFactoryTitle = OneyGatewayFactory::FACTORY_TITLE; - $builder - ->add('secretKey', TextType::class, [ - 'label' => 'payplug_sylius_payplug_plugin.ui.secret_key', - 'validation_groups' => $validationGroups, - 'constraints' => [ - new NotBlank([ - 'message' => 'payplug_sylius_payplug_plugin.secret_key.not_blank', - ]), - new IsPayPlugSecretKeyValid(), - new IsOneyEnabled(), - ], - 'help' => $this->translator->trans('payplug_sylius_payplug_plugin.ui.retrieve_secret_key_in_api_configuration_portal'), - 'help_html' => true, - ]) - ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { - $this->checkCreationRequirements( - OneyGatewayFactory::FACTORY_TITLE, - OneyGatewayFactory::FACTORY_NAME, - $event->getForm() - ); + protected string $gatewayFactoryName = OneyGatewayFactory::FACTORY_NAME; - /** @phpstan-ignore-next-line */ - $formChannels = $event->getForm()->getParent()->getParent()->get('channels'); - $dataFormChannels = $formChannels->getData(); - /** @var ChannelInterface $dataFormChannel */ - foreach ($dataFormChannels as $key => $dataFormChannel) { - $baseCurrency = $dataFormChannel->getBaseCurrency(); - if ($baseCurrency === null) { - continue; - } - $baseCurrencyCode = $baseCurrency->getCode(); - if ($baseCurrencyCode !== OneyGatewayFactory::BASE_CURRENCY_CODE) { - $message = $this->translator->trans( - 'payplug_sylius_payplug_plugin.form.base_currency_not_euro', - [ - '#channel_code#' => $dataFormChannel->getCode(), - '#payment_method#' => OneyGatewayFactory::FACTORY_TITLE, - ] - ); - $formChannels->get($key)->addError(new FormError($message)); - $this->flashBag->add('error', $message); - } - } - }) - ; - } + protected string $gatewayBaseCurrencyCode = OneyGatewayFactory::BASE_CURRENCY_CODE; } diff --git a/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php b/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php index e6c56196..f9056fdf 100644 --- a/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php +++ b/src/Gateway/Form/Type/PayPlugGatewayConfigurationType.php @@ -5,84 +5,21 @@ namespace PayPlug\SyliusPayPlugPlugin\Gateway\Form\Type; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsCanSaveCards; -use PayPlug\SyliusPayPlugPlugin\Gateway\Validator\Constraints\IsPayPlugSecretKeyValid; -use Sylius\Component\Core\Model\ChannelInterface; -use Symfony\Component\Form\Extension\Core\Type\CheckboxType; -use Symfony\Component\Form\Extension\Core\Type\TextType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\Form\FormError; -use Symfony\Component\Form\FormEvent; -use Symfony\Component\Form\FormEvents; -use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; +#[AutoconfigureTag( + 'sylius.gateway_configuration_type', + [ + 'type' => 'payplug', + 'label' => 'payplug_sylius_payplug_plugin.ui.payplug_gateway_label', + 'priority' => 100, + ], +)] final class PayPlugGatewayConfigurationType extends AbstractGatewayConfigurationType { - /** - * @inheritdoc - */ - public function buildForm(FormBuilderInterface $builder, array $options): void - { - $validationGroups = ['Default', 'sylius']; + protected string $gatewayFactoryTitle = PayPlugGatewayFactory::FACTORY_TITLE; - $builder - ->add('secretKey', TextType::class, [ - 'label' => 'payplug_sylius_payplug_plugin.ui.secret_key', - 'validation_groups' => $validationGroups, - 'constraints' => [ - new NotBlank([ - 'message' => 'payplug_sylius_payplug_plugin.secret_key.not_blank', - ]), - new IsPayPlugSecretKeyValid(), - ], - 'help' => $this->translator->trans('payplug_sylius_payplug_plugin.ui.retrieve_secret_key_in_api_configuration_portal'), - 'help_html' => true, - ]) - ->add(PayPlugGatewayFactory::ONE_CLICK, CheckboxType::class, [ - 'label' => 'payplug_sylius_payplug_plugin.form.one_click_enable', - 'validation_groups' => $validationGroups, - 'constraints' => [ - new IsCanSaveCards(), - ], - 'help' => $this->translator->trans('payplug_sylius_payplug_plugin.form.one_click_help'), - 'help_html' => true, - ]) - ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void { - $data = $event->getData(); - $data['payum.http_client'] = '@payplug_sylius_payplug_plugin.api_client.payplug'; + protected string $gatewayFactoryName = PayPlugGatewayFactory::FACTORY_NAME; - $event->setData($data); - }) - ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event): void { - $this->checkCreationRequirements( - PayPlugGatewayFactory::FACTORY_TITLE, - PayPlugGatewayFactory::FACTORY_NAME, - $event->getForm() - ); - - /** @phpstan-ignore-next-line */ - $formChannels = $event->getForm()->getParent()->getParent()->get('channels'); - $dataFormChannels = $formChannels->getData(); - /** @var ChannelInterface $dataFormChannel */ - foreach ($dataFormChannels as $key => $dataFormChannel) { - $baseCurrency = $dataFormChannel->getBaseCurrency(); - if ($baseCurrency === null) { - continue; - } - $baseCurrencyCode = $baseCurrency->getCode(); - if ($baseCurrencyCode !== PayPlugGatewayFactory::BASE_CURRENCY_CODE) { - $message = $this->translator->trans( - 'payplug_sylius_payplug_plugin.form.base_currency_not_euro', - [ - '#channel_code#' => $dataFormChannel->getCode(), - '#payment_method#' => PayPlugGatewayFactory::FACTORY_TITLE, - ] - ); - $formChannels->get($key)->addError(new FormError($message)); - $this->flashBag->add('error', $message); - } - } - }) - ; - } + protected string $gatewayBaseCurrencyCode = PayPlugGatewayFactory::BASE_CURRENCY_CODE; } diff --git a/src/Gateway/OneyGatewayFactory.php b/src/Gateway/OneyGatewayFactory.php index 7516c8f7..93cd6ed8 100644 --- a/src/Gateway/OneyGatewayFactory.php +++ b/src/Gateway/OneyGatewayFactory.php @@ -10,12 +10,35 @@ final class OneyGatewayFactory extends AbstractGatewayFactory public const FACTORY_TITLE = 'Oney by PayPlug'; + public const MERCHANT_FEES = 'merchant'; + + public const CLIENT_FEES = 'client'; + public const MAX_ITEMS = 999; public const REFUND_WAIT_TIME_IN_HOURS = 48; + public const FEES_FOR = 'fees_for'; + + public const ONEY_WITH_FEES_CHOICES = [ + 'x3_with_fees', + 'x4_with_fees', + ]; + + public const ONEY_WITHOUT_FEES_CHOICES = [ + 'x3_without_fees', + 'x4_without_fees', + ]; + + public const PAYMENT_CHOICES_FEES_FOR = [ + 'merchant' => self::ONEY_WITHOUT_FEES_CHOICES, + 'client' => self::ONEY_WITH_FEES_CHOICES, + ]; + public const PAYMENT_CHOICES = [ 'oney_x3_with_fees', 'oney_x4_with_fees', + 'oney_x3_without_fees', + 'oney_x4_without_fees', ]; } diff --git a/src/Gateway/PayPlugGatewayFactory.php b/src/Gateway/PayPlugGatewayFactory.php index ac24278e..a6aa1f7a 100644 --- a/src/Gateway/PayPlugGatewayFactory.php +++ b/src/Gateway/PayPlugGatewayFactory.php @@ -10,8 +10,13 @@ final class PayPlugGatewayFactory extends AbstractGatewayFactory public const FACTORY_TITLE = 'PayPlug'; + // Custom gateway configuration keys public const ONE_CLICK = 'oneClick'; + public const INTEGRATED_PAYMENT = 'integratedPayment'; + + public const DEFERRED_CAPTURE = 'deferredCapture'; + public const AUTHORIZED_CURRENCIES = [ 'EUR' => [ 'min_amount' => 99, diff --git a/src/Gateway/Validator/Constraints/IsCanSaveCards.php b/src/Gateway/Validator/Constraints/IsCanSaveCards.php deleted file mode 100644 index b8b0b7e8..00000000 --- a/src/Gateway/Validator/Constraints/IsCanSaveCards.php +++ /dev/null @@ -1,21 +0,0 @@ -apiClientFactory = $apiClientFactory; - } - - public function validate($value, Constraint $constraint): void - { - if (!$constraint instanceof IsCanSaveCards) { - throw new UnexpectedTypeException($constraint, IsCanSaveCards::class); - } - if (null === $value || '' === $value) { - return; - } - if (!is_bool($value)) { - throw new UnexpectedValueException($value, 'boolean'); - } - - $secretKey = $this->context->getRoot()->getData()->getGatewayConfig()->getConfig()['secretKey']; - - try { - if (true === $value) { - $checker = new PermissionCanSaveCardsChecker($this->apiClientFactory->create(PayPlugGatewayFactory::FACTORY_NAME, $secretKey)); - if (false === $checker->isEnabled()) { - $this->context->buildViolation($constraint->message)->addViolation(); - } - } - - return; - } catch (UnauthorizedException|\LogicException $exception) { - return; - } - } -} diff --git a/src/Gateway/Validator/Constraints/IsCanSavePaymentMethod.php b/src/Gateway/Validator/Constraints/IsCanSavePaymentMethod.php new file mode 100644 index 00000000..7bd79203 --- /dev/null +++ b/src/Gateway/Validator/Constraints/IsCanSavePaymentMethod.php @@ -0,0 +1,21 @@ +isEnabled() === false) { + return; + } + + $factoryName = $value->getGatewayConfig()?->getFactoryName(); + $channels = $value->getChannels(); + + Assert::stringNotEmpty($factoryName); + + if (in_array($factoryName, self::GATEWAYS_SKIP, true)) { + return; + } + + try { + $checker = new CanSavePayplugPaymentMethodChecker($this->apiClientFactory->createForPaymentMethod($value)); + if (!$checker->isLive()) { + $this->context->buildViolation(sprintf($constraint->noTestKeyMessage, $factoryName))->addViolation(); + + return; + } + + if (!$checker->isEnabled($factoryName, $channels)) { + $this->context->buildViolation(sprintf($constraint->noAccessMessage, $factoryName))->addViolation(); + } + + return; + } catch (GatewayConfigurationException $exception) { + $this->context->buildViolation($exception->getMessage()) + ->addViolation(); + } catch (UnauthorizedException | \LogicException) { + return; + } + } +} diff --git a/src/Gateway/Validator/Constraints/IsOneyEnabledValidator.php b/src/Gateway/Validator/Constraints/IsOneyEnabledValidator.php index 95ab1fee..86aefd6e 100644 --- a/src/Gateway/Validator/Constraints/IsOneyEnabledValidator.php +++ b/src/Gateway/Validator/Constraints/IsOneyEnabledValidator.php @@ -7,20 +7,19 @@ use Payplug\Exception\UnauthorizedException; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientFactory; use PayPlug\SyliusPayPlugPlugin\Checker\OneyChecker; +use PayPlug\SyliusPayPlugPlugin\Exception\GatewayConfigurationException; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; +use Sylius\Component\Payment\Model\GatewayConfigInterface; +use Sylius\Component\Core\Model\PaymentMethodInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; -use Symfony\Component\Validator\Exception\UnexpectedValueException; +use Webmozart\Assert\Assert; final class IsOneyEnabledValidator extends ConstraintValidator { - /** @var PayPlugApiClientFactory */ - private $apiClientFactory; - - public function __construct(PayPlugApiClientFactory $apiClientFactory) + public function __construct(private PayPlugApiClientFactory $apiClientFactory) { - $this->apiClientFactory = $apiClientFactory; } public function validate($value, Constraint $constraint): void @@ -31,20 +30,38 @@ public function validate($value, Constraint $constraint): void if (null === $value || '' === $value) { return; } - if (!is_string($value)) { - throw new UnexpectedValueException($value, 'string'); + if (!$value instanceof PaymentMethodInterface) { + return; } - try { - $checker = new OneyChecker($this->apiClientFactory->create(OneyGatewayFactory::FACTORY_NAME, $value)); + if ($value->isEnabled() === false) { + return; + } + $paymentMethod = $value; + $gatewayConfig = $paymentMethod->getGatewayConfig(); + if (!$gatewayConfig instanceof GatewayConfigInterface) { + return; + } + + $factoryName = $gatewayConfig->getFactoryName(); + Assert::stringNotEmpty($factoryName); + + if ($factoryName !== OneyGatewayFactory::FACTORY_NAME) { + return; + } + + try { + $checker = new OneyChecker($this->apiClientFactory->createForPaymentMethod($paymentMethod)); if (false === $checker->isEnabled()) { $this->context->buildViolation($constraint->message) ->addViolation(); } - } catch (UnauthorizedException $exception) { - // do nothing, this should be handle by IsPayPlugSecretKeyValid Constraint + } catch (UnauthorizedException) { return; + } catch (GatewayConfigurationException $exception) { + $this->context->buildViolation($exception->getMessage()) + ->addViolation(); } } } diff --git a/src/Gateway/Validator/Constraints/IsPayPlugSecretKeyValid.php b/src/Gateway/Validator/Constraints/IsPayPlugSecretKeyValid.php deleted file mode 100644 index 0b2719c6..00000000 --- a/src/Gateway/Validator/Constraints/IsPayPlugSecretKeyValid.php +++ /dev/null @@ -1,21 +0,0 @@ -apiClientFactory = $apiClientFactory; - } - - public function validate($value, Constraint $constraint): void - { - if (!$constraint instanceof IsPayPlugSecretKeyValid) { - throw new UnexpectedTypeException($constraint, IsPayPlugSecretKeyValid::class); - } - if (null === $value || '' === $value) { - return; - } - if (!is_string($value)) { - throw new UnexpectedValueException($value, 'string'); - } - - try { - \Payplug\Payplug::init(['secretKey' => $value]); - \Payplug\Authentication::getPermissions(); - $apiClient = $this->apiClientFactory->create(PayPlugGatewayFactory::FACTORY_NAME, $value); - $apiClient->getAccount(true); - } catch (UnauthorizedException $exception) { - $this->context->buildViolation($constraint->message) - ->addViolation(); - } - } -} diff --git a/src/Gateway/Validator/Constraints/PayplugPermission.php b/src/Gateway/Validator/Constraints/PayplugPermission.php new file mode 100644 index 00000000..dc57db67 --- /dev/null +++ b/src/Gateway/Validator/Constraints/PayplugPermission.php @@ -0,0 +1,27 @@ +permission = $feature; + $this->message = $message ?? $this->message; + } +} diff --git a/src/Gateway/Validator/Constraints/PayplugPermissionValidator.php b/src/Gateway/Validator/Constraints/PayplugPermissionValidator.php new file mode 100644 index 00000000..328b47e8 --- /dev/null +++ b/src/Gateway/Validator/Constraints/PayplugPermissionValidator.php @@ -0,0 +1,49 @@ +isEnabled() === false) { + return; + } + + try { + $client = $this->apiClientFactory->createForPaymentMethod($paymentMethod); + $accountPermissions = $client->getPermissions(); + + if (false === $accountPermissions[$constraint->permission]) { + $this->context + ->buildViolation($constraint->message) + ->addViolation(); + } + + return; + } catch (UnauthorizedException | \LogicException) { + return; + } + } +} diff --git a/src/Handler/PaymentNotificationHandler.php b/src/Handler/PaymentNotificationHandler.php index e0493a64..afcc8468 100644 --- a/src/Handler/PaymentNotificationHandler.php +++ b/src/Handler/PaymentNotificationHandler.php @@ -5,63 +5,62 @@ namespace PayPlug\SyliusPayPlugPlugin\Handler; use DateTimeImmutable; +use Doctrine\ORM\EntityManagerInterface; use Payplug\Resource\IVerifiableAPIResource; use Payplug\Resource\Payment; use Payplug\Resource\PaymentAuthorization; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Entity\Card; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; -use Payum\Core\Request\Generic; use Psr\Log\LoggerInterface; use Sylius\Component\Core\Model\CustomerInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Repository\CustomerRepositoryInterface; use Sylius\Component\Resource\Factory\FactoryInterface; use Sylius\Component\Resource\Repository\RepositoryInterface; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Lock\LockFactory; class PaymentNotificationHandler { - /** @var \Psr\Log\LoggerInterface */ - private $logger; - - /** @var \Sylius\Component\Resource\Repository\RepositoryInterface */ - private $payplugCardRepository; - - /** @var \Sylius\Component\Resource\Factory\FactoryInterface */ - private $payplugCardFactory; - - /** @var \Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface */ - private $flashBag; - - /** @var \Sylius\Component\Core\Repository\CustomerRepositoryInterface */ - private $customerRepository; - public function __construct( - LoggerInterface $logger, - RepositoryInterface $payplugCardRepository, - FactoryInterface $payplugCardFactory, - CustomerRepositoryInterface $customerRepository, - FlashBagInterface $flashBag + private LoggerInterface $logger, + private RepositoryInterface $payplugCardRepository, + private FactoryInterface $payplugCardFactory, + private CustomerRepositoryInterface $customerRepository, + private EntityManagerInterface $entityManager, + private LockFactory $lockFactory, + private RequestStack $requestStack, ) { - $this->logger = $logger; - $this->payplugCardRepository = $payplugCardRepository; - $this->payplugCardFactory = $payplugCardFactory; - $this->flashBag = $flashBag; - $this->customerRepository = $customerRepository; } - public function treat(Generic $request, IVerifiableAPIResource $paymentResource, \ArrayObject $details): void - { + public function treat( + PaymentInterface $payment, + IVerifiableAPIResource $paymentResource, + \ArrayObject $details, + ): void { if (!$paymentResource instanceof Payment) { return; } + $lock = $this->lockFactory->createLock('payment_' . $paymentResource->id); + $lock->acquire(true); + + $this->entityManager->refresh($payment); + + if ($details['status'] === PayPlugApiClientInterface::STATUS_ABORTED) { + $lock->release(); + + return; + } + if ($paymentResource->is_paid) { $details['status'] = PayPlugApiClientInterface::STATUS_CAPTURED; $details['created_at'] = $paymentResource->created_at; - $this->saveCard($request->getFirstModel(), $paymentResource); + $this->saveCard($payment, $paymentResource); + + $lock->release(); return; } @@ -69,6 +68,8 @@ public function treat(Generic $request, IVerifiableAPIResource $paymentResource, if ($this->isResourceIsAuthorized($paymentResource)) { $details['status'] = PayPlugApiClientInterface::STATUS_AUTHORIZED; + $lock->release(); + return; } @@ -80,6 +81,8 @@ public function treat(Generic $request, IVerifiableAPIResource $paymentResource, 'message' => $paymentResource->failure->message ?? '', ]; + $lock->release(); + return; } @@ -89,11 +92,12 @@ public function treat(Generic $request, IVerifiableAPIResource $paymentResource, 'message' => $paymentResource->failure->message ?? '', ]; - if ($details['status'] === PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK) { - $this->flashBag->add('error', 'payplug_sylius_payplug_plugin.error.transaction_failed_1click'); + if (PayPlugApiClientInterface::INTERNAL_STATUS_ONE_CLICK === $details['status']) { + $this->requestStack->getSession()->getFlashBag()->add('error', 'payplug_sylius_payplug_plugin.error.transaction_failed_1click'); } $details['status'] = PayPlugApiClientInterface::FAILED; + $lock->release(); } private function saveCard(PaymentInterface $payment, IVerifiableAPIResource $paymentResource): void @@ -118,15 +122,17 @@ private function saveCard(PaymentInterface $payment, IVerifiableAPIResource $pay return; } - if (!$paymentResource->__isset('card') || + if ( + !$paymentResource->__isset('card') || null === $paymentResource->__get('card') || - (null !== $paymentResource->__get('card') && null === $paymentResource->__get('card')->id)) { + (null !== $paymentResource->__get('card') && null === $paymentResource->__get('card')->id) + ) { return; } // Payment has been successfully made, but card was not saved - if ($paymentResource->__get('card')->id === null) { - $this->flashBag->add('info', 'payplug_sylius_payplug_plugin.warning.payment_success_no_card_saved'); + if (null === $paymentResource->__get('card')->id) { + $this->requestStack->getSession()->getFlashBag()->add('info', 'payplug_sylius_payplug_plugin.warning.payment_success_no_card_saved'); return; } @@ -167,21 +173,18 @@ private function isResourceIsAuthorized(IVerifiableAPIResource $paymentResource) } // Oney is reviewing the payer’s file - if ($paymentResource->__isset('payment_method') && - $paymentResource->__get('payment_method') !== null && - $paymentResource->__get('payment_method')['is_pending'] === true) { + if ( + $paymentResource->__isset('payment_method') && + null !== $paymentResource->__get('payment_method') && + \array_key_exists('is_pending', $paymentResource->__get('payment_method')) && + true === $paymentResource->__get('payment_method')['is_pending'] + ) { return true; } $now = new DateTimeImmutable(); - if ($paymentResource->__isset('authorization') && - $paymentResource->__get('authorization') instanceof PaymentAuthorization && - $paymentResource->__get('authorization')->__get('expires_at') !== null && - $now < $now->setTimestamp($paymentResource->__get('authorization')->__get('expires_at'))) { - return true; - } - return false; + return $paymentResource->__isset('authorization') && $paymentResource->__get('authorization') instanceof PaymentAuthorization && null !== $paymentResource->__get('authorization')->__get('expires_at') && $now < $now->setTimestamp($paymentResource->__get('authorization')->__get('expires_at')); } private function isRefusedOneyPayment(IVerifiableAPIResource $paymentResource): bool @@ -191,15 +194,6 @@ private function isRefusedOneyPayment(IVerifiableAPIResource $paymentResource): } // Oney has reviewed the payer’s file and refused it - if (!$paymentResource->is_paid && - $paymentResource->__isset('payment_method') && - $paymentResource->__get('payment_method') !== null && - $paymentResource->__get('payment_method')['is_pending'] === false && - \in_array($paymentResource->__get('payment_method')['type'], OneyGatewayFactory::PAYMENT_CHOICES, true) - ) { - return true; - } - - return false; + return !$paymentResource->is_paid && $paymentResource->__isset('payment_method') && null !== $paymentResource->__get('payment_method') && \array_key_exists('is_pending', $paymentResource->__get('payment_method')) && false === $paymentResource->__get('payment_method')['is_pending'] && \in_array($paymentResource->__get('payment_method')['type'], OneyGatewayFactory::PAYMENT_CHOICES, true); } } diff --git a/src/Handler/RefundNotificationHandler.php b/src/Handler/RefundNotificationHandler.php index 2923fdb4..18d3c173 100644 --- a/src/Handler/RefundNotificationHandler.php +++ b/src/Handler/RefundNotificationHandler.php @@ -10,32 +10,23 @@ use PayPlug\SyliusPayPlugPlugin\Entity\RefundHistory; use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\RefundPaymentHandlerInterface; use PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface; -use Payum\Core\Request\Generic; +use Sylius\Component\Core\Model\PaymentInterface; use Symfony\Component\Messenger\MessageBusInterface; class RefundNotificationHandler { - /** @var \PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface */ - private $payplugRefundHistoryRepository; - - /** @var \PayPlug\SyliusPayPlugPlugin\PaymentProcessing\RefundPaymentHandlerInterface */ - private $refundPaymentHandler; - - /** @var \Symfony\Component\Messenger\MessageBusInterface */ - private $commandBus; - public function __construct( - RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, - RefundPaymentHandlerInterface $refundPaymentHandler, - MessageBusInterface $commandBus + private RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, + private RefundPaymentHandlerInterface $refundPaymentHandler, + private MessageBusInterface $commandBus, ) { - $this->payplugRefundHistoryRepository = $payplugRefundHistoryRepository; - $this->refundPaymentHandler = $refundPaymentHandler; - $this->commandBus = $commandBus; } - public function treat(Generic $request, IVerifiableAPIResource $refundResource, \ArrayObject $details): void - { + public function treat( + PaymentInterface $payment, + IVerifiableAPIResource $refundResource, + \ArrayObject $details, + ): void { if (!$refundResource instanceof Refund) { return; } @@ -46,7 +37,7 @@ public function treat(Generic $request, IVerifiableAPIResource $refundResource, } $details['status'] = PayPlugApiClientInterface::REFUNDED; - $refundUnits = $this->refundPaymentHandler->handle($refundResource, $request->getFirstModel()); + $refundUnits = $this->refundPaymentHandler->handle($refundResource, $payment); /** @var RefundHistory|null $refundHistory */ $refundHistory = $this->payplugRefundHistoryRepository->findOneBy(['externalId' => $refundResource->id]); @@ -58,7 +49,7 @@ public function treat(Generic $request, IVerifiableAPIResource $refundResource, $refundHistory ->setExternalId($refundResource->id) ->setValue($refundResource->amount) - ->setPayment($request->getFirstModel()) + ->setPayment($payment) ; $this->payplugRefundHistoryRepository->add($refundHistory); diff --git a/src/MessageHandler/RefundPaymentGeneratedHandler.php b/src/MessageHandler/RefundPaymentGeneratedHandler.php index 845e1b19..9bd4bc27 100644 --- a/src/MessageHandler/RefundPaymentGeneratedHandler.php +++ b/src/MessageHandler/RefundPaymentGeneratedHandler.php @@ -9,13 +9,16 @@ use Doctrine\ORM\EntityManagerInterface; use PayPlug\SyliusPayPlugPlugin\Entity\RefundHistory; use PayPlug\SyliusPayPlugPlugin\Exception\ApiRefundException; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\PaymentProcessing\RefundPaymentProcessor; use PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface; -use Payum\Core\Model\GatewayConfigInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; use Psr\Log\LoggerInterface; -use SM\Factory\FactoryInterface; +use Sylius\Abstraction\StateMachine\StateMachineInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; @@ -26,65 +29,27 @@ use Sylius\RefundPlugin\Event\RefundPaymentGenerated; use Sylius\RefundPlugin\Exception\InvalidRefundAmount; use Sylius\RefundPlugin\StateResolver\RefundPaymentTransitions; -use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Contracts\Translation\TranslatorInterface; use Throwable; use Webmozart\Assert\Assert; +#[AsMessageHandler] final class RefundPaymentGeneratedHandler { - /** @var EntityManagerInterface */ - private $entityManager; - - /** @var FactoryInterface */ - private $stateMachineFactory; - - /** @var RefundPaymentProcessor */ - private $refundPaymentProcessor; - - /** @var PaymentRepositoryInterface */ - private $paymentRepository; - - /** @var LoggerInterface */ - private $logger; - - /** @var RefundHistoryRepositoryInterface */ - private $payplugRefundHistoryRepository; - - /** @var Session */ - private $session; - - /** @var OrderRepositoryInterface */ - private $orderRepository; - - /** @var TranslatorInterface */ - private $translator; - - /** @var RepositoryInterface */ - private $refundPaymentRepository; - public function __construct( - EntityManagerInterface $entityManager, - PaymentRepositoryInterface $paymentRepository, - RepositoryInterface $refundPaymentRepository, - RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, - FactoryInterface $stateMachineFactory, - RefundPaymentProcessor $refundPaymentProcessor, - LoggerInterface $logger, - Session $session, - OrderRepositoryInterface $orderRepository, - TranslatorInterface $translator + private EntityManagerInterface $entityManager, + private PaymentRepositoryInterface $paymentRepository, + private RepositoryInterface $refundPaymentRepository, + private RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, + private StateMachineInterface $stateMachine, + private RefundPaymentProcessor $refundPaymentProcessor, + private LoggerInterface $logger, + private RequestStack $requestStack, + private OrderRepositoryInterface $orderRepository, + private TranslatorInterface $translator, ) { - $this->entityManager = $entityManager; - $this->paymentRepository = $paymentRepository; - $this->refundPaymentRepository = $refundPaymentRepository; - $this->payplugRefundHistoryRepository = $payplugRefundHistoryRepository; - $this->stateMachineFactory = $stateMachineFactory; - $this->refundPaymentProcessor = $refundPaymentProcessor; - $this->logger = $logger; - $this->session = $session; - $this->orderRepository = $orderRepository; - $this->translator = $translator; } public function __invoke(RefundPaymentGenerated $message): void @@ -104,20 +69,23 @@ public function __invoke(RefundPaymentGenerated $message): void !\in_array($paymentMethod->getGatewayConfig()->getFactoryName(), [ PayPlugGatewayFactory::FACTORY_NAME, OneyGatewayFactory::FACTORY_NAME, + BancontactGatewayFactory::FACTORY_NAME, + ApplePayGatewayFactory::FACTORY_NAME, + AmericanExpressGatewayFactory::FACTORY_NAME, ], true) ) { return; } $refundHistory = $this->payplugRefundHistoryRepository->findLastRefundForPayment($payment); - if ($refundHistory instanceof RefundHistory && - $refundHistory->getExternalId() !== null && - $refundHistory->getRefundPayment() === null + if ( + $refundHistory instanceof RefundHistory && + null !== $refundHistory->getExternalId() && + !$refundHistory->getRefundPayment() instanceof \Sylius\RefundPlugin\Entity\RefundPayment ) { /** @var RefundPayment $refundPayment */ $refundPayment = $this->refundPaymentRepository->find($message->id()); - $stateMachine = $this->stateMachineFactory->get($refundPayment, RefundPaymentTransitions::GRAPH); - $stateMachine->apply(RefundPaymentTransitions::TRANSITION_COMPLETE); + $this->stateMachine->apply($refundPayment, RefundPaymentTransitions::GRAPH, RefundPaymentTransitions::TRANSITION_COMPLETE); $this->entityManager->flush(); $refundHistory->setProcessed(true); @@ -130,7 +98,7 @@ public function __invoke(RefundPaymentGenerated $message): void $this->processRefund($payment, $message); } catch (InvalidRefundAmount $exception) { - $this->session->getFlashBag()->add('error', $exception->getMessage()); + $this->requestStack->getSession()->getFlashBag()->add('error', $exception->getMessage()); $this->logger->error($exception->getMessage()); throw new ApiRefundException($exception->getMessage(), $exception->getCode(), $exception); @@ -147,8 +115,7 @@ private function processRefund(PaymentInterface $payment, RefundPaymentGenerated /** @var RefundPayment $refundPayment */ $refundPayment = $this->refundPaymentRepository->find($message->id()); - $stateMachine = $this->stateMachineFactory->get($refundPayment, RefundPaymentTransitions::GRAPH); - $stateMachine->apply(RefundPaymentTransitions::TRANSITION_COMPLETE); + $this->stateMachine->apply($refundPayment, RefundPaymentTransitions::GRAPH, RefundPaymentTransitions::TRANSITION_COMPLETE); $this->entityManager->flush(); } @@ -170,7 +137,7 @@ private function hasLessThanFortyEightHoursTransaction(PaymentInterface $payment return $this->isLessThanFortyEightHours( $order->getLastPayment()->getCreatedAt(), - $now + $now, ); } @@ -180,7 +147,7 @@ private function hasLessThanFortyEightHoursTransaction(PaymentInterface $payment return $this->isLessThanFortyEightHours( $refundHistory->getCreatedAt(), - $now + $now, ); } @@ -195,16 +162,16 @@ private function isLessThanFortyEightHours(DateTimeInterface $from, DateTimeInte private function checkOneyRequirements( PaymentInterface $payment, - RefundPaymentGenerated $message + RefundPaymentGenerated $message, ): void { Assert::isInstanceOf($payment->getMethod(), PaymentMethodInterface::class); Assert::isInstanceOf($payment->getMethod()->getGatewayConfig(), GatewayConfigInterface::class); - if ($payment->getMethod()->getGatewayConfig()->getFactoryName() === OneyGatewayFactory::FACTORY_NAME && - $this->hasLessThanFortyEightHoursTransaction($payment, $message->orderNumber())) { - throw InvalidRefundAmount::withValidationConstraint( - $this->translator->trans('payplug_sylius_payplug_plugin.ui.oney_transaction_less_than_forty_eight_hours') - ); + if ( + OneyGatewayFactory::FACTORY_NAME === $payment->getMethod()->getGatewayConfig()->getFactoryName() && + $this->hasLessThanFortyEightHoursTransaction($payment, $message->orderNumber()) + ) { + throw InvalidRefundAmount::withValidationConstraint($this->translator->trans('payplug_sylius_payplug_plugin.ui.oney_transaction_less_than_forty_eight_hours')); } } } diff --git a/src/Model/OneyCompleteInfoDTO.php b/src/Model/OneyCompleteInfoDTO.php index bf48edc0..6d50a266 100644 --- a/src/Model/OneyCompleteInfoDTO.php +++ b/src/Model/OneyCompleteInfoDTO.php @@ -14,32 +14,30 @@ final class OneyCompleteInfoDTO /** @var string */ public $phone; - /** - * @var string - * @Assert\Email - */ + /** @var string */ + #[Assert\Email] public $email; /** @var string */ public $countryCode; - /** - * @Assert\Callback - */ + #[Assert\Callback] public function validatePhoneNumber(ExecutionContextInterface $context): void { - if ($this->phone === null) { + if (null === $this->phone) { return; } try { $phoneNumberUtil = PhoneNumberUtil::getInstance(); $parsedNumber = $phoneNumberUtil->parse($this->phone, $this->countryCode); - if (!$phoneNumberUtil->isValidNumber($parsedNumber) || - $phoneNumberUtil->getNumberType($parsedNumber) !== PhoneNumberType::MOBILE) { + if ( + !$phoneNumberUtil->isValidNumber($parsedNumber) || + PhoneNumberType::MOBILE !== $phoneNumberUtil->getNumberType($parsedNumber) + ) { throw new \InvalidArgumentException('Not a valid mobile phone number'); } - } catch (\Throwable $throwable) { + } catch (\Throwable) { $context->buildViolation('payplug_sylius_payplug_plugin.oney.not_valid_phone_number') ->atPath('phone') ->addViolation(); diff --git a/src/OrderPay/Provider/CaptureHttpResponseProvider.php b/src/OrderPay/Provider/CaptureHttpResponseProvider.php new file mode 100644 index 00000000..6fe83347 --- /dev/null +++ b/src/OrderPay/Provider/CaptureHttpResponseProvider.php @@ -0,0 +1,54 @@ + PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.http_response_provider.payplug_oney', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.http_response_provider.payplug_bancontact', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.http_response_provider.payplug_apple_pay', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +#[AutoconfigureTag( + 'payplug_sylius_payplug_plugin.http_response_provider.payplug_american_express', + ['action' => PaymentRequestInterface::ACTION_CAPTURE], +)] +class CaptureHttpResponseProvider implements HttpResponseProviderInterface +{ + public function supports(RequestConfiguration $requestConfiguration, PaymentRequestInterface $paymentRequest): bool + { + return $paymentRequest->getAction() === PaymentRequestInterface::ACTION_CAPTURE && + ($paymentRequest->getResponseData()['redirect_url'] ?? null) !== null; + } + + public function getResponse( + RequestConfiguration $requestConfiguration, + PaymentRequestInterface $paymentRequest, + ): Response { + // This is called after the capture payment request has been handled + $data = $paymentRequest->getResponseData(); + if (!\is_string($data['redirect_url'] ?? null)) { + throw new \LogicException('Redirect URL is not set in the payment request response data.'); + } + + return new RedirectResponse($data['redirect_url']); + } +} diff --git a/src/OrderPay/Provider/NotifyPaymentProvider.php b/src/OrderPay/Provider/NotifyPaymentProvider.php new file mode 100644 index 00000000..1f7818c3 --- /dev/null +++ b/src/OrderPay/Provider/NotifyPaymentProvider.php @@ -0,0 +1,73 @@ +getPayload()->all('metadata')['order_number'] ?? null; + if (null === $orderNumber) { + throw new \InvalidArgumentException('Order number not found in request payload'); + } + $order = $this->getOrderFromReference((string) $orderNumber); + + $payId = $request->getPayload()->getString('id'); + $payment = $order->getPayments()->filter(function (PaymentInterface $payment) use ($payId) { + return $payId === ($payment->getDetails()['payment_id'] ?? null); + })->first(); + if (false === $payment) { + throw new \InvalidArgumentException(sprintf('Payment with ID "%s" not found in order "%s"', $payId, $orderNumber)); + } + + return $payment; + } + + public function supports(Request $request, PaymentMethodInterface $paymentMethod): bool + { + return \str_contains($paymentMethod->getGatewayConfig()?->getFactoryName() ?? '', 'payplug') && + $request->getPayload()->has('id') && + $request->getPayload()->has('metadata') && + $request->getPayload()->has('object') && + $request->getPayload()->get('object') === 'payment'; + } + + private function getOrderFromReference(string $orderReference): OrderInterface + { + $order = $this->orderRepository->findOneBy(['number' => $orderReference]); + if (null === $order) { + // @see \PayPlug\SyliusPayPlugPlugin\Creator\PayPlugPaymentDataCreator order_number can be number/token or id + $order = $this->orderRepository->findOneBy(['tokenValue' => $orderReference]); + } + if (null === $order) { + $order = $this->orderRepository->findOneBy(['id' => $orderReference]); + } + if (!$order instanceof OrderInterface) { + throw new \InvalidArgumentException(sprintf('Order with reference "%s" not found', $orderReference)); + } + + return $order; + } +} diff --git a/src/OrderPay/Provider/NotifyRefundPaymentProvider.php b/src/OrderPay/Provider/NotifyRefundPaymentProvider.php new file mode 100644 index 00000000..50cdbee6 --- /dev/null +++ b/src/OrderPay/Provider/NotifyRefundPaymentProvider.php @@ -0,0 +1,46 @@ +getPayload()->get('payment_id'); + if (null === $paymentId) { + throw new \InvalidArgumentException('Order number not found in request payload'); + } + + $payment = $this->paymentRepository->findOneByPayPlugPaymentId($paymentId); + if (null === $payment || $payment->getMethod() !== $paymentMethod) { + throw new \InvalidArgumentException(sprintf('Payment with ID "%s" not found', $paymentId)); + } + + return $payment; + } + + public function supports(Request $request, PaymentMethodInterface $paymentMethod): bool + { + return \str_contains($paymentMethod->getGatewayConfig()?->getFactoryName() ?? '', 'payplug') && + $request->getPayload()->has('id') && + $request->getPayload()->has('metadata') && + $request->getPayload()->has('object') && + $request->getPayload()->get('object') === 'refund'; + } +} diff --git a/src/PayPlugSyliusPayPlugPlugin.php b/src/PayPlugSyliusPayPlugPlugin.php index 49882ae2..1720cf4c 100644 --- a/src/PayPlugSyliusPayPlugPlugin.php +++ b/src/PayPlugSyliusPayPlugPlugin.php @@ -9,7 +9,12 @@ final class PayPlugSyliusPayPlugPlugin extends Bundle { - public const VERSION = '1.3.0'; - use SyliusPluginTrait; + + public const VERSION = '2.0.0'; + + public function getPath(): string + { + return \dirname(__DIR__); + } } diff --git a/src/PaymentProcessing/AbortPaymentProcessor.php b/src/PaymentProcessing/AbortPaymentProcessor.php new file mode 100644 index 00000000..a4f85d78 --- /dev/null +++ b/src/PaymentProcessing/AbortPaymentProcessor.php @@ -0,0 +1,56 @@ +getSubject(); + if (!$subject instanceof PaymentInterface) { + return; + } + + $this->process($subject); + } + + public function process(PaymentInterface $payment): void + { + $paymentId = $payment->getDetails()['payment_id'] ?? null; + if (null === $paymentId) { + // Payment not even started on payplug + return; + } + + $method = $payment->getMethod(); + if (null === $method) { + return; + } + $client = $this->payplugApiClientFactory->createForPaymentMethod($method); + try { + // When a payment is failed on Sylius, also abort it on PayPlug. + // This should prevent the case that if we are already on PayPlug payment page + // and go to the order history in another tab to click on pay again, then fail the transaction + // and go back on the first PayPlug payment page and succeed it, it stays failed as its first payment model is already failed + $client->abortPayment($paymentId); + } catch (HttpException) { + } + } +} diff --git a/src/PaymentProcessing/CaptureAuthorizedPaymentProcessor.php b/src/PaymentProcessing/CaptureAuthorizedPaymentProcessor.php new file mode 100644 index 00000000..4b16ee5b --- /dev/null +++ b/src/PaymentProcessing/CaptureAuthorizedPaymentProcessor.php @@ -0,0 +1,73 @@ +getSubject(); + if (!$subject instanceof PaymentInterface) { + return; + } + + $this->process($subject); + } + + public function process(PaymentInterface $payment): void + { + $details = new ArrayObject($payment->getDetails()); + $method = $payment->getMethod(); + if (!$method instanceof PaymentMethodInterface) { + return; + } + if (PayPlugGatewayFactory::FACTORY_NAME !== $method->getGatewayConfig()?->getFactoryName()) { + // Not a supported payment method + return; + } + + if (!isset($details['status']) || PayPlugApiClientInterface::STATUS_AUTHORIZED !== $details['status']) { + // Not an authorized payment, do nothing + return; + } + if (!isset($details['payment_id'])) { + // not a payplug payment id ? do nothing + return; + } + $paymentId = $details['payment_id']; + if (!is_string($paymentId)) { + throw new \LogicException('Payment id is not a string'); + } + + $client = $this->apiClientFactory->createForPaymentMethod($method); + $payplugPayment = $client->retrieve($paymentId); + + $updatedPayment = $payplugPayment->capture($client->getConfiguration()); + if (null === $updatedPayment) { + throw new \LogicException('Payment capture failed'); + } + + $this->paymentNotificationHandler->treat($payment, $updatedPayment, $details); + $payment->setDetails($details->getArrayCopy()); + } +} diff --git a/src/PaymentProcessing/RefundPaymentHandler.php b/src/PaymentProcessing/RefundPaymentHandler.php index e14a8536..70d80e53 100644 --- a/src/PaymentProcessing/RefundPaymentHandler.php +++ b/src/PaymentProcessing/RefundPaymentHandler.php @@ -25,28 +25,12 @@ final class RefundPaymentHandler implements RefundPaymentHandlerInterface { - /** @var RemainingTotalProviderInterface */ - private $remainingTotalProvider; - - /** @var UnitRefundTotalCalculatorInterface */ - private $unitRefundTotalCalculator; - - /** @var ObjectRepository */ - private $refundPaymentRepository; - - /** @var RefundPaymentCompletedStateApplierInterface */ - private $refundPaymentCompletedStateApplier; - public function __construct( - UnitRefundTotalCalculatorInterface $unitRefundTotalCalculator, - RemainingTotalProviderInterface $remainingTotalProvider, - ObjectRepository $refundPaymentInterface, - RefundPaymentCompletedStateApplierInterface $refundPaymentCompletedStateApplier + private UnitRefundTotalCalculatorInterface $unitRefundTotalCalculator, + private RemainingTotalProviderInterface $remainingTotalProvider, + private ObjectRepository $refundPaymentRepository, + private RefundPaymentCompletedStateApplierInterface $refundPaymentCompletedStateApplier, ) { - $this->unitRefundTotalCalculator = $unitRefundTotalCalculator; - $this->remainingTotalProvider = $remainingTotalProvider; - $this->refundPaymentRepository = $refundPaymentInterface; - $this->refundPaymentCompletedStateApplier = $refundPaymentCompletedStateApplier; } public function handle(Refund $refund, PaymentInterface $payment): RefundUnits @@ -64,16 +48,18 @@ public function fromRequest(Refund $refund, PaymentInterface $payment): RefundUn $shippingRemainingPrice = $this->getShippingRemainingPrice($payment->getOrder()); [$items, $shipments] = $this->dispatchRefundPrice($itemsRemainingPrice, $shippingRemainingPrice, $refund->amount); - if (count($items) === 0 && count($shipments) === 0) { + if (0 === count($items) && 0 === count($shipments)) { throw new InvalidRefundAmount(); } return new RefundUnits( $payment->getOrder()->getNumber(), - $this->parseIdsToUnitRefunds($items, RefundType::orderItemUnit(), OrderItemUnitRefund::class), - $this->parseIdsToUnitRefunds($shipments, RefundType::shipment(), ShipmentRefund::class), - $payment->getMethod()->getId(), - '' + array_merge( + $this->parseIdsToUnitRefunds($items, RefundType::orderItemUnit(), OrderItemUnitRefund::class), + $this->parseIdsToUnitRefunds($shipments, RefundType::shipment(), ShipmentRefund::class) + ), + $payment->getMethod()->getId(), // @phpstan-ignore-line + '', ); } @@ -94,7 +80,7 @@ public function updatePaymentStatus(PaymentInterface $payment): void } /** - * Parse shipment id's to ShipmentRefund with id and remaining total or amount passed in request + * Parse shipment id's to ShipmentRefund with id and remaining total or amount passed in request. * * @return array|UnitRefundInterface[] */ @@ -135,7 +121,7 @@ private function getItemsRemainingPrice(?OrderInterface $order): array foreach ($orderItem->getUnits() as $itemUnit) { $items[$itemUnit->getId()] = $this->remainingTotalProvider->getTotalLeftToRefund( $itemUnit->getId(), - RefundType::orderItemUnit() + RefundType::orderItemUnit(), ); } } @@ -153,7 +139,7 @@ private function getShippingRemainingPrice(?OrderInterface $order): array foreach ($order->getAdjustments(AdjustmentInterface::SHIPPING_ADJUSTMENT) as $shipment) { $items[$shipment->getId()] = $this->remainingTotalProvider->getTotalLeftToRefund( $shipment->getId(), - RefundType::shipment() + RefundType::shipment(), ); } @@ -186,12 +172,12 @@ private function dispatchRefundPrice(array $itemsRemainingPrice, array $shipment return [$this->addItem($items, $itemId, (int) $amount), $shipments]; } - if ($price !== 0) { + if (0 !== $price) { $items = $this->addItem($items, $itemId, $price); $amount -= $price; } - if ($amount === 0) { + if (0 === $amount) { return [$items, $shipments]; } } @@ -205,7 +191,7 @@ private function dispatchRefundPrice(array $itemsRemainingPrice, array $shipment $shipments = $this->addItem($shipments, $itemId, $price); $amount -= $price; - if ($amount === 0) { + if (0 === $amount) { return [$items, $shipments]; } } diff --git a/src/PaymentProcessing/RefundPaymentProcessor.php b/src/PaymentProcessing/RefundPaymentProcessor.php index 290934f7..d9c62382 100644 --- a/src/PaymentProcessing/RefundPaymentProcessor.php +++ b/src/PaymentProcessing/RefundPaymentProcessor.php @@ -5,61 +5,61 @@ namespace PayPlug\SyliusPayPlugPlugin\PaymentProcessing; use Exception; +use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientFactoryInterface; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Entity\RefundHistory; +use PayPlug\SyliusPayPlugPlugin\Gateway\AmericanExpressGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\ApplePayGatewayFactory; +use PayPlug\SyliusPayPlugPlugin\Gateway\BancontactGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Repository\RefundHistoryRepositoryInterface; -use Payum\Core\Model\GatewayConfigInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; +use Webmozart\Assert\Assert; use Psr\Log\LoggerInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; +use Sylius\Component\Payment\PaymentTransitions; use Sylius\Component\Resource\Exception\UpdateHandlingException; use Sylius\Component\Resource\Repository\RepositoryInterface; use Sylius\RefundPlugin\Entity\RefundPayment; -use Symfony\Component\HttpFoundation\Session\Session; +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Workflow\Attribute\AsCompletedListener; +use Symfony\Component\Workflow\Event\CompletedEvent; use Symfony\Contracts\Translation\TranslatorInterface; +#[Autoconfigure(public: true)] final class RefundPaymentProcessor implements PaymentProcessorInterface { - /** @var Session */ - private $session; - - /** @var PayPlugApiClientInterface */ - private $payPlugApiClient; - - /** @var LoggerInterface */ - private $logger; - - /** @var TranslatorInterface */ - private $translator; - - /** @var RepositoryInterface */ - private $refundPaymentRepository; - - /** @var RefundHistoryRepositoryInterface */ - private $payplugRefundHistoryRepository; + private PayPlugApiClientInterface $payPlugApiClient; public function __construct( - Session $session, - PayPlugApiClientInterface $payPlugApiClient, - LoggerInterface $logger, - TranslatorInterface $translator, - RepositoryInterface $refundPaymentRepository, - RefundHistoryRepositoryInterface $payplugRefundHistoryRepository + private RequestStack $requestStack, + private LoggerInterface $logger, + private TranslatorInterface $translator, + private RepositoryInterface $refundPaymentRepository, + private RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, + private PayPlugApiClientFactoryInterface $apiClientFactory, ) { - $this->session = $session; - $this->payPlugApiClient = $payPlugApiClient; - $this->logger = $logger; - $this->translator = $translator; - $this->refundPaymentRepository = $refundPaymentRepository; - $this->payplugRefundHistoryRepository = $payplugRefundHistoryRepository; + } + + #[AsCompletedListener(workflow: PaymentTransitions::GRAPH, transition: PaymentTransitions::TRANSITION_REFUND)] + public function onRefundCompleteTransitionEvent(CompletedEvent $event): void + { + $subject = $event->getSubject(); + if (!$subject instanceof PaymentInterface) { + return; + } + + $this->process($subject); } public function process(PaymentInterface $payment): void { $this->prepare($payment); $details = $payment->getDetails(); + Assert::string($details['payment_id']); try { $this->payPlugApiClient->refundPayment($details['payment_id']); @@ -76,6 +76,7 @@ public function processWithAmount(PaymentInterface $payment, int $amount, int $r { $this->prepare($payment); $details = $payment->getDetails(); + Assert::string($details['payment_id']); try { $refund = $this->payPlugApiClient->refundPaymentWithAmount($details['payment_id'], $amount, $refundId); @@ -113,23 +114,25 @@ private function prepare(PaymentInterface $payment): void { /** @var PaymentMethodInterface $paymentMethod */ $paymentMethod = $payment->getMethod(); - $details = $payment->getDetails(); if ( !$paymentMethod->getGatewayConfig() instanceof GatewayConfigInterface || - !\in_array($paymentMethod->getGatewayConfig()->getFactoryName(), [ + !\in_array($factoryName = $paymentMethod->getGatewayConfig()->getFactoryName(), [ PayPlugGatewayFactory::FACTORY_NAME, OneyGatewayFactory::FACTORY_NAME, + BancontactGatewayFactory::FACTORY_NAME, + ApplePayGatewayFactory::FACTORY_NAME, + AmericanExpressGatewayFactory::FACTORY_NAME, ], true) ) { return; } if (!isset($details['payment_id'])) { - $this->session->getFlashBag()->add( + $this->requestStack->getSession()->getFlashBag()->add( 'info', - $this->translator->trans('payplug_sylius_payplug_plugin.ui.payment_refund_locally') + $this->translator->trans('payplug_sylius_payplug_plugin.ui.payment_refund_locally'), ); return; @@ -137,8 +140,6 @@ private function prepare(PaymentInterface $payment): void $this->logger->info('[PayPlug] Start refund payment', ['payment_id' => $details['payment_id']]); - $gatewayConfig = $paymentMethod->getGatewayConfig()->getConfig(); - - $this->payPlugApiClient->initialise($gatewayConfig['secretKey']); + $this->payPlugApiClient = $this->apiClientFactory->createForPaymentMethod($paymentMethod); } } diff --git a/src/Processor/OrderPaymentProcessor.php b/src/Processor/OrderPaymentProcessor.php new file mode 100644 index 00000000..55a8446f --- /dev/null +++ b/src/Processor/OrderPaymentProcessor.php @@ -0,0 +1,63 @@ +getLastPayment(PaymentInterface::STATE_NEW); + + if ( + null !== $payment && + PaymentInterface::STATE_COMPLETED === $payment->getDetails()['status'] && + ApplePayGatewayFactory::FACTORY_NAME === $this->getFactoryName($payment) + ) { + return; + } + + if ( + null !== $payment && + ApplePayGatewayFactory::FACTORY_NAME !== $this->getFactoryName($payment) + ) { + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, PaymentTransitions::TRANSITION_CANCEL); + } + + $this->baseOrderPaymentProcessor->process($order); + } + + private function getFactoryName(PaymentInterface $payment): string + { + /** @var PaymentMethodInterface $paymentMethod */ + $paymentMethod = $payment->getMethod(); + /** @var GatewayConfigInterface $gatewayConfig */ + $gatewayConfig = $paymentMethod->getGatewayConfig(); + + return $gatewayConfig->getFactoryName(); + } +} diff --git a/src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php b/src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php new file mode 100644 index 00000000..2336059d --- /dev/null +++ b/src/Provider/AbstractSupportedRefundPaymentMethodsProvider.php @@ -0,0 +1,88 @@ +decorated->findForOrder($order); + $request = $this->requestStack->getCurrentRequest(); + if (!$request instanceof Request || 'sylius_refund_order_refunds_list' !== $request->get('_route')) { + return $paymentMethods; + } + + return $this->find($paymentMethods, $order); + } + + protected function find(array $paymentMethods, OrderInterface $order): array + { + if ($this->isPayplugPayment($order)) { + return array_filter($paymentMethods, function (PaymentMethodInterface $paymentMethod) use ($order): bool { + $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); + if (!$lastPayment instanceof PaymentInterface) { + return false; + } + $lastPaymentMethod = $lastPayment->getMethod(); + if (!$lastPaymentMethod instanceof PaymentMethodInterface) { + return false; + } + + return $paymentMethod->getId() === $lastPaymentMethod->getId(); + }); + } + + foreach ($paymentMethods as $key => $paymentMethod) { + /** @var GatewayConfigInterface $gatewayConfig */ + $gatewayConfig = $paymentMethod->getGatewayConfig(); + + if ($this->gatewayFactoryName !== $gatewayConfig->getFactoryName()) { + continue; + } + unset($paymentMethods[$key]); + } + + return $paymentMethods; + } + + protected function isPayplugPayment(OrderInterface $order): bool + { + $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); + if (!$lastPayment instanceof PaymentInterface) { + return false; + } + + $paymentMethod = $lastPayment->getMethod(); + if (!$paymentMethod instanceof PaymentMethodInterface) { + return false; + } + + $gatewayConfig = $paymentMethod->getGatewayConfig(); + + if (!$gatewayConfig instanceof GatewayConfigInterface) { + return false; + } + + return $this->gatewayFactoryName === $gatewayConfig->getFactoryName(); + } +} diff --git a/src/Provider/AmexSupportedRefundPaymentMethodsProviderDecorator.php b/src/Provider/AmexSupportedRefundPaymentMethodsProviderDecorator.php new file mode 100644 index 00000000..1a9ee00d --- /dev/null +++ b/src/Provider/AmexSupportedRefundPaymentMethodsProviderDecorator.php @@ -0,0 +1,15 @@ +decorated = $decorated; - $this->cache = $cache; + public function __construct( + #[AutowireDecorated] + private OneySimulationDataProviderInterface $decorated, + private CacheInterface $cache, + private OneySupportedPaymentChoiceProvider $oneySupportedPaymentChoiceProvider, + ) { } public function getForCart(OrderInterface $cart): array { $country = \explode('_', $cart->getLocaleCode() ?? 'fr_FR')[1]; - $cacheKey = \sprintf('oney_simulation_%s_%s', $country, $cart->getTotal()); + $cacheKey = \sprintf( + 'oney_simulation_%s_%s_%s', + $country, + $cart->getTotal(), + $this->oneySupportedPaymentChoiceProvider->getFeesFor(), + ); return $this->cache->get($cacheKey, function (ItemInterface $item) use ($cart): array { $item->expiresAfter(new \DateInterval('P1D')); // One day of cache diff --git a/src/Provider/OneySimulation/OneySimulationDataProvider.php b/src/Provider/OneySimulation/OneySimulationDataProvider.php index babb6d8f..bab83133 100644 --- a/src/Provider/OneySimulation/OneySimulationDataProvider.php +++ b/src/Provider/OneySimulation/OneySimulationDataProvider.php @@ -6,23 +6,19 @@ use Payplug\OneySimulation; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; +use PayPlug\SyliusPayPlugPlugin\Provider\OneySupportedPaymentChoiceProvider; use Psr\Log\LoggerInterface; use Sylius\Component\Core\Model\OrderInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class OneySimulationDataProvider implements OneySimulationDataProviderInterface { - /** @var \PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface */ - private $oneyClient; - - /** @var \Psr\Log\LoggerInterface */ - private $payplugLogger; - public function __construct( - PayPlugApiClientInterface $oneyClient, - LoggerInterface $payplugLogger + #[Autowire('@payplug_sylius_payplug_plugin.api_client.oney')] + private PayPlugApiClientInterface $oneyClient, + private LoggerInterface $logger, + private OneySupportedPaymentChoiceProvider $oneySupportedPaymentChoiceProvider, ) { - $this->oneyClient = $oneyClient; - $this->payplugLogger = $payplugLogger; } public function getForCart(OrderInterface $cart): array @@ -32,19 +28,16 @@ public function getForCart(OrderInterface $cart): array $data = [ 'amount' => $cart->getTotal(), 'country' => $country, - 'operations' => [ - 'x3_with_fees', - 'x4_with_fees', - ], + 'operations' => $this->oneySupportedPaymentChoiceProvider->getSupportedPaymentChoices(), ]; - $this->payplugLogger->debug('[PayPlug] Call oney simulation with following data', $data); + $this->logger->debug('[PayPlug] Call oney simulation with following data', $data); try { $currency = $cart->getCurrencyCode(); $accountData = $this->oneyClient->getAccount(true); $simulationData = OneySimulation::getSimulations($data, $this->oneyClient->getConfiguration()); - $this->payplugLogger->debug('[PayPlug] Oney simulation response', $simulationData); + $this->logger->debug('[PayPlug] Oney simulation response', $simulationData); return \array_merge( [ @@ -52,9 +45,9 @@ public function getForCart(OrderInterface $cart): array 'min_amount' => $accountData['configuration']['oney']['min_amounts'][$currency], 'max_amount' => $accountData['configuration']['oney']['max_amounts'][$currency], ], - $simulationData + $simulationData, ); - } catch (\Exception $exception) { + } catch (\Exception) { return []; } } diff --git a/src/Provider/OneySupportedPaymentChoiceProvider.php b/src/Provider/OneySupportedPaymentChoiceProvider.php new file mode 100644 index 00000000..64309253 --- /dev/null +++ b/src/Provider/OneySupportedPaymentChoiceProvider.php @@ -0,0 +1,53 @@ +getPaymentGatewayConfig(); + + $values = OneyGatewayFactory::PAYMENT_CHOICES_FEES_FOR[$config['fees_for'] ?? OneyGatewayFactory::CLIENT_FEES]; + + if (!$useOneyPrefix) { + return $values; + } + + return array_map(fn ($data): string => 'oney_' . $data, $values); + } catch (\Exception) { + return []; + } + } + + public function getFeesFor(): string + { + return $this->getPaymentGatewayConfig()['fees_for'] ?? ''; + } + + private function getPaymentGatewayConfig(): array + { + $paymentMethod = $this->paymentMethodRepository->findOneByGatewayName(OneyGatewayFactory::FACTORY_NAME); + + if (!$paymentMethod instanceof PaymentMethodInterface) { + return []; + } + + /** @var GatewayConfigInterface $gateway */ + $gateway = $paymentMethod->getGatewayConfig(); + + return $gateway->getConfig(); + } +} diff --git a/src/Provider/OneySupportedRefundPaymentMethodsProviderDecorator.php b/src/Provider/OneySupportedRefundPaymentMethodsProviderDecorator.php index 8c691576..009729bd 100644 --- a/src/Provider/OneySupportedRefundPaymentMethodsProviderDecorator.php +++ b/src/Provider/OneySupportedRefundPaymentMethodsProviderDecorator.php @@ -5,102 +5,11 @@ namespace PayPlug\SyliusPayPlugPlugin\Provider; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; -use Sylius\Component\Core\Model\ChannelInterface; -use Sylius\Component\Core\Model\OrderInterface; -use Sylius\Component\Core\Model\PaymentInterface; -use Sylius\Component\Core\Model\PaymentMethodInterface; -use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\RefundPlugin\Provider\RefundPaymentMethodsProviderInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; -final class OneySupportedRefundPaymentMethodsProviderDecorator implements RefundPaymentMethodsProviderInterface +#[AsDecorator(SupportedRefundPaymentMethodsProviderDecorator::class)] +final class OneySupportedRefundPaymentMethodsProviderDecorator extends AbstractSupportedRefundPaymentMethodsProvider implements RefundPaymentMethodsProviderInterface { - /** @var RefundPaymentMethodsProviderInterface */ - private $decorated; - - /** @var RequestStack */ - private $requestStack; - - /** @var OrderRepositoryInterface */ - private $orderRepository; - - public function __construct( - RefundPaymentMethodsProviderInterface $decorated, - RequestStack $requestStack, - OrderRepositoryInterface $orderRepository - ) { - $this->decorated = $decorated; - $this->requestStack = $requestStack; - $this->orderRepository = $orderRepository; - } - - public function findForChannel(ChannelInterface $channel): array - { - $paymentMethods = $this->decorated->findForChannel($channel); - $request = $this->requestStack->getCurrentRequest(); - if (!$request instanceof Request || 'sylius_refund_order_refunds_list' !== $request->get('_route')) { - return $paymentMethods; - } - - /** @var OrderInterface|null $order */ - $order = $this->orderRepository->findOneByNumber($request->get('orderNumber')); - - if (!$order instanceof OrderInterface) { - return $paymentMethods; - } - - if ($this->isOneyPayment($order)) { - return array_filter($paymentMethods, function (PaymentMethodInterface $paymentMethod) use ($order): bool { - $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); - if (!$lastPayment instanceof PaymentInterface) { - return false; - } - $lastPaymentMethod = $lastPayment->getMethod(); - if (!$lastPaymentMethod instanceof PaymentMethodInterface) { - return false; - } - - return $paymentMethod->getId() === $lastPaymentMethod->getId(); - }); - } - - foreach ($paymentMethods as $key => $paymentMethod) { - /** @var GatewayConfigInterface $gatewayConfig */ - $gatewayConfig = $paymentMethod->getGatewayConfig(); - - if (OneyGatewayFactory::FACTORY_NAME !== $gatewayConfig->getFactoryName()) { - continue; - } - unset($paymentMethods[$key]); - } - - return $paymentMethods; - } - - private function isOneyPayment(OrderInterface $order): bool - { - $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); - if (!$lastPayment instanceof PaymentInterface) { - return false; - } - - $paymentMethod = $lastPayment->getMethod(); - if (!$paymentMethod instanceof PaymentMethodInterface) { - return false; - } - - $gatewayConfig = $paymentMethod->getGatewayConfig(); - - if (!$gatewayConfig instanceof GatewayConfigInterface) { - return false; - } - - if (OneyGatewayFactory::FACTORY_NAME !== $gatewayConfig->getFactoryName()) { - return false; - } - - return true; - } + protected string $gatewayFactoryName = OneyGatewayFactory::FACTORY_NAME; } diff --git a/src/Provider/Payment/ApplePayPaymentProvider.php b/src/Provider/Payment/ApplePayPaymentProvider.php new file mode 100644 index 00000000..74f9b93c --- /dev/null +++ b/src/Provider/Payment/ApplePayPaymentProvider.php @@ -0,0 +1,301 @@ +paymentMethodRepository->findOneByGatewayName(ApplePayGatewayFactory::FACTORY_NAME); + + if (!$paymentMethod instanceof PaymentMethodInterface || !$paymentMethod->isEnabled()) { + throw new LogicException('Apple Pay is not enabled'); + } + + $payment = $this->initApplePaySyliusPaymentState($order); + + Assert::notNull($order->getBillingAddress()); + if (($customer = $order->getBillingAddress()->getCustomer()) instanceof \Sylius\Component\Customer\Model\CustomerInterface) { + $order->setCustomer($customer); + } + + Assert::isInstanceOf($order->getChannel(), ChannelInterface::class); + + $paymentDataObject = $this->paymentDataCreator->create( + $payment, + [ + 'apple_pay' => [ + 'domain_name' => $order->getChannel()->getHostname(), + /* @phpstan-ignore-next-line */ + 'application_data' => \base64_encode(\json_encode([ + 'apple_pay_domain' => $order->getChannel()->getHostname(), + ])), + ], + ], + ); + + $paymentData = $paymentDataObject->getArrayCopy(); + $paymentData['notification_url'] = $this->router->generate('sylius_payment_method_notify', ['code' => $payment->getMethod()?->getCode()], RouterInterface::ABSOLUTE_URL); + $this->logger->notice('[Payplug] ApplePay payment data', ['data' => $paymentData]); + + $paymentResource = $this->applePayClient->createPayment($paymentData); + $this->logger->notice('[Payplug] ApplePay payment resource', ['payment' => (array) $paymentResource]); + + $details = $paymentData; + $details['merchant_session'] = $paymentResource->payment_method['merchant_session']; + $details['status'] = PayPlugApiClientInterface::STATUS_CREATED; + $details['payment_id'] = $paymentResource->id; + $details['is_live'] = $paymentResource->is_live; + + $payment->setDetails($details); + $this->applyRequiredPaymentTransition($payment, PaymentInterface::STATE_NEW); + $this->applyRequiredOrderPaymentTransition($order, OrderPaymentStates::STATE_AWAITING_PAYMENT); + $this->applyRequiredOrderCheckoutTransition($order, OrderCheckoutStates::STATE_COMPLETED); + $this->orderTokenAssigner->assignTokenValueIfNotSet($order); + + return $payment; + } + + public function patch(Request $request, OrderInterface $order): PaymentInterface + { + $this->logger->notice('[Payplug] ApplePay payment patch', ['order' => $order]); + $lastPayment = $order->getLastPayment(PaymentInterface::STATE_NEW); + + if (!$lastPayment instanceof PaymentInterface) { + $this->logger->error('[Payplug] No new payment found for order', ['order' => $order]); + throw new LogicException(); + } + + $paymentMethod = $lastPayment->getMethod(); + + Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class); + Assert::isInstanceOf($paymentMethod->getGatewayConfig(), GatewayConfigInterface::class); + + if (ApplePayGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName()) { + throw new LogicException(); + } + + $paymentResource = $this->applePayClient->retrieve($lastPayment->getDetails()['payment_id']); + $this->logger->notice('[Payplug] ApplePay payment resource', ['payment' => (array) $paymentResource]); + try { + $token = $request->request->all('token'); + if ([] === $token) { + $token = json_decode($request->getContent(), true)['token'] ?? null; // @phpstan-ignore-line + } + + if (null === $token) { + throw new \InvalidArgumentException('Missing token in request'); + } + + $this->logger->notice('[Payplug] ApplePay payment token', ['token' => $token]); + $data = [ + 'apple_pay' => [ + 'payment_token' => $token, + ], + 'metadata' => (array) $paymentResource->metadata, + ]; + + $this->logger->notice('[Payplug] ApplePay sending update to Payplug', ['data' => $data]); + /** @var Payment $response */ + $response = $paymentResource->update($data, $this->applePayClient->getConfiguration()); + $this->logger->notice('[Payplug] ApplePay updated response from Payplug', ['response' => (array) $response]); + + if (!$response->is_paid) { + throw new PaymentNotCompletedException(); + } + $this->logger->notice('[Payplug] ApplePay payment update response is paid', ['response' => (array) $response]); + + $details = $lastPayment->getDetails(); + $details['status'] = PaymentInterface::STATE_COMPLETED; + $details['created_at'] = $response->created_at; + + $this->applyRequiredPaymentTransition($lastPayment, PaymentInterface::STATE_COMPLETED); + + if ($this->isResourceIsAuthorized($response)) { + $details['status'] = PayPlugApiClientInterface::STATUS_AUTHORIZED; + } + + $lastPayment->setDetails($details); + + return $lastPayment; + } catch (\Exception $exception) { + $this->logger->error('[Payplug] ApplePay payment update failed', ['exception' => $exception, 'message' => $exception->getMessage()]); + $this->applyRequiredPaymentTransition($lastPayment, PaymentInterface::STATE_FAILED); + try { + $paymentResource->abort($this->applePayClient->getConfiguration()); + } catch (\Throwable $throwable) { + $this->logger->error('[Payplug] ApplePay payment abort failed', ['payment' => $lastPayment, 'exception' => $throwable]); + } + + throw new PaymentNotCompletedException(); + } + } + + public function cancel(OrderInterface $order): void + { + $lastPayment = $order->getLastPayment(PaymentInterface::STATE_NEW); + if (!$lastPayment instanceof PaymentInterface) { + $this->logger->error('[Payplug] No new payment found for order during cancel', ['order' => $order]); + + return; + } + + $paymentMethod = $lastPayment->getMethod(); + + Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class); + Assert::isInstanceOf($paymentMethod->getGatewayConfig(), GatewayConfigInterface::class); + + if (ApplePayGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName()) { + throw new LogicException(); + } + + $this->applyRequiredPaymentTransition($lastPayment, PaymentInterface::STATE_CANCELLED); + } + + /** + * @throws NotProvidedOrderPaymentException + */ + private function initApplePaySyliusPaymentState(OrderInterface $order): PaymentInterface + { + Assert::notNull($order->getCurrencyCode()); + + $payment = $this->getPayment($order); + + $paymentMethod = $this->paymentMethodRepository->findOneByGatewayName(ApplePayGatewayFactory::FACTORY_NAME); + $payment->setMethod($paymentMethod); + $order->addPayment($payment); + + return $payment; + } + + private function getPayment(OrderInterface $order): PaymentInterface + { + $lastPayment = $order->getLastPayment(); + + if ( + $lastPayment instanceof PaymentInterface && + PaymentInterface::STATE_CART === $lastPayment->getState() + ) { + return $lastPayment; + } + + if ( + $lastPayment instanceof PaymentInterface && OrderInterface::STATE_NEW === $order->getState() && + PaymentInterface::STATE_NEW === $lastPayment->getState() + ) { + return $lastPayment; + } + + Assert::string($order->getCurrencyCode()); + + /** @phpstan-ignore-next-line */ + return $this->paymentFactory->createWithAmountAndCurrencyCode($order->getTotal(), $order->getCurrencyCode()); + } + + private function applyRequiredPaymentTransition(PaymentInterface $payment, string $targetState): void + { + if ($targetState === $payment->getState()) { + return; + } + + /** @phpstan-ignore-next-line */ + $targetTransition = $this->stateMachine->getTransitionToState($payment, PaymentTransitions::GRAPH, $targetState); + + if (null !== $targetTransition) { + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $targetTransition); + } + } + + private function applyRequiredOrderPaymentTransition(OrderInterface $order, string $targetState): void + { + if ($targetState === $order->getPaymentState()) { + return; + } + + $targetTransition = $this->stateMachine->getTransitionToState($order, OrderPaymentTransitions::GRAPH, $targetState); + + if (null !== $targetTransition) { + $this->stateMachine->apply($order, OrderPaymentTransitions::GRAPH, $targetTransition); + } + } + + private function applyRequiredOrderCheckoutTransition(OrderInterface $order, string $targetState): void + { + if ($targetState === $order->getPaymentState()) { + return; + } + + $targetTransition = $this->stateMachine->getTransitionToState($order, OrderCheckoutTransitions::GRAPH, $targetState); + + if (null !== $targetTransition) { + $this->stateMachine->apply($order, OrderCheckoutTransitions::GRAPH, $targetTransition); + } + } + + private function isResourceIsAuthorized(IVerifiableAPIResource $paymentResource): bool + { + if (!$paymentResource instanceof Payment) { + return false; + } + + // Oney is reviewing the payer’s file + if ( + $paymentResource->__isset('payment_method') && + null !== $paymentResource->__get('payment_method') && + \array_key_exists('is_pending', $paymentResource->__get('payment_method')) && + true === $paymentResource->__get('payment_method')['is_pending'] + ) { + return true; + } + + $now = new DateTimeImmutable(); + + return $paymentResource->__isset('authorization') && $paymentResource->__get('authorization') instanceof PaymentAuthorization && null !== $paymentResource->__get('authorization')->__get('expires_at') && $now < $now->setTimestamp($paymentResource->__get('authorization')->__get('expires_at')); + } +} diff --git a/src/Provider/PaymentTokenProvider.php b/src/Provider/PaymentTokenProvider.php new file mode 100644 index 00000000..622cc87b --- /dev/null +++ b/src/Provider/PaymentTokenProvider.php @@ -0,0 +1,49 @@ +payum->getTokenFactory(); + + /** @var PaymentMethodInterface $paymentMethod */ + $paymentMethod = $payment->getMethod(); + /** @var GatewayConfigInterface $gatewayConfig */ + $gatewayConfig = $paymentMethod->getGatewayConfig(); + + if ( + isset($gatewayConfig->getConfig()['use_authorize']) && + true === $gatewayConfig->getConfig()['use_authorize'] + ) { + return $tokenFactory->createAuthorizeToken( + $gatewayConfig->getGatewayName(), + $payment, + $this->afterPayRoute, + ); + } + + return $tokenFactory->createCaptureToken( + $gatewayConfig->getGatewayName(), + $payment, + $this->afterPayRoute, + ); + } +} diff --git a/src/Provider/SupportedMethodsProvider.php b/src/Provider/SupportedMethodsProvider.php new file mode 100644 index 00000000..b8793187 --- /dev/null +++ b/src/Provider/SupportedMethodsProvider.php @@ -0,0 +1,54 @@ +currencyContext->getCurrencyCode(); + + foreach ($supportedMethods as $key => $paymentMethod) { + Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class); + + /** @var GatewayConfigInterface $gatewayConfig */ + $gatewayConfig = $paymentMethod->getGatewayConfig(); + + if ($factoryName !== $gatewayConfig->getFactoryName()) { + continue; + } + + if (!\array_key_exists($activeCurrencyCode, $authorizedCurrencies)) { + unset($supportedMethods[$key]); + + continue; + } + + if ( + $paymentAmount < $authorizedCurrencies[$activeCurrencyCode]['min_amount'] || + $paymentAmount > $authorizedCurrencies[$activeCurrencyCode]['max_amount'] + ) { + unset($supportedMethods[$key]); + + continue; + } + } + + return $supportedMethods; + } +} diff --git a/src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php b/src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php index b9aa5518..40095917 100644 --- a/src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php +++ b/src/Provider/SupportedRefundPaymentMethodsProviderDecorator.php @@ -5,64 +5,36 @@ namespace PayPlug\SyliusPayPlugPlugin\Provider; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; -use Sylius\Component\Core\Model\ChannelInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\RefundPlugin\Provider\RefundPaymentMethodsProviderInterface; -use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\DependencyInjection\Attribute\Autowire; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface; -final class SupportedRefundPaymentMethodsProviderDecorator implements RefundPaymentMethodsProviderInterface +#[AsDecorator('sylius_refund.provider.refund_payment_methods')] +final class SupportedRefundPaymentMethodsProviderDecorator extends AbstractSupportedRefundPaymentMethodsProvider implements RefundPaymentMethodsProviderInterface { - /** @var RefundPaymentMethodsProviderInterface */ - private $decorated; - - /** @var RequestStack */ - private $requestStack; - - /** @var OrderRepositoryInterface */ - private $orderRepository; - - /** @var FlashBagInterface */ - private $flashBag; - - /** @var array */ - private $supportedRefundGateways; + protected string $gatewayFactoryName = PayPlugGatewayFactory::FACTORY_NAME; public function __construct( + #[AutowireDecorated] RefundPaymentMethodsProviderInterface $decorated, RequestStack $requestStack, OrderRepositoryInterface $orderRepository, - FlashBagInterface $flashBag, - array $supportedRefundGateways + #[Autowire(param: 'sylius_refund.supported_gateways')] + protected array $supportedRefundGateways, ) { - $this->decorated = $decorated; - $this->requestStack = $requestStack; - $this->orderRepository = $orderRepository; - $this->flashBag = $flashBag; - $this->supportedRefundGateways = $supportedRefundGateways; + parent::__construct($decorated, $requestStack, $orderRepository); } - public function findForChannel(ChannelInterface $channel): array + protected function find(array $paymentMethods, OrderInterface $order): array { - $paymentMethods = $this->decorated->findForChannel($channel); - $request = $this->requestStack->getCurrentRequest(); - if (!$request instanceof Request || 'sylius_refund_order_refunds_list' !== $request->get('_route')) { - return $paymentMethods; - } - - /** @var OrderInterface|null $order */ - $order = $this->orderRepository->findOneByNumber($request->get('orderNumber')); - - if (!$order instanceof OrderInterface) { - return $paymentMethods; - } - - if ($this->isPayPlugPayment($order)) { + if ($this->isPayplugPayment($order)) { return array_filter($paymentMethods, function (PaymentMethodInterface $paymentMethod) use ($order): bool { $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); if (!$lastPayment instanceof PaymentInterface) { @@ -77,18 +49,20 @@ public function findForChannel(ChannelInterface $channel): array }); } - if (null !== $order->getLastPayment() && - null !== $order->getLastPayment()->getMethod() && - $order->getLastPayment()->getMethod()->getCode() === PayPlugGatewayFactory::FACTORY_NAME && - !\in_array(PayPlugGatewayFactory::FACTORY_NAME, $this->supportedRefundGateways, true)) { - $this->flashBag->add('info', 'payplug_sylius_payplug_plugin.ui.payplug_refund_gateway_is_not_activated'); + if ( + $order->getLastPayment() instanceof \Sylius\Component\Core\Model\PaymentInterface && + $order->getLastPayment()->getMethod() instanceof \Sylius\Component\Payment\Model\PaymentMethodInterface && + $this->gatewayFactoryName === $order->getLastPayment()->getMethod()->getCode() && + !\in_array($this->gatewayFactoryName, $this->supportedRefundGateways, true) + ) { + $this->requestStack->getSession()->getFlashBag()->add('info', 'payplug_sylius_payplug_plugin.ui.payplug_refund_gateway_is_not_activated'); } foreach ($paymentMethods as $key => $paymentMethod) { /** @var GatewayConfigInterface $gatewayConfig */ $gatewayConfig = $paymentMethod->getGatewayConfig(); - if (PayPlugGatewayFactory::FACTORY_NAME !== $gatewayConfig->getFactoryName()) { + if ($this->gatewayFactoryName !== $gatewayConfig->getFactoryName()) { continue; } unset($paymentMethods[$key]); @@ -96,29 +70,4 @@ public function findForChannel(ChannelInterface $channel): array return $paymentMethods; } - - private function isPayPlugPayment(OrderInterface $order): bool - { - $lastPayment = $order->getLastPayment(PaymentInterface::STATE_COMPLETED); - if (!$lastPayment instanceof PaymentInterface) { - return false; - } - - $paymentMethod = $lastPayment->getMethod(); - if (!$paymentMethod instanceof PaymentMethodInterface) { - return false; - } - - $gatewayConfig = $paymentMethod->getGatewayConfig(); - - if (!$gatewayConfig instanceof GatewayConfigInterface) { - return false; - } - - if (PayPlugGatewayFactory::FACTORY_NAME !== $gatewayConfig->getFactoryName()) { - return false; - } - - return true; - } } diff --git a/src/Repository/PaymentMethodRepository.php b/src/Repository/PaymentMethodRepository.php new file mode 100644 index 00000000..d2e12daa --- /dev/null +++ b/src/Repository/PaymentMethodRepository.php @@ -0,0 +1,23 @@ +createQueryBuilder('o') + ->innerJoin('o.gatewayConfig', 'gatewayConfig') + ->where('gatewayConfig.factoryName = :gatewayFactoryName') + ->setParameter('gatewayFactoryName', $gatewayFactoryName) + ->getQuery() + ->setMaxResults(1) + ->getSingleResult() + ; + } +} diff --git a/src/Repository/PaymentMethodRepositoryInterface.php b/src/Repository/PaymentMethodRepositoryInterface.php new file mode 100644 index 00000000..54f8c2e9 --- /dev/null +++ b/src/Repository/PaymentMethodRepositoryInterface.php @@ -0,0 +1,13 @@ +setParameter('stateProcessing', PaymentInterface::STATE_PROCESSING) ->getQuery() ->getResult() - ; + ; + } + + public function findOneByPayPlugPaymentId(string $payplugPaymentId): ?PaymentInterface + { + /** @var PaymentInterface|null */ + return $this->createQueryBuilder('o') + ->where('o.details LIKE :payplugPaymentId') + ->setParameter('payplugPaymentId', '%' . $payplugPaymentId . '%') + ->getQuery() + ->setMaxResults(1) + ->getOneOrNullResult() + ; + } + + /** + * @return array + */ + public function findAllAuthorizedOlderThanDays(int $days, ?string $gatewayFactoryName = null): array + { + if (null === $gatewayFactoryName) { + // For now, only this gateway support authorized payments + $gatewayFactoryName = PayPlugGatewayFactory::FACTORY_NAME; + } + + $date = (new \DateTime())->modify(sprintf('-%d days', $days)); + + return $this->createQueryBuilder('o') + ->innerJoin('o.method', 'method') + ->innerJoin('method.gatewayConfig', 'gatewayConfig') + ->where('o.state = :state') + ->andWhere('o.updatedAt < :date') + ->andWhere('gatewayConfig.factoryName = :factoryName') + ->setParameter('state', PaymentInterface::STATE_AUTHORIZED) + ->setParameter('factoryName', $gatewayFactoryName) + ->setParameter('date', $date) + ->getQuery() + ->getResult() + ; } } diff --git a/src/Repository/PaymentRepositoryInterface.php b/src/Repository/PaymentRepositoryInterface.php index d7ff6410..b8b783e6 100644 --- a/src/Repository/PaymentRepositoryInterface.php +++ b/src/Repository/PaymentRepositoryInterface.php @@ -4,9 +4,17 @@ namespace PayPlug\SyliusPayPlugPlugin\Repository; +use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Repository\PaymentRepositoryInterface as BasePaymentRepositoryInterface; interface PaymentRepositoryInterface extends BasePaymentRepositoryInterface { public function findAllActiveByGatewayFactoryName(string $gatewayFactoryName): array; + + public function findOneByPayPlugPaymentId(string $payplugPaymentId): ?PaymentInterface; + + /** + * @return array + */ + public function findAllAuthorizedOlderThanDays(int $days, ?string $gatewayFactoryName = null): array; } diff --git a/src/Resolver/AmericanExpressPaymentMethodsResolverDecorator.php b/src/Resolver/AmericanExpressPaymentMethodsResolverDecorator.php new file mode 100644 index 00000000..923a3eca --- /dev/null +++ b/src/Resolver/AmericanExpressPaymentMethodsResolverDecorator.php @@ -0,0 +1,43 @@ +decorated->getSupportedMethods($subject); + + return $this->supportedMethodsProvider->provide( + $supportedMethods, + AmericanExpressGatewayFactory::FACTORY_NAME, + AmericanExpressGatewayFactory::AUTHORIZED_CURRENCIES, + $subject->getAmount() ?? 0, + ); + } + + public function supports(BasePaymentInterface $subject): bool + { + return $this->decorated->supports($subject); + } +} diff --git a/src/Resolver/ApplePayPaymentMethodsResolverDecorator.php b/src/Resolver/ApplePayPaymentMethodsResolverDecorator.php new file mode 100644 index 00000000..1374a5ad --- /dev/null +++ b/src/Resolver/ApplePayPaymentMethodsResolverDecorator.php @@ -0,0 +1,43 @@ +decorated->getSupportedMethods($subject); + + return $this->supportedMethodsProvider->provide( + $supportedMethods, + ApplePayGatewayFactory::FACTORY_NAME, + ApplePayGatewayFactory::AUTHORIZED_CURRENCIES, + $subject->getAmount() ?? 0, + ); + } + + public function supports(BasePaymentInterface $subject): bool + { + return $this->decorated->supports($subject); + } +} diff --git a/src/Resolver/BancontactPaymentMethodsResolverDecorator.php b/src/Resolver/BancontactPaymentMethodsResolverDecorator.php new file mode 100644 index 00000000..22dc0c51 --- /dev/null +++ b/src/Resolver/BancontactPaymentMethodsResolverDecorator.php @@ -0,0 +1,43 @@ +decorated->getSupportedMethods($subject); + + return $this->supportedMethodsProvider->provide( + $supportedMethods, + BancontactGatewayFactory::FACTORY_NAME, + BancontactGatewayFactory::AUTHORIZED_CURRENCIES, + $subject->getAmount() ?? 0, + ); + } + + public function supports(BasePaymentInterface $subject): bool + { + return $this->decorated->supports($subject); + } +} diff --git a/src/Resolver/OneyPaymentMethodsResolverDecorator.php b/src/Resolver/OneyPaymentMethodsResolverDecorator.php index 6aba408a..e555f96e 100644 --- a/src/Resolver/OneyPaymentMethodsResolverDecorator.php +++ b/src/Resolver/OneyPaymentMethodsResolverDecorator.php @@ -6,43 +6,35 @@ use PayPlug\SyliusPayPlugPlugin\Checker\OneyCheckerInterface; use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Model\Payment; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Currency\Context\CurrencyContextInterface; use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface; use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; use Webmozart\Assert\Assert; +#[AsDecorator('sylius.resolver.payment_methods')] final class OneyPaymentMethodsResolverDecorator implements PaymentMethodsResolverInterface { - /** @var CurrencyContextInterface */ - private $currencyContext; - - /** @var PaymentMethodsResolverInterface */ - private $decorated; - - /** @var \PayPlug\SyliusPayPlugPlugin\Checker\OneyCheckerInterface */ - private $oneyChecker; - public function __construct( - PaymentMethodsResolverInterface $decorated, - CurrencyContextInterface $currencyContext, - OneyCheckerInterface $oneyChecker + #[AutowireDecorated] + private PaymentMethodsResolverInterface $decorated, + private CurrencyContextInterface $currencyContext, + private OneyCheckerInterface $oneyChecker, ) { - $this->currencyContext = $currencyContext; - $this->decorated = $decorated; - $this->oneyChecker = $oneyChecker; } - public function getSupportedMethods(BasePaymentInterface $payment): array + public function getSupportedMethods(BasePaymentInterface $subject): array { - Assert::isInstanceOf($payment, Payment::class); - $supportedMethods = $this->decorated->getSupportedMethods($payment); + Assert::isInstanceOf($subject, Payment::class); + $supportedMethods = $this->decorated->getSupportedMethods($subject); /** @var OrderInterface $order */ - $order = $payment->getOrder(); + $order = $subject->getOrder(); $activeCurrencyCode = $this->currencyContext->getCurrencyCode(); @@ -64,10 +56,12 @@ public function getSupportedMethods(BasePaymentInterface $payment): array $countryCodeBilling = $order->getBillingAddress()->getCountryCode(); } - if (!$this->oneyChecker->isEnabled() || - !$this->oneyChecker->isPriceEligible($payment->getAmount() ?? 0, $activeCurrencyCode) || + if ( + !$this->oneyChecker->isEnabled() || + !$this->oneyChecker->isPriceEligible($subject->getAmount() ?? 0, $activeCurrencyCode) || !$this->oneyChecker->isNumberOfProductEligible($order->getItemUnits()->count()) || - !$this->oneyChecker->isCountryEligible($countryCodeShipping, $countryCodeBilling)) { + !$this->oneyChecker->isCountryEligible($countryCodeShipping, $countryCodeBilling) + ) { unset($supportedMethods[$key]); } } @@ -75,8 +69,8 @@ public function getSupportedMethods(BasePaymentInterface $payment): array return $supportedMethods; } - public function supports(BasePaymentInterface $payment): bool + public function supports(BasePaymentInterface $subject): bool { - return $this->decorated->supports($payment); + return $this->decorated->supports($subject); } } diff --git a/src/Resolver/PayPlugPaymentMethodsResolverDecorator.php b/src/Resolver/PayPlugPaymentMethodsResolverDecorator.php index 0631720f..38818645 100644 --- a/src/Resolver/PayPlugPaymentMethodsResolverDecorator.php +++ b/src/Resolver/PayPlugPaymentMethodsResolverDecorator.php @@ -5,67 +5,39 @@ namespace PayPlug\SyliusPayPlugPlugin\Resolver; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; +use PayPlug\SyliusPayPlugPlugin\Provider\SupportedMethodsProvider; use Sylius\Component\Core\Model\Payment; -use Sylius\Component\Core\Model\PaymentMethodInterface; -use Sylius\Component\Currency\Context\CurrencyContextInterface; use Sylius\Component\Payment\Model\PaymentInterface as BasePaymentInterface; use Sylius\Component\Payment\Resolver\PaymentMethodsResolverInterface; +use Symfony\Component\DependencyInjection\Attribute\AsDecorator; +use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated; use Webmozart\Assert\Assert; +#[AsDecorator('sylius.resolver.payment_methods')] final class PayPlugPaymentMethodsResolverDecorator implements PaymentMethodsResolverInterface { - /** @var CurrencyContextInterface */ - private $currencyContext; - - /** @var PaymentMethodsResolverInterface */ - private $decorated; - public function __construct( - CurrencyContextInterface $currencyContext, - PaymentMethodsResolverInterface $decorated + #[AutowireDecorated] + private PaymentMethodsResolverInterface $decorated, + private SupportedMethodsProvider $supportedMethodsProvider, ) { - $this->currencyContext = $currencyContext; - $this->decorated = $decorated; } - public function getSupportedMethods(BasePaymentInterface $payment): array + public function getSupportedMethods(BasePaymentInterface $subject): array { - Assert::isInstanceOf($payment, Payment::class); - $supportedMethods = $this->decorated->getSupportedMethods($payment); - - $activeCurrencyCode = $this->currencyContext->getCurrencyCode(); - - foreach ($supportedMethods as $key => $paymentMethod) { - Assert::isInstanceOf($paymentMethod, PaymentMethodInterface::class); - - /** @var GatewayConfigInterface $gatewayConfig */ - $gatewayConfig = $paymentMethod->getGatewayConfig(); - - if (PayPlugGatewayFactory::FACTORY_NAME !== $gatewayConfig->getFactoryName()) { - continue; - } - - if (!\array_key_exists($activeCurrencyCode, PayPlugGatewayFactory::AUTHORIZED_CURRENCIES)) { - unset($supportedMethods[$key]); - - continue; - } - - if ($payment->getAmount() < PayPlugGatewayFactory::AUTHORIZED_CURRENCIES[$activeCurrencyCode]['min_amount'] - || $payment->getAmount() > PayPlugGatewayFactory::AUTHORIZED_CURRENCIES[$activeCurrencyCode]['max_amount'] - ) { - unset($supportedMethods[$key]); - - continue; - } - } - - return $supportedMethods; + Assert::isInstanceOf($subject, Payment::class); + $supportedMethods = $this->decorated->getSupportedMethods($subject); + + return $this->supportedMethodsProvider->provide( + $supportedMethods, + PayPlugGatewayFactory::FACTORY_NAME, + PayPlugGatewayFactory::AUTHORIZED_CURRENCIES, + $subject->getAmount() ?? 0, + ); } - public function supports(BasePaymentInterface $payment): bool + public function supports(BasePaymentInterface $subject): bool { - return $this->decorated->supports($payment); + return $this->decorated->supports($subject); } } diff --git a/src/Resolver/PaymentStateResolver.php b/src/Resolver/PaymentStateResolver.php index 2fc65bd6..1b338106 100644 --- a/src/Resolver/PaymentStateResolver.php +++ b/src/Resolver/PaymentStateResolver.php @@ -5,34 +5,25 @@ namespace PayPlug\SyliusPayPlugPlugin\Resolver; use Doctrine\ORM\EntityManagerInterface; +use Payplug\Resource\Payment; +use Payplug\Resource\PaymentAuthorization; +use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientFactory; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use Payum\Core\Model\GatewayConfigInterface; -use SM\Factory\FactoryInterface; -use SM\StateMachine\StateMachineInterface; +use Sylius\Component\Payment\Model\GatewayConfigInterface; +use Sylius\Abstraction\StateMachine\StateMachineInterface; use Sylius\Component\Core\Model\PaymentInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Sylius\Component\Payment\PaymentTransitions; +use Symfony\Component\DependencyInjection\Attribute\Autowire; final class PaymentStateResolver implements PaymentStateResolverInterface { - /** @var FactoryInterface */ - private $stateMachineFactory; - - /** @var PayPlugApiClientInterface */ - private $payPlugApiClient; - - /** @var EntityManagerInterface */ - private $paymentEntityManager; - public function __construct( - FactoryInterface $stateMachineFactory, - PayPlugApiClientInterface $payPlugApiClient, - EntityManagerInterface $paymentEntityManager + private StateMachineInterface $stateMachine, + private PayPlugApiClientFactory $payPlugApiClientFactory, + private EntityManagerInterface $paymentEntityManager, ) { - $this->stateMachineFactory = $stateMachineFactory; - $this->payPlugApiClient = $payPlugApiClient; - $this->paymentEntityManager = $paymentEntityManager; } public function resolve(PaymentInterface $payment): void @@ -40,45 +31,52 @@ public function resolve(PaymentInterface $payment): void /** @var PaymentMethodInterface $paymentMethod */ $paymentMethod = $payment->getMethod(); - if (!$paymentMethod->getGatewayConfig() instanceof GatewayConfigInterface || - PayPlugGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName()) { + if ( + !$paymentMethod->getGatewayConfig() instanceof GatewayConfigInterface || + PayPlugGatewayFactory::FACTORY_NAME !== $paymentMethod->getGatewayConfig()->getFactoryName() + ) { return; } $details = $payment->getDetails(); - if (!isset($details['payment_id'])) { return; } - $gatewayConfig = $paymentMethod->getGatewayConfig()->getConfig(); - - $this->payPlugApiClient->initialise($gatewayConfig['secretKey']); - - $paymentStateMachine = $this->stateMachineFactory->get($payment, PaymentTransitions::GRAPH); - - $payment = $this->payPlugApiClient->retrieve((string) $details['payment_id']); + $payplugApiClient = $this->payPlugApiClientFactory->createForPaymentMethod($paymentMethod); + $payment = $payplugApiClient->retrieve((string) $details['payment_id']); switch (true) { case $payment->is_paid: - $this->applyTransition($paymentStateMachine, PaymentTransitions::TRANSITION_COMPLETE); + $this->applyTransition($payment, PaymentTransitions::TRANSITION_COMPLETE); break; case null !== $payment->failure: - $this->applyTransition($paymentStateMachine, PaymentTransitions::TRANSITION_FAIL); + $this->applyTransition($payment, PaymentTransitions::TRANSITION_FAIL); + + break; + case $this->isAuthorized($payment): + $this->applyTransition($payment, PaymentTransitions::TRANSITION_AUTHORIZE); break; default: - $this->applyTransition($paymentStateMachine, PaymentTransitions::TRANSITION_PROCESS); + $this->applyTransition($payment, PaymentTransitions::TRANSITION_PROCESS); } $this->paymentEntityManager->flush(); } - private function applyTransition(StateMachineInterface $paymentStateMachine, string $transition): void + private function applyTransition(Payment $payment, string $transition): void { - if ($paymentStateMachine->can($transition)) { - $paymentStateMachine->apply($transition); + if ($this->stateMachine->can($payment, PaymentTransitions::GRAPH, $transition)) { + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $transition); } } + + private function isAuthorized(Payment $payment): bool + { + $now = new \DateTimeImmutable(); + + return $payment->__isset('authorization') && $payment->__get('authorization') instanceof PaymentAuthorization && null !== $payment->__get('authorization')->__get('expires_at') && $now < $now->setTimestamp($payment->__get('authorization')->__get('expires_at')); + } } diff --git a/src/Resources/config/routing.yaml b/src/Resources/config/routing.yaml deleted file mode 100644 index 88d261f0..00000000 --- a/src/Resources/config/routing.yaml +++ /dev/null @@ -1,46 +0,0 @@ -sylius_refund_complete_refund_payment: - path: /%sylius_admin.path_name%/orders/{orderNumber}/refund-payments/{id}/complete - methods: [POST] - defaults: - _controller: PayPlug\SyliusPayPlugPlugin\Action\Admin\CompleteRefundPaymentAction - -sylius_refund_refund_units: - path: /%sylius_admin.path_name%/orders/{orderNumber}/refund-units - defaults: - _controller: PayPlug\SyliusPayPlugPlugin\Action\Admin\RefundUnitsAction - -payplug_sylius_oney_complete_info: - path: /{_locale}/payplug/oney_complete_info - methods: ['GET', 'POST'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\CompleteInfoController' - -payplug_sylius_oney_simulation_popin: - path: /{_locale}/payplug/oney_popin - methods: ['GET'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\OneySimulationPopin' - -payplug_sylius_oney_is_product_eligible: - path: /{_locale}/payplug/oney/is-product-eligible - methods: ['GET'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\OneyIsProductEligible' - -payplug_sylius_card_account_index: - path: /{_locale}/account/saved-cards - methods: ['GET'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\CardController::indexAction' - -payplug_sylius_card_account_delete: - path: /{_locale}/account/saved-cards/delete/{id} - methods: ['DELETE'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\CardController::deleteAction' - -payplug_sylius_oneclick_verification: - path: /{_locale}/payment/capture/{payum_token}/1-click-checkup - methods: ['GET'] - defaults: - _controller: 'PayPlug\SyliusPayPlugPlugin\Controller\OneClickAction' diff --git a/src/Resources/config/services.xml b/src/Resources/config/services.xml deleted file mode 100644 index fe038eab..00000000 --- a/src/Resources/config/services.xml +++ /dev/null @@ -1,184 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - %sylius_refund.supported_gateways% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Resources/config/services/action.xml b/src/Resources/config/services/action.xml deleted file mode 100644 index e57ef431..00000000 --- a/src/Resources/config/services/action.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Resources/config/services/client.xml b/src/Resources/config/services/client.xml deleted file mode 100644 index 2a361f1d..00000000 --- a/src/Resources/config/services/client.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - payplug - - - - - payplug_oney - - - diff --git a/src/Resources/config/services/gateway.xml b/src/Resources/config/services/gateway.xml deleted file mode 100644 index 593b8bb3..00000000 --- a/src/Resources/config/services/gateway.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory - - - - - - - - - - PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Resources/config/services/no_defaults.xml b/src/Resources/config/services/no_defaults.xml deleted file mode 100644 index 713f1c0e..00000000 --- a/src/Resources/config/services/no_defaults.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/src/Resources/config/state_machine.yml b/src/Resources/config/state_machine.yml deleted file mode 100644 index 2181757b..00000000 --- a/src/Resources/config/state_machine.yml +++ /dev/null @@ -1,3 +0,0 @@ -imports: - - { resource: "state_machine/sylius_payment.yml" } - - { resource: "state_machine/sylius_order_payment.yaml" } diff --git a/src/Resources/config/state_machine/sylius_order_payment.yaml b/src/Resources/config/state_machine/sylius_order_payment.yaml deleted file mode 100644 index 9daf1f00..00000000 --- a/src/Resources/config/state_machine/sylius_order_payment.yaml +++ /dev/null @@ -1,51 +0,0 @@ -winzou_state_machine: - payplug_sylius_order_payment: - class: "%sylius.model.order.class%" - property_path: paymentState - graph: payplug_sylius_order_payment - state_machine_class: "%sylius.state_machine.class%" - states: - cart: ~ - awaiting_payment: ~ - partially_authorized: ~ - authorized: ~ - partially_paid: ~ - cancelled: ~ - paid: ~ - partially_refunded: ~ - refunded: ~ - transitions: - request_payment: - from: [ cart, authorized ] - to: awaiting_payment - partially_authorize: - from: [ awaiting_payment, partially_authorized ] - to: partially_authorized - authorize: - from: [ awaiting_payment, partially_authorized ] - to: authorized - partially_pay: - from: [ awaiting_payment, partially_paid, partially_authorized ] - to: partially_paid - cancel: - from: [ awaiting_payment, authorized, partially_authorized ] - to: cancelled - pay: - from: [ awaiting_payment, partially_paid, authorized ] - to: paid - partially_refund: - from: [ paid, partially_paid, partially_refunded ] - to: partially_refunded - refund: - from: [ paid, partially_paid, partially_refunded ] - to: refunded - callbacks: - after: - sylius_order_paid: - on: [ "pay" ] - do: [ "@sylius.inventory.order_inventory_operator", "sell" ] - args: [ "object" ] - sylius_resolve_state: - on: [ "pay" ] - do: [ "@sylius.state_resolver.order", "resolve" ] - args: [ "object" ] diff --git a/src/Resources/config/state_machine/sylius_payment.yml b/src/Resources/config/state_machine/sylius_payment.yml deleted file mode 100644 index 89b339f4..00000000 --- a/src/Resources/config/state_machine/sylius_payment.yml +++ /dev/null @@ -1,8 +0,0 @@ -winzou_state_machine: - sylius_payment: - callbacks: - before: - payplug_sylius_payplug_plugin_refund_process: - on: ["refund"] - do: ["@payplug_sylius_payplug_plugin.payment_processing.refund", "process"] - args: ["object"] diff --git a/src/Resources/config/ui.yaml b/src/Resources/config/ui.yaml deleted file mode 100644 index 7596cba1..00000000 --- a/src/Resources/config/ui.yaml +++ /dev/null @@ -1,51 +0,0 @@ -sylius_ui: - events: - sylius.shop.product.show.right_sidebar: - blocks: - pay_with_oney: - template: '@PayPlugSyliusPayPlugPlugin/oney/product/pay_with_oney.html.twig' - priority: 29 # After price widget - context: - legacy_event: 'sonata.block.event.sylius.shop.product.show.after_price' - sylius.shop.cart.summary.totals: - blocks: - pay_with_oney: - template: '@PayPlugSyliusPayPlugPlugin/oney/cart/pay_with_oney.html.twig' - sylius.shop.layout.javascripts: - blocks: - webfontloader: - template: '@PayPlugSyliusPayPlugPlugin/javascripts/webfont_loader.html.twig' - oney_common: - template: '@PayPlugSyliusPayPlugPlugin/javascripts/oney_common.html.twig' - sylius.shop.layout.stylesheets: - blocks: - oney_common: - template: '@PayPlugSyliusPayPlugPlugin/stylesheets/oney_common.html.twig' - sylius.shop.account.saved_cards.index.header.content: - blocks: - legacy: - template: "@SyliusUi/Block/_legacySonataEvent.html.twig" - context: - event: sylius.shop.account.saved_cards.index.header - sylius.shop.account.saved_cards.layout.stylesheets: - blocks: - saved_cards: - template: '@PayPlugSyliusPayPlugPlugin/stylesheets/saved_cards.html.twig' - sylius.shop.account.saved_cards.index.subcontent: - blocks: - header: - template: '@SyliusShop/Account/SavedCards/Index/_header.html.twig' - priority: 20 - after_content_header_legacy: - template: "@SyliusUi/Block/_legacySonataEvent.html.twig" - priority: 15 - context: - event: sylius.shop.account.order.index.after_content_header - subcontent: - template: "@SyliusShop/Account/SavedCards/Index/_subcontent.html.twig" - priority: 10 - after_grid_legacy: - template: "@SyliusUi/Block/_legacySonataEvent.html.twig" - priority: 5 - context: - event: sylius.shop.account.order.index.after_grid diff --git a/src/Resources/dev/.babelrc b/src/Resources/dev/.babelrc deleted file mode 100644 index 1320b9a3..00000000 --- a/src/Resources/dev/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env"] -} diff --git a/src/Resources/dev/package.json b/src/Resources/dev/package.json deleted file mode 100644 index 35ffdc1c..00000000 --- a/src/Resources/dev/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "sylius-payplug-plugin", - "version": "1.3.0", - "description": "Sylius Payplug Plugin", - "source": "src/index.js", - "scripts": { - "build": "parcel build pages/**/* --dist-dir ../public/assets/oney --no-source-maps", - "dev": "parcel watch pages/**/* --dist-dir ../public/assets/oney --no-hmr", - "eslint": "eslint -c .eslintrc ./", - "fix-eslint": "eslint -c .eslintrc ./ --fix", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "license": "MIT", - "browserslist": [ - "> 2%", - "last 4 versions", - "ie > 8", - "not dead", - "not op_mob 59" - ], - "devDependencies": { - "@babel/core": "^7.9.0", - "@babel/eslint-parser": "^7.14.7", - "@babel/preset-env": "^7.9.5", - "@parcel/transformer-sass": "^2.0.0-rc.0", - "eslint": "^6.8.0", - "eslint-config-prettier": "^6.10.1", - "eslint-plugin-prettier": "^3.1.3", - "parcel": "^2.0.0-rc.0", - "prettier": "^2.0.4", - "sass": "^1.26.3" - }, - "dependencies": { - "jquery": "^3.5.1" - } -} diff --git a/src/Resources/dev/pages/account/index.scss b/src/Resources/dev/pages/account/index.scss deleted file mode 100644 index 444367f6..00000000 --- a/src/Resources/dev/pages/account/index.scss +++ /dev/null @@ -1,105 +0,0 @@ -@import "../../settings/constants.scss"; - -.sylius-customer-account-saved-cards-grid { - .ui { - &.table { - td { - span { - &.expired { - color: $red; - } - } - } - } - } -} - - -@media screen and (max-width: 767px) { - .ui { - &.segment { - &.sylius-customer-account-saved-cards-grid { - -webkit-box-shadow: none; - box-shadow: none; - background: none; - border: 0; - padding: 0; - } - } - - &.basic { - &.table { - tbody { - tr { - position: relative; - background: #fff; - -webkit-box-shadow: 0 1px 2px 0 rgb(34, 36, 38, 0.15) !important; - box-shadow: 0 1px 2px 0 rgb(34, 36, 38, 0.15) !important; - margin: 1rem 0 2rem 0; - padding: 1em; - border-radius: .28571429rem; - border: 1px solid rgba($darkgrey, 0.26); - - &:first-child { - margin-top: 0; - } - - &:last-child { - margin-bottom: 0; - } - } - } - } - } - } - - .sylius-customer-account-saved-cards-grid { - .ui { - &.table { - td { - &:before { - content: attr(data-label); - float: left; - font-weight: bold; - } - - &[data-label] { - > span { - margin-left: 3px; - } - } - } - - &:not(.unstackable) { - thead { - border: none; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; - } - - tr { - > td { - display: block; - font-weight: normal; - - &.actions { - text-align: right; - margin-top: 1rem; - } - } - - > th, - > td { - padding: 0 !important; - } - } - } - } - } - } -} diff --git a/src/Resources/dev/pages/cart/index.js b/src/Resources/dev/pages/cart/index.js deleted file mode 100644 index 36e2733d..00000000 --- a/src/Resources/dev/pages/cart/index.js +++ /dev/null @@ -1,11 +0,0 @@ -const Cart = { - init() { - Cart.position(); - }, - position() { - let el = $(".oney-info"); - el.next().insertBefore(el); - }, -}; - -document.addEventListener("DOMContentLoaded", Cart.init, false); diff --git a/src/Resources/dev/pages/common/index.js b/src/Resources/dev/pages/common/index.js deleted file mode 100644 index d4046a0b..00000000 --- a/src/Resources/dev/pages/common/index.js +++ /dev/null @@ -1,5 +0,0 @@ -WebFont.load({ - google: { - families: ["Poppins:400,600"], - }, -}); diff --git a/src/Resources/dev/pages/common/index.scss b/src/Resources/dev/pages/common/index.scss deleted file mode 100644 index 6c9e68ab..00000000 --- a/src/Resources/dev/pages/common/index.scss +++ /dev/null @@ -1,42 +0,0 @@ -@import "../../settings/constants.scss"; - -[class*=oney] * { - font: { - family: Poppins, Arial, sans-serif; - } - - line-height: 1.25; - - p { - color: $greyish; - margin: 0; - } - - small { - font: { - size: 90%; - } - } -} - -.oney-info { - position: relative; - display: inline-block; - margin: 1em auto .5em; - - span { - vertical-align: text-bottom; - text-transform: uppercase; - font-size: 16px; - } - - > img { - cursor: pointer; - vertical-align: middle; - margin: 0 4px; - } - - &.loading { - pointer-events: none; - } -} diff --git a/src/Resources/dev/pages/payment/index.js b/src/Resources/dev/pages/payment/index.js deleted file mode 100644 index a49e0402..00000000 --- a/src/Resources/dev/pages/payment/index.js +++ /dev/null @@ -1,131 +0,0 @@ -const Payment = { - options: { - trigger: ".payment-method-choice", - completeInfo: { - modal: ".oney-complete-info-popin", - area: ".ui.steps + .ui.grid", - }, - }, - init(options) { - if (typeof options === "undefined") { - options = this.options; - } - this.options = $.extend(true, {}, options); - Payment.toggleGateway(); - if (typeof completeInfoRoute !== "undefined") { - Payment.modalAppear(); - } - Payment.tabs(); - $(window).on("resize", () => { - setTimeout(Payment.tabs, 100); - }); - Payment.tabsHandler(); - }, - toggleGateway() { - const paymentMethodInputId = $(this.options.trigger).data("payment-input-id"); - const checkedPaymentMethodInput = $(`#${paymentMethodInputId}:checked`); - if (checkedPaymentMethodInput.length) { - $(`.payment-method-choice[data-payment-input-id="${paymentMethodInputId}"]`).show(); - } - $("input[id*=sylius_checkout_select_payment]").on("change", (event) => { - const clickedPaymentMethodId = $(event.currentTarget).attr("id"); - $(".payment-method-choice").slideUp(); - $(`.payment-method-choice[data-payment-input-id="${clickedPaymentMethodId}"]`).slideDown(); - }); - }, - tabs() { - if (window.innerWidth <= 991) { - $(".oney-payment-choice__item").hide(); - setTimeout(() => { - $.each($(".oney-payment-choice__input"), (k, el) => { - if ($(el).is(":checked")) { - $(el).parent().show(); - $(`a.tablink[data-id=${$(el).val()}]`).addClass("active"); - } - }); - }, 1); - } else { - $(".oney-payment-choice__item").show(); - $("a.tablink").removeClass("active"); - } - }, - tabsHandler() { - $.each($("a.tablink"), (k, el) => { - $(el).click(function (evt) { - $("a.tablink").removeClass("active"); - $(this).addClass("active"); - $(".oney-payment-choice__item").hide(); - $(`#${$(this).data("id")}`).show(); - $(`input[value=${$(this).data("id")}`).prop("checked", true); - }); - }); - }, - modalAppear() { - const self = this; - let path = completeInfoRoute; - $.get(path).then((data) => { - $("body .pusher").append("
"); - $(self.options.completeInfo.area).addClass("inactive"); - $(self.options.completeInfo.area).parent().append(data); - self.modalEvents(); - }); - }, - modalFadeaway() { - $(this.options.completeInfo.modal).fadeOut(300, () => { - $(this.options.completeInfo.area).removeClass("inactive"); - $(".overlay").hide(); - }); - }, - modalSubmit(evt) { - const self = this; - evt.preventDefault(); - $(evt.currentTarget).addClass("loading"); - - $.ajax({ - method: "post", - url: completeInfoRoute, - data: $(evt.currentTarget).serialize(), - success: function (res) { - if (Array.isArray(res)) { - $(`${self.options.completeInfo.modal}__content`).fadeOut(() => { - $(`${self.options.completeInfo.modal}__success`).show(); - }); - setTimeout(() => { - self.modalFadeaway(); - }, 2500); - } else { - $(self.options.completeInfo.modal).html(res); - } - self.modalEvents(); - }, - error: function (res) { - console.log(res); - }, - }); - }, - modalEvents() { - $(".close").on("click", () => { - this.modalFadeaway(); - }); - $("form[name=form]").on("submit", (e) => { - this.modalSubmit(e); - }); - }, -}; - -const onDocumentLoad = function (event) { - Payment.init(); - - $('form[name="sylius_checkout_select_payment"] button[type="submit"]').on("click", (event) => { - if ($(".checkbox-oney :radio:checked").length) { - $(".checkbox-payplug").closest(".payment-item").find(".payment-choice__input:checked").prop("checked", false); - } else if ($(".checkbox-payplug :radio:checked").length) { - $(".checkbox-oney").closest(".payment-item").find(".payment-choice__input:checked").prop("checked", false); - } - - $("input#payplug_choice_card_other").attr("disabled", true); - $('form[name="sylius_checkout_select_payment"]').submit(); - }); -}; - -document.addEventListener("DOMContentLoaded", onDocumentLoad, false); diff --git a/src/Resources/dev/pages/payment/index.scss b/src/Resources/dev/pages/payment/index.scss deleted file mode 100644 index 85d3e987..00000000 --- a/src/Resources/dev/pages/payment/index.scss +++ /dev/null @@ -1,281 +0,0 @@ -@import "../../settings/constants.scss"; - -.oney-payment-choice, -.payplug-payment-choice { - display: none; - - &__container { - display: flex; - margin: 1rem 0; - } - - &__header { - p { - margin: .5em 0 !important; - color: $black; - } - } - - &__item { - flex: 1 1 auto; - - &--oney_x3_with_fees { - margin-right: 1em; - } - - input { - display: none; - - &:checked + label { - border-color: $green; - background-color: transparentize($green, .87); - - &.payplug-payment-choice__label { - border-color: $paypluggreen; - background-color: transparentize($paypluggreen, .87) - } - } - } - - label { - width: 100%; - height: 100%; - cursor: pointer; - position: relative; - display: flex; - flex-direction: column; - border: 1px solid $lightgrey; - box-shadow: 0 1px 2px 0 transparentize($darkgrey, .85); - padding: 1em 1em; - border-radius: .28571429rem; - transition: border-color, background-color 300ms ease-in-out; - - img { - vertical-align: text-bottom; - } - } - } - - &__content { - display: contents; - - p { - color: $black; - display: flex; - flex-wrap: wrap; - justify-content: space-between; - border-bottom: 1px solid $lightgrey; - margin: 0 !important; - padding: .75rem 0 !important; - - &:nth-last-of-type(2) { - margin-bottom: 1rem !important; - } - - &:last-of-type { - margin-top: auto !important; - border: none; - margin-bottom: 0 !important; - } - } - - small { - margin-top: .5rem; - font: { - size: 80%; - } - } - } -} - -.oney-payment-choice { - &__tab { - display: none; - } - - &__header { - margin: 0 auto; - text-align: center; - } -} - -.payplug-payment-choice { - &__container { - flex-direction: column; - } - - &__item { - margin-bottom: 1em; - } - - &__header { - display: flex; - justify-content: space-between; - align-items: center; - - .card-expiry span { - font-weight: 700; - } - } -} - -.oney-complete-info-popin { - position: fixed !important; - margin: auto !important; - text-align: center; - left: 0; - right: 0; - top: 50%; - transform: translateY(-50%); - max-width: 480px; - z-index: 4; - - &__header { - text-align: right; - - a.close { - > span { - position: absolute; - width: 15px; - height: 2px; - right: .5em; - top: 1em; - margin: 0; - border-radius: 0; - background-color: transparentize($black, .95); - - &:first-of-type { - transform: rotate(45deg); - } - - &:last-of-type { - transform: rotate(-45deg); - - } - } - } - } - - &__content { - text-align: left; - - ul { - list-style: none; - padding: 0; - - li { - display: inline-block; - margin: 0 .14285714em; - padding: .5833em .833em; - font-weight: 700; - border-radius: .28571429rem; - background-color: $red; - border-color: $red; - color: $white; - font-size: .85714286rem; - } - } - } - - &__success { - display: none; - - i.icon { - display: inline-block !important; - color: $neongreen; - } - } -} - -.ui.container { - position: relative; -} - -.inactive { - pointer-events: none; -} - -.overlay { - width: 100%; - height: 100%; - position: absolute; - display: block; - background: transparentize($black, .75); - z-index: 3; -} - -@media screen and (max-width: 991px) { - .oney-payment-choice, - .payplug-payment-choice { - &__container { - display: block; - } - - &__content { - small { - width: 100%; - } - } - } - - .oney-payment-choice { - &__tab { - display: flex; - justify-content: space-between; - - .tablink { - padding: 1rem 0; - flex: 1; - text-align: center; - border: 1px solid $lightgrey; - border-bottom: 0; - - &.active { - border-bottom: 5px solid $green; - } - - p { - color: $black; - } - - &:first-of-type { - border-right: 0; - } - } - } - - &__header { - display: none; - } - - &__item { - display: none; - - input:checked + label { - border-color: $lightgrey; - background-color: $white; - } - - label { - border-top-right-radius: 0; - border-top-left-radius: 0; - } - - &--oney_x3_with_fees { - margin-bottom: 1rem; - margin-right: 0; - display: block; - } - } - } -} - -@media screen and (max-width: 480px) { - .payplug-payment-choice { - &__header, - &__header .card-type, - &__header .card-expiry { - display: block; - } - } -} diff --git a/src/Resources/dev/pages/popin/index.js b/src/Resources/dev/pages/popin/index.js deleted file mode 100644 index ed4cd010..00000000 --- a/src/Resources/dev/pages/popin/index.js +++ /dev/null @@ -1,148 +0,0 @@ -const Popin = { - handlers: { - info: ".oney-info", - popin: ".oney-popin", - codes: "#payplug-product-variant-codes", - }, - triggers: { - option: "cartItem_variant", - quantity: "cartItem_quantity", - }, - productMeta: [], - storage: [], - init() { - if (typeof productMeta !== "undefined") { - Popin.watch(); - } - Popin.fade(); - Popin.closeHandler(); - }, - watch() { - for (const prop in this.triggers) { - const $selectors = $(`[id*=${this.triggers[prop]}`); - if ($selectors.length > 0) { - this.handleProductOptionsChange($selectors, prop); - } - productMeta[prop] = $selectors.val(); - $selectors.on( - "input", - this.debounce((e) => { - e.preventDefault(); - if ($selectors.length > 0) { - this.handleProductOptionsChange($selectors, prop); - } - productMeta[prop] = $(e.currentTarget).val(); - this.check(); - }, 500) - ); - } - this.productMeta = productMeta; - }, - /** - * @see Sylius/Bundle/ShopBundle/Resources/private/js/sylius-variants-prices.js - * @param $selectors - * @param prop - */ - handleProductOptionsChange($selectors, prop) { - if (prop === "option") { - let selector = ""; - $selectors.each((k, v) => { - const select = $(v); - const option = select.find("option:selected").val(); - selector += `[data-${select.attr("data-option")}="${option}"]`; - }); - return (productMeta.product_variant_code = $(this.handlers.codes).find(selector).attr("data-value")); - } - }, - check() { - const self = this; - this.storage = []; - $.ajax({ - url: this.productMeta.url, - data: this.productMeta, - success: function (res) { - $(self.handlers.info).find("img:first").attr("src", self.productMeta.img[res.isEligible]); - res.isEligible - ? $(self.handlers.popin).removeClass("disabled").addClass("enabled") - : $(self.handlers.popin).removeClass("enabled").addClass("disabled"); - }, - }); - }, - /** - * https://davidwalsh.name/javascript-debounce-function - */ - debounce(func, wait) { - let timeout; - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }, - fade() { - $(this.handlers.info).on("click", (e) => { - e.preventDefault(); - e.stopPropagation(); - if (!$(this.handlers.popin).is(":empty") && $(this.handlers.popin).text().trim() === this.storage) { - $(this.handlers.popin).fadeIn(); - return; - } - // content not loaded yet - this.toggleLoader(); - this.load(); - }); - }, - load() { - const self = this; - $.ajax({ - url: $(this.handlers.popin).data("popin-url"), - data: this.productMeta, - success: function (res) { - if (res.includes(translations.reason)) { - $(self.handlers.popin).removeClass("enabled").addClass("disabled"); - } - self.storage = $(res).text().trim(); - $(self.handlers.popin).html(res); - }, - error: function () { - $(self.handlers.popin).removeClass("enabled").addClass("disabled").html(` -
- - - -
-
-

${translations.reason}

-
- `); - }, - complete: function () { - self.toggleLoader(); - $(self.handlers.popin).fadeIn(); - Popin.closeHandler(); - }, - }); - }, - toggleLoader() { - $(this.handlers.info).toggleClass("loading").find(".dimmer").toggleClass("active"); - }, - closeHandler() { - $("html") - .not(this.handlers.popin) - .on("click", (e) => { - e.stopPropagation(); - $(this.handlers.popin).fadeOut(); - }); - $(this.handlers.popin) - .find("a.close") - .on("click", (e) => { - e.stopPropagation(); - $(this.handlers.popin).fadeOut(); - }); - }, -}; - -document.addEventListener("DOMContentLoaded", Popin.init, false); diff --git a/src/Resources/dev/pages/popin/index.scss b/src/Resources/dev/pages/popin/index.scss deleted file mode 100644 index 240d9389..00000000 --- a/src/Resources/dev/pages/popin/index.scss +++ /dev/null @@ -1,161 +0,0 @@ -@import "../../settings/constants.scss"; - -.oney-popin { - display: none; - background-color: white; - padding: 10px; - position: absolute; - z-index: 99; - max-width: 20em; - top: 0; - left: calc(-20em - 32px); - transform: translateY(calc(-100% / 3 + 10px)); - - &:after { - content: ''; - display: inline-block; - height: 0; - width: 0; - border-top: 20px solid transparent; - border-bottom: 20px solid transparent; - position: absolute; - right: -20px; - top: calc(100% / 3 - 10px); - } - - &.enabled { - border: 1px solid $green; - - hr { - border-color: $green; - } - - &:after { - border-left: 20px solid $green; - } - - a.close > span { - background: $green; - } - - .oney-popin__content > p { - color: $green; - } - } - - &.disabled { - border: 1px solid $lightgrey; - - hr { - border-color: $lightgrey; - } - - &:after { - border-left: 20px solid $lightgrey; - } - - a.close > span { - background: $lightgrey; - } - - .oney-popin__content > p { - color: $greyish; - } - } - - &__header { - text-align: right; - - a.close { - position: absolute; - top: 0; - right: 0; - width: 40px; - height: 40px; - - > span { - position: absolute; - width: 15px; - height: 2px; - right: .5em; - top: 1em; - margin: 0; - border-radius: 0; - - &:first-of-type { - transform: rotate(55deg); - } - - &:last-of-type { - transform: rotate(-55deg); - - } - } - } - } - - &__content { - > p { - &:not(.reasons) { - text-transform: uppercase; - margin-bottom: 0; - font-size: 16px; - - &:last-of-type { - margin-bottom: 1em; - } - } - &.reasons { - // avoid superposition of closing button over text - max-width: 95%; - } - } - } - - &__footer { - margin-top: 1em; - - > p { - text-align: justify; - } - } - - section { - display: flex; - align-items: flex-start; - } - - img { - height: auto; - margin-right: .5em; - } - - hr { - border-top-width: 1px; - border-top-style: solid; - border-bottom: 0; - border-left: 0; - border-right: 0; - margin: 1.25em 0; - } -} - -@media screen and (max-width: 768px) { - .oney-popin { - top: 60px; - left: 0; - transform: none; - - &__header { - a.close { - padding: 10px 50px; - } - } - - &:after { - transform: rotate(-90deg); - right: calc(50% - 10px); - top: -30px; - } - } -} diff --git a/src/Resources/dev/settings/constants.scss b/src/Resources/dev/settings/constants.scss deleted file mode 100644 index c125ab01..00000000 --- a/src/Resources/dev/settings/constants.scss +++ /dev/null @@ -1,9 +0,0 @@ -$white: #ffffff; -$lightgrey: #cccccc; -$greyish: #66727f; -$darkgrey: #222426; -$black: #000000; -$green: #81bc00; -$neongreen: #21ba45; -$red: #db2828; -$paypluggreen: #8fd2b8; diff --git a/src/Resources/dev/yarn.lock b/src/Resources/dev/yarn.lock deleted file mode 100644 index 99850626..00000000 --- a/src/Resources/dev/yarn.lock +++ /dev/null @@ -1,6335 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" - integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== - dependencies: - "@babel/highlight" "^7.14.5" - -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/core@^7.12.0", "@babel/core@^7.9.0": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - -"@babel/eslint-parser@^7.14.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.15.7.tgz#2dc3d0ff0ea22bb1e08d93b4eeb1149bf1c75f2d" - integrity sha512-yJkHyomClm6A2Xzb8pdAo4HzYMSXFn1O5zrCYvbFP0yQFvHueLedV8WiEno8yJOKStjUXzBZzJFeWQ7b3YMsqQ== - dependencies: - eslint-scope "^5.1.1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.0" - -"@babel/generator@^7.15.4", "@babel/generator@^7.9.0": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.4.tgz#85acb159a267ca6324f9793986991ee2022a05b0" - integrity sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw== - dependencies: - "@babel/types" "^7.15.4" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" - integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz#21ad815f609b84ee0e3058676c33cf6d1670525f" - integrity sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.15.4", "@babel/helper-compilation-targets@^7.8.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" - semver "^6.3.0" - -"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" - integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - -"@babel/helper-create-regexp-features-plugin@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" - integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== - dependencies: - "@babel/helper-annotate-as-pure" "^7.14.5" - regexpu-core "^4.7.1" - -"@babel/helper-define-polyfill-provider@^0.2.2": - version "0.2.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" - integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - -"@babel/helper-explode-assignable-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz#f9aec9d219f271eaf92b9f561598ca6b2682600c" - integrity sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-function-name@^7.14.5", "@babel/helper-function-name@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz#845744dafc4381a4a5fb6afa6c3d36f98a787ebc" - integrity sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw== - dependencies: - "@babel/helper-get-function-arity" "^7.15.4" - "@babel/template" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-get-function-arity@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz#098818934a137fce78b536a3e015864be1e2879b" - integrity sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-hoist-variables@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz#09993a3259c0e918f99d104261dfdfc033f178df" - integrity sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-member-expression-to-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" - integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" - integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz#7da80c8cbc1f02655d83f8b79d25866afe50d226" - integrity sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw== - dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.15.7" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.6" - -"@babel/helper-optimise-call-expression@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" - integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" - integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== - -"@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f" - integrity sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-wrap-function" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" - integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-skip-transparent-expression-wrappers@^7.14.5", "@babel/helper-skip-transparent-expression-wrappers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz#707dbdba1f4ad0fa34f9114fc8197aec7d5da2eb" - integrity sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-split-export-declaration@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz#aecab92dcdbef6a10aa3b62ab204b085f776e257" - integrity sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw== - dependencies: - "@babel/types" "^7.15.4" - -"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" - integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== - -"@babel/helper-validator-option@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" - integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== - -"@babel/helper-wrap-function@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz#6f754b2446cfaf3d612523e6ab8d79c27c3a3de7" - integrity sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw== - dependencies: - "@babel/helper-function-name" "^7.15.4" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== - dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/highlight@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" - integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== - dependencies: - "@babel/helper-validator-identifier" "^7.14.5" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.0.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5": - version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.7.tgz#0c3ed4a2eb07b165dfa85b3cc45c727334c4edae" - integrity sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g== - -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz#dbdeabb1e80f622d9f0b583efb2999605e0a567e" - integrity sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.15.4" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - -"@babel/plugin-proposal-async-generator-functions@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz#f82aabe96c135d2ceaa917feb9f5fca31635277e" - integrity sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.15.4" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-proposal-class-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" - integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-class-static-block@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz#3e7ca6128453c089e8b477a99f970c63fc1cb8d7" - integrity sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-proposal-dynamic-import@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" - integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - -"@babel/plugin-proposal-export-namespace-from@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" - integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - -"@babel/plugin-proposal-json-strings@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" - integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-json-strings" "^7.8.3" - -"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" - integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" - integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - -"@babel/plugin-proposal-numeric-separator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" - integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - -"@babel/plugin-proposal-object-rest-spread@^7.15.6": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" - integrity sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.15.4" - -"@babel/plugin-proposal-optional-catch-binding@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" - integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - -"@babel/plugin-proposal-optional-chaining@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" - integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - -"@babel/plugin-proposal-private-methods@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" - integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-proposal-private-property-in-object@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz#55c5e3b4d0261fd44fe637e3f624cfb0f484e3e5" - integrity sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-create-class-features-plugin" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - -"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" - integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-flow@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz#2ff654999497d7d7d142493260005263731da180" - integrity sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-arrow-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" - integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-async-to-generator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" - integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== - dependencies: - "@babel/helper-module-imports" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-remap-async-to-generator" "^7.14.5" - -"@babel/plugin-transform-block-scoped-functions@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" - integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-block-scoping@^7.15.3": - version "7.15.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" - integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-classes@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz#50aee17aaf7f332ae44e3bce4c2e10534d5d3bf1" - integrity sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-optimise-call-expression" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" - integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-destructuring@^7.14.7": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" - integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" - integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-duplicate-keys@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" - integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-exponentiation-operator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" - integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.14.5.tgz#0dc9c1d11dcdc873417903d6df4bed019ef0f85e" - integrity sha512-KhcolBKfXbvjwI3TV7r7TkYm8oNXHNBqGOy6JDVwtecFaRoKYsUUqJdS10q0YDKW1c6aZQgO+Ys3LfGkox8pXA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-flow" "^7.14.5" - -"@babel/plugin-transform-for-of@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz#25c62cce2718cfb29715f416e75d5263fb36a8c2" - integrity sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-function-name@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" - integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== - dependencies: - "@babel/helper-function-name" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" - integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-member-expression-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" - integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-modules-amd@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" - integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-commonjs@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz#8201101240eabb5a76c08ef61b2954f767b6b4c1" - integrity sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA== - dependencies: - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-simple-access" "^7.15.4" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-systemjs@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz#b42890c7349a78c827719f1d2d0cd38c7d268132" - integrity sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw== - dependencies: - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-identifier" "^7.14.9" - babel-plugin-dynamic-import-node "^2.3.3" - -"@babel/plugin-transform-modules-umd@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0" - integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA== - dependencies: - "@babel/helper-module-transforms" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": - version "7.14.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" - integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - -"@babel/plugin-transform-new-target@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" - integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-object-super@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" - integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-replace-supers" "^7.14.5" - -"@babel/plugin-transform-parameters@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz#5f2285cc3160bf48c8502432716b48504d29ed62" - integrity sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-property-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" - integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-regenerator@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" - integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" - integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-shorthand-properties@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" - integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-spread@^7.14.6": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" - integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" - -"@babel/plugin-transform-sticky-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" - integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-template-literals@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" - integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-typeof-symbol@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" - integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-unicode-escapes@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" - integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-transform-unicode-regex@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" - integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/preset-env@^7.9.5": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" - integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/helper-validator-option" "^7.14.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.15.4" - "@babel/plugin-proposal-async-generator-functions" "^7.15.4" - "@babel/plugin-proposal-class-properties" "^7.14.5" - "@babel/plugin-proposal-class-static-block" "^7.15.4" - "@babel/plugin-proposal-dynamic-import" "^7.14.5" - "@babel/plugin-proposal-export-namespace-from" "^7.14.5" - "@babel/plugin-proposal-json-strings" "^7.14.5" - "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" - "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread" "^7.15.6" - "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" - "@babel/plugin-proposal-optional-chaining" "^7.14.5" - "@babel/plugin-proposal-private-methods" "^7.14.5" - "@babel/plugin-proposal-private-property-in-object" "^7.15.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.14.5" - "@babel/plugin-transform-async-to-generator" "^7.14.5" - "@babel/plugin-transform-block-scoped-functions" "^7.14.5" - "@babel/plugin-transform-block-scoping" "^7.15.3" - "@babel/plugin-transform-classes" "^7.15.4" - "@babel/plugin-transform-computed-properties" "^7.14.5" - "@babel/plugin-transform-destructuring" "^7.14.7" - "@babel/plugin-transform-dotall-regex" "^7.14.5" - "@babel/plugin-transform-duplicate-keys" "^7.14.5" - "@babel/plugin-transform-exponentiation-operator" "^7.14.5" - "@babel/plugin-transform-for-of" "^7.15.4" - "@babel/plugin-transform-function-name" "^7.14.5" - "@babel/plugin-transform-literals" "^7.14.5" - "@babel/plugin-transform-member-expression-literals" "^7.14.5" - "@babel/plugin-transform-modules-amd" "^7.14.5" - "@babel/plugin-transform-modules-commonjs" "^7.15.4" - "@babel/plugin-transform-modules-systemjs" "^7.15.4" - "@babel/plugin-transform-modules-umd" "^7.14.5" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" - "@babel/plugin-transform-new-target" "^7.14.5" - "@babel/plugin-transform-object-super" "^7.14.5" - "@babel/plugin-transform-parameters" "^7.15.4" - "@babel/plugin-transform-property-literals" "^7.14.5" - "@babel/plugin-transform-regenerator" "^7.14.5" - "@babel/plugin-transform-reserved-words" "^7.14.5" - "@babel/plugin-transform-shorthand-properties" "^7.14.5" - "@babel/plugin-transform-spread" "^7.14.6" - "@babel/plugin-transform-sticky-regex" "^7.14.5" - "@babel/plugin-transform-template-literals" "^7.14.5" - "@babel/plugin-transform-typeof-symbol" "^7.14.5" - "@babel/plugin-transform-unicode-escapes" "^7.14.5" - "@babel/plugin-transform-unicode-regex" "^7.14.5" - "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.15.6" - babel-plugin-polyfill-corejs2 "^0.2.2" - babel-plugin-polyfill-corejs3 "^0.2.2" - babel-plugin-polyfill-regenerator "^0.2.2" - core-js-compat "^3.16.0" - semver "^6.3.0" - -"@babel/preset-modules@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" - integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/runtime@^7.8.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" - integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.15.4.tgz#51898d35dcf3faa670c4ee6afcfd517ee139f194" - integrity sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - -"@babel/traverse@^7.0.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" - integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/types@^7.12.13", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.4.4": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" - integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - -"@iarna/toml@^2.2.0": - version "2.2.5" - resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" - integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@parcel/babel-ast-utils@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/babel-ast-utils/-/babel-ast-utils-2.0.0-rc.0.tgz#acc368d6c9e1c9a63657a02ca3766b2c81c62fb8" - integrity sha512-cEWoinV9RW4T4iaRGL1TeI9hexRD/xAMGUpjTSiswRP1SJXr4uftOw3V+ptRuny7+mvMXGoID+c8nXFE5kgEIw== - dependencies: - "@babel/parser" "^7.0.0" - "@parcel/babylon-walk" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - astring "^1.6.2" - -"@parcel/babylon-walk@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/babylon-walk/-/babylon-walk-2.0.0-rc.0.tgz#fda5b73fa4803cd4c835ec85230a6f8f9baec2d7" - integrity sha512-h/Gz+RQNbPUxHHd0TO1lm1QmLhKI+kgByXq8U9cIMhkoef8gN2BqwA8v1Dr3Cm2tbT1G9TUPPx1GUrN8uA44pQ== - dependencies: - "@babel/types" "^7.12.13" - lodash.clone "^4.5.0" - -"@parcel/bundler-default@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.0.0-rc.0.tgz#ac5d3943da5db6b01a35d41cb4898a5c0c785957" - integrity sha512-DyCvrxpHyvj1JcdRZ4yqcxU4NRFuJOvmpyfPIx53BfAjZqtkEfcZ0TPnQzR9sXkv754qkISPfCKEJlhTWCDoDw== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/hash" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - -"@parcel/cache@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.0.0-rc.0.tgz#44b693d57981577cd5595ceb0ce8c6a7ad731893" - integrity sha512-XW3evoovrpr661Ts7Pgw6OTQ+TC63yCffd/+e4qvxD+/nmvHLRUnJR66gRX9GzbG7xaEfJvgcENbxx1CHNm3WA== - dependencies: - "@parcel/logger" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - lmdb-store "^1.5.5" - -"@parcel/codeframe@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.0.0-rc.0.tgz#4ee51cd64eb954791fcc96387c264c49c2d26d13" - integrity sha512-wJR/5y1xAutpCPTpDSEpSO1d5Tm6GYQZ1kNS9jx+J7KVcwpwB/ypw9mon+4kFoyegkc98YaJpTm3jlL/bBJblg== - dependencies: - chalk "^4.1.0" - emphasize "^4.2.0" - slice-ansi "^4.0.0" - string-width "^4.2.0" - -"@parcel/config-default@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.0.0-rc.0.tgz#bc722fee941304c9432577b715000ff8d24009e5" - integrity sha512-BVSst1GXA9Y2/+7E9uiuiPYiAAM+9OJRaOyveClBDRj9t8zltP4f6dlk5hbNtLIF1SnFir2kY4I8Rrc1OOp/DQ== - dependencies: - "@parcel/bundler-default" "2.0.0-rc.0" - "@parcel/namer-default" "2.0.0-rc.0" - "@parcel/optimizer-cssnano" "2.0.0-rc.0" - "@parcel/optimizer-htmlnano" "2.0.0-rc.0" - "@parcel/optimizer-svgo" "2.0.0-rc.0" - "@parcel/optimizer-terser" "2.0.0-rc.0" - "@parcel/packager-css" "2.0.0-rc.0" - "@parcel/packager-html" "2.0.0-rc.0" - "@parcel/packager-js" "2.0.0-rc.0" - "@parcel/packager-raw" "2.0.0-rc.0" - "@parcel/reporter-dev-server" "2.0.0-rc.0" - "@parcel/resolver-default" "2.0.0-rc.0" - "@parcel/runtime-browser-hmr" "2.0.0-rc.0" - "@parcel/runtime-js" "2.0.0-rc.0" - "@parcel/runtime-react-refresh" "2.0.0-rc.0" - "@parcel/transformer-babel" "2.0.0-rc.0" - "@parcel/transformer-css" "2.0.0-rc.0" - "@parcel/transformer-html" "2.0.0-rc.0" - "@parcel/transformer-js" "2.0.0-rc.0" - "@parcel/transformer-json" "2.0.0-rc.0" - "@parcel/transformer-postcss" "2.0.0-rc.0" - "@parcel/transformer-posthtml" "2.0.0-rc.0" - "@parcel/transformer-raw" "2.0.0-rc.0" - "@parcel/transformer-react-refresh-wrap" "2.0.0-rc.0" - -"@parcel/core@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.0.0-rc.0.tgz#6fca58e32b7cc538f3d3c0b660e684c7b041c61d" - integrity sha512-W4Qun0RTFJ258DrSwiQj66tIhqz/OXw7O+KlOLLWQ0gnB59t1NMd9S0jqk/dRQMVBohmg1VZf/haxLtgKkLlJQ== - dependencies: - "@parcel/cache" "2.0.0-rc.0" - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/events" "2.0.0-rc.0" - "@parcel/fs" "2.0.0-rc.0" - "@parcel/hash" "2.0.0-rc.0" - "@parcel/logger" "2.0.0-rc.0" - "@parcel/package-manager" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - "@parcel/workers" "2.0.0-rc.0" - abortcontroller-polyfill "^1.1.9" - base-x "^3.0.8" - browserslist "^4.6.6" - clone "^2.1.1" - dotenv "^7.0.0" - dotenv-expand "^5.1.0" - json-source-map "^0.6.1" - json5 "^1.0.1" - micromatch "^4.0.2" - nullthrows "^1.1.1" - querystring "^0.2.0" - semver "^5.4.1" - -"@parcel/diagnostic@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.0.0-rc.0.tgz#b20213dd42e2ac884031d586f64225cc79fb8523" - integrity sha512-s8hzLkUcgFqwfuCxHHuqx0zyeDU+GYtz69StWlCECXumHJMS0iaomE4IaKW5fsIMsdgndg7g4/yZc2eMXiHR1Q== - dependencies: - json-source-map "^0.6.1" - nullthrows "^1.1.1" - -"@parcel/events@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.0.0-rc.0.tgz#e2c9e4b5dd9ea17671bb8f6a377dd6cebbcbc0e8" - integrity sha512-k/fqhFXyQQYqo/2Y0pfxz97usoW14+g5hFO1Kfnto3t5l46M8sU65Di6qLHeTEVkO2cWh/alc7N8QxlcXmxO3Q== - -"@parcel/fs-search@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.0.0-rc.0.tgz#c0a26cec8a703d1490ab7e8d323b9d2191212d19" - integrity sha512-x/gdmnxWIhuP6kVUe3u8fiY5JBCmALHNJIPNDGdoVada1CEEHF+DJtQG7LT+LIcPFeAqXT6qx05HrgO94KLaUQ== - dependencies: - detect-libc "^1.0.3" - -"@parcel/fs-write-stream-atomic@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/fs-write-stream-atomic/-/fs-write-stream-atomic-2.0.0-rc.0.tgz#c9fd243a7a168c808b9e91d010132726be8c68a8" - integrity sha512-KQ9FbE+ee2nzEtZwdVcxup1uWGfyfKj0cDsbxfak+oMubDTb3ycQlyCAnVPKoybvxqpsTG+TKDXObDz8SBCF1A== - dependencies: - graceful-fs "^4.1.2" - iferr "^1.0.2" - imurmurhash "^0.1.4" - readable-stream "1 || 2" - -"@parcel/fs@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.0.0-rc.0.tgz#6ec58e0dc3828f3fac5cb476b5ce0cde3722e20a" - integrity sha512-vUXkiNiHa6cc9QrV4GGi40ID27aH5a/GNZ8G2EZxnPtC7FXjrI359CAt7qU8rGxOyPVECGNIwBr+e31p+Xg/Lg== - dependencies: - "@parcel/fs-search" "2.0.0-rc.0" - "@parcel/fs-write-stream-atomic" "2.0.0-rc.0" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - "@parcel/watcher" "2.0.0-alpha.10" - "@parcel/workers" "2.0.0-rc.0" - graceful-fs "^4.2.4" - mkdirp "^0.5.1" - ncp "^2.0.0" - nullthrows "^1.1.1" - rimraf "^3.0.2" - utility-types "^3.10.0" - -"@parcel/hash@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.0.0-rc.0.tgz#9100ce510e1b41eec31cd2a34892edf6154be124" - integrity sha512-qbR1evXfjR4t0LhY3z32nrGnPh32vsuafS6rrS4JOJyD7mbOsHUKsT1Vkggh3R5Jv0sMtuRqlYngK59WO/Yzbg== - dependencies: - detect-libc "^1.0.3" - xxhash-wasm "^0.4.1" - -"@parcel/logger@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.0.0-rc.0.tgz#e837f256f6133aa85681c75dad9cf5d6b70e3025" - integrity sha512-gUbEN0iTM0E8Vb0qhLev/AcHyKc3McVWOSZQDC31CQ0DpPY8KPVmDR4tEL+hC0YEl6ekpG2c41F5XpH2mzTawg== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/events" "2.0.0-rc.0" - -"@parcel/markdown-ansi@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.0.0-rc.0.tgz#aebb97c7811b0bd054603e29a881f5937e2f87a0" - integrity sha512-ipR71hKCpqq9aXaPCordBPETYP/QyrN2t2Ra7tPPCvNful44i0JqWakPeSrDO1HJT1s1GI1lGpIk+ytc/5PCCg== - dependencies: - chalk "^4.1.0" - -"@parcel/namer-default@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.0.0-rc.0.tgz#7a6ef5eeb1ecfad141958b518a1e147ef22047a1" - integrity sha512-voQC1VQzkZqU2cJJ7hS8mN/TlpxLURYBSK1qERT0+zCVuQR1z+5HX+pwTXet7HdnI6+A5FSq2F5B7fj4KMRMqQ== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - nullthrows "^1.1.1" - -"@parcel/node-libs-browser@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/node-libs-browser/-/node-libs-browser-2.0.0-rc.0.tgz#26cdbc85f527d1201b68220c1a46aff92740929a" - integrity sha512-QQVvT0qRdbu1Q8FDiqlrby+4EqjJW24mckKOGiLsDzT134/XGiG8psgYm1HOsrsqgN1psetTbZRs49yfIs4Zog== - dependencies: - assert "^2.0.0" - browserify-zlib "^0.2.0" - buffer "^5.5.0" - console-browserify "^1.2.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.12.0" - domain-browser "^3.5.0" - events "^3.1.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "^1.0.0" - process "^0.11.10" - punycode "^1.4.1" - querystring-es3 "^0.2.1" - readable-stream "^3.6.0" - stream-http "^3.1.0" - string_decoder "^1.3.0" - timers-browserify "^2.0.11" - tty-browserify "^0.0.1" - url "^0.11.0" - util "^0.12.3" - vm-browserify "^1.1.2" - -"@parcel/node-resolver-core@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.0.0-rc.0.tgz#ba96fa4d0f8652de05bf6be9c102e4b505de11d4" - integrity sha512-Xl8XNT13SgzjTxPzthUcyodz5PIaXixaZQrkKUBIdVuoohQkBqzs9U8p38pRXuM65xesGVLpjGKZWICAwViM2Q== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/node-libs-browser" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - micromatch "^3.0.4" - nullthrows "^1.1.1" - querystring "^0.2.0" - -"@parcel/optimizer-cssnano@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-cssnano/-/optimizer-cssnano-2.0.0-rc.0.tgz#bf28648287c394ea2c542e783d261a2015f8f4bc" - integrity sha512-Sr7aXsYJt05hfAsBv8JKYtbNVD/GbO7RoMVrZw+Gd3a2uwLyMRjnOIyDp9+L06U/LQIKAMBJt+bToDBoWYPl3A== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - cssnano "^5.0.5" - postcss "^8.3.0" - -"@parcel/optimizer-htmlnano@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.0.0-rc.0.tgz#ad138a37dfc630312c6d37d95cd8eccabc8c5385" - integrity sha512-ItYNuT/CxEwSKo3hFHUZfWa8+LgqwfnmUdpFfyf5vrEXqM8o/LZUukR69m8nZGSaKspfR/c4H/UQxpYKmsJfIQ== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - htmlnano "^1.0.0" - nullthrows "^1.1.1" - posthtml "^0.16.4" - svgo "^2.3.0" - -"@parcel/optimizer-svgo@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.0.0-rc.0.tgz#3d1855a25144c5386ed4e374c65334f21585a980" - integrity sha512-mokwpZt5Ki169t/wVXXfXcYsdn0oN4WFoo5lr0ihZujDwPcuYg2Ygpdktd+g6nAxznXrN7rhpXKpTSnpJjdTdA== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - svgo "^2.3.0" - -"@parcel/optimizer-terser@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.0.0-rc.0.tgz#4c03f435f877f80f604adc51694bfae4de98b0f7" - integrity sha512-Xnu/6NP5B8kOgeXFjq1DzAdaMj3mWCop75235ZFfM7EMLFVH1qn0OZnJPK1THO4CZ2vElOknO1BW25gqNCoE4A== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - terser "^5.2.0" - -"@parcel/package-manager@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.0.0-rc.0.tgz#c1ded5914ead2da60337f28561917c8a9a58c612" - integrity sha512-QA1B7FViEMB0CpEeEV1oCqIDFHDReYWL38NnwWesLiewIAeIZHLCHqN35ClCK84F8NnCUp9uMymDv61rwJlq9A== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/fs" "2.0.0-rc.0" - "@parcel/logger" "2.0.0-rc.0" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - "@parcel/workers" "2.0.0-rc.0" - command-exists "^1.2.6" - cross-spawn "^6.0.4" - nullthrows "^1.1.1" - semver "^5.4.1" - split2 "^3.1.1" - -"@parcel/packager-css@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.0.0-rc.0.tgz#c0c48a1fc0bd15bbfef27b3fbc2850ec9bd7fd9c" - integrity sha512-X+H2QrnHtUdXY7pLCaU+FnYVHW/W2x7bMfIpxdEaqz9QNvmpivHfmQ+Ifda7WwyIg66KHeG55RiODv6qi6bsgg== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - postcss "^8.3.0" - -"@parcel/packager-html@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.0.0-rc.0.tgz#9ef3737cd1af4d8633654d458901ce9834af65d2" - integrity sha512-xYMUmDBRjcCafItklOPz0dllIQkDSdSocdRpPF2apLyms8QU8EQ7JzOAVSpI+I2OyQbHYzMjTssFTJbqywz2zA== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - posthtml "^0.16.4" - -"@parcel/packager-js@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.0.0-rc.0.tgz#48aee0133b27466cd217e560da0b69c1b2451ae5" - integrity sha512-12+kqcdW55WuMNRRu5unYWDnEDyw24WSJZiRaA+UH3oYkYF8MrK3BRrTbv4a6X2sH4iGA/4FznXEWc1mzWgl6Q== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/hash" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - globals "^13.2.0" - nullthrows "^1.1.1" - -"@parcel/packager-raw@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.0.0-rc.0.tgz#446cb71e9c03420035804f43fbcb4bdb1832ad09" - integrity sha512-9R0OIreEqDQxj8coMhqDBdqGpJMsQo1gHimLWw/pcYQFLQDSM2eqxGIt0NdB2ZbESltbkfyOl5BdfjuR7iUOyQ== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - -"@parcel/plugin@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.0.0-rc.0.tgz#6529cb2640fc811de9e65a629c7d3d4e767a902c" - integrity sha512-dCfnWnkoqsPijEHKhisENDiGBUUCLuZfjPkVGqMcKBpLhv6bnh3ivmXyC9bcJBZJ8BV9Ytltj+ooOyFOMQRJnQ== - dependencies: - "@parcel/types" "2.0.0-rc.0" - -"@parcel/reporter-cli@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.0.0-rc.0.tgz#c4cd3a5f7706c394ee4cbc2f511271d141127347" - integrity sha512-szynnxoWewnALI9zdwD5d4ZlvY95xDRliza/TnzKqYHHFtFcfER6DXiznSgZ9sMXILZ0S1xZrXiagATpQUpxnQ== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - chalk "^4.1.0" - filesize "^6.1.0" - nullthrows "^1.1.1" - ora "^5.2.0" - string-width "^4.2.0" - strip-ansi "^6.0.0" - term-size "^2.2.1" - wrap-ansi "^7.0.0" - -"@parcel/reporter-dev-server@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.0.0-rc.0.tgz#223cab22514c43416bc6889ae3f3caa4c6e252fa" - integrity sha512-upA2rugECBsLb8JzG8A7iNrl7EYYNpnNwuW/o4x6aDWYSa3bdx0XI/1K2+9zHxj5V5bj3n0mDH6qw65f25ykEg== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - connect "^3.7.0" - ejs "^2.6.1" - http-proxy-middleware "^1.0.0" - nullthrows "^1.1.1" - serve-handler "^6.0.0" - ws "^7.0.0" - -"@parcel/resolver-default@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.0.0-rc.0.tgz#9c94fe66e41b067c1d46b4f1d5708fe9f0d97e6b" - integrity sha512-b79IUkDIVQ4LGuFsWWCdSqrXrU6bPR+AouMb1vH4Dbu8ljdqAdVHs3fu5TnAHBY2o0cXhm1KD3ecH7iEz/h8EA== - dependencies: - "@parcel/node-resolver-core" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - -"@parcel/runtime-browser-hmr@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.0.0-rc.0.tgz#5d9634fdc5d0d965f6a484262b2fb312cda93447" - integrity sha512-PTljXkNp4ZH9iOIgEg3EpdSPqrPfPssOGUE3W4tTvE6r/DfweqhiyQCHL7XWbFaG4uXJACko8WVqJAtXadcUDQ== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - -"@parcel/runtime-js@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.0.0-rc.0.tgz#89d45ef3154fe8c70b12bc4e482e07c380a56035" - integrity sha512-L+7umxrp0VrOJB6FooGmDvxbXGseVXibeHqluMsRpN0tmh3bwxhPbWl2KGhtxvWCFVADKHtZo9sBIcnTU4Dp/Q== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - -"@parcel/runtime-react-refresh@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.0.0-rc.0.tgz#4aac7aab7a43d7ab8d57cee999e9792d372e39a0" - integrity sha512-KuIz9vI6zWcA7IOAYR8ldCby7DnqhtZwR5LG3GU0oH4QUckUdheH5Pi35qg0wpFy2N9KSRRbNarXps4WQ0IJvg== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - react-refresh "^0.9.0" - -"@parcel/source-map@2.0.0-rc.6": - version "2.0.0-rc.6" - resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.0.0-rc.6.tgz#9b0e84ba4bca9fe8aee484941e48345c79c4121c" - integrity sha512-qtXLd9dbxWx/ybe1dduAzAGzb7iTSQv3imNZo7pVyEtSaCcphg+rTmY8/Fg3MQqqu7of/2+tEqNAGMz8nOJyUA== - dependencies: - detect-libc "^1.0.3" - globby "^11.0.3" - -"@parcel/transformer-babel@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.0.0-rc.0.tgz#77fbe2024eea244fe739b04f9667d2a449046f30" - integrity sha512-z0SapRmPycI1sQ4h+Gs+i14bzv97VCz3q1moTzsD8DhkPPuFRBXS7N/cxmRIGqXt8P0qaffJ+gsf4jN0ji3JWg== - dependencies: - "@babel/core" "^7.12.0" - "@babel/generator" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.4" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@parcel/babel-ast-utils" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - browserslist "^4.6.6" - core-js "^3.2.1" - nullthrows "^1.1.1" - semver "^5.7.0" - -"@parcel/transformer-css@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.0.0-rc.0.tgz#a5561631761afbcc0bf121d48b77d32205b51881" - integrity sha512-KJ/Xc1GqirUSr8BZ/UoPMcwXaDFqtc/E9bGfPGdWiPND/R4x24GHPtY1IsT7V4BBQ1hiO4Yw8C8jl1BgheWS+w== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - postcss "^8.3.0" - postcss-value-parser "^4.1.0" - semver "^5.4.1" - -"@parcel/transformer-html@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.0.0-rc.0.tgz#27baca8a617afdbf1e504709db3f5d565efd64ac" - integrity sha512-jGzgxDiN7YrsosG9kwGeGSEz+gCUvl1tP4EJIx4PY401bYOlr31+ppR/7aGWQ+BxmsG4SL7QTxU4KZ42TE7gEQ== - dependencies: - "@parcel/hash" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - nullthrows "^1.1.1" - posthtml "^0.16.4" - posthtml-parser "^0.9.0" - posthtml-render "^2.0.6" - semver "^5.4.1" - -"@parcel/transformer-js@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.0.0-rc.0.tgz#92437bca0c48289ea7044c98f583b6a9d5028e90" - integrity sha512-zmp2ha7fnIBCG7d56MBneXjZxhOBcJLXpO+3rpiwGoic2fQdcNk702QHGBmfqnZW4u/pebGZpolj/wUqtP0bcQ== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/utils" "2.0.0-rc.0" - "@swc/helpers" "^0.2.11" - browserslist "^4.6.6" - detect-libc "^1.0.3" - micromatch "^4.0.2" - nullthrows "^1.1.1" - regenerator-runtime "^0.13.7" - semver "^5.4.1" - -"@parcel/transformer-json@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.0.0-rc.0.tgz#ac626c425d1b3843f21aa9fc9da99d73f76e5c7c" - integrity sha512-nTGPI5gyDP166FjDafzOw8WhBOqq9T95j3Q7qSmdXQ3og6Tm5pzN92YDsAXhcaIkRhJeof5eRG3Q1XsoGR0n9g== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - json5 "^2.1.0" - -"@parcel/transformer-postcss@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.0.0-rc.0.tgz#898606175794f1d1a6ddf093d2c4fb0a19d760ab" - integrity sha512-VqYBjLP1wmBrUFkazUvN7O4XYD61NCAtvKfTuH6P4eer8+GbeSFeYiG5vpXpbleRk2u9o2aJ5iyzY0Rie8ogiA== - dependencies: - "@parcel/hash" "2.0.0-rc.0" - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - clone "^2.1.1" - css-modules-loader-core "^1.1.0" - nullthrows "^1.1.1" - postcss-modules "^3.2.2" - postcss-value-parser "^4.1.0" - semver "^5.4.1" - -"@parcel/transformer-posthtml@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.0.0-rc.0.tgz#f70f7f1a5d63ab05d77677b71a7c510b8d74c40b" - integrity sha512-RcpCUNNm70V+HeR3l6onhLeflZAwytgmVdb8TDFkTkoZ7GVZ2qdkMuYBhz4aTnLZZm+/Fjh8kRJMkIFYOLx1mA== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - nullthrows "^1.1.1" - posthtml "^0.16.4" - posthtml-parser "^0.9.0" - posthtml-render "^2.0.6" - semver "^5.4.1" - -"@parcel/transformer-raw@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.0.0-rc.0.tgz#9971cf38e04dc8c33538bec4aa223dcedbfdcb60" - integrity sha512-yyu1y0ViatnY05JdU8uqA1iypcdYx9qrt0ZliJZYT5WGb5eYZXtc500sk6x7Mpch35RiQzIjUFg6oBvgCnTqAw== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - -"@parcel/transformer-react-refresh-wrap@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.0.0-rc.0.tgz#ba4245a8d3da2f20464f615b87972cb9aaeb79f4" - integrity sha512-pwF00jhJ+H108ZhZY/L/wOklDNC91+Slv/INN0avFa3c1xBceDLEb7363mZzvRJThaFChxwya7siuuohKc0xqw== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - react-refresh "^0.9.0" - -"@parcel/transformer-sass@^2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.0.0-rc.0.tgz#97fe64b6b9beb73b0fdca977cd018ea4e0cfd3ec" - integrity sha512-7n09Zwq1VjhilPf0QZ8vENnYuQjYd/3xdvBEdpB6U6nS9v6wiQhDlLgNe/o7aIaFM9EkX5UZqKwBrS0qDPqngg== - dependencies: - "@parcel/plugin" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - sass "^1.32.4" - -"@parcel/types@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.0.0-rc.0.tgz#afe4892a548db25e3ffd81ec03ba9948e03d4e5f" - integrity sha512-v1/pS/benX/ekED8FC5kcKfUJffuPcvllzuZKaBlV5rsMwlRbMtdWfRfJ+ibdEIqjvJRtflt84p88Oo725SMQA== - dependencies: - "@parcel/cache" "2.0.0-rc.0" - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/fs" "2.0.0-rc.0" - "@parcel/package-manager" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - "@parcel/workers" "2.0.0-rc.0" - utility-types "^3.10.0" - -"@parcel/utils@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.0.0-rc.0.tgz#4f7e8e2ed1982ad113c070114812d072243ae25b" - integrity sha512-4W5HT3zILVH0c8W1SMu6jPYtjEy7qh2IOSDR2KiUlT1jFF1OOjd4iQFAEYvHP0iBr1mdiSwXEdkEMhm4hR9xYA== - dependencies: - "@iarna/toml" "^2.2.0" - "@parcel/codeframe" "2.0.0-rc.0" - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/hash" "2.0.0-rc.0" - "@parcel/logger" "2.0.0-rc.0" - "@parcel/markdown-ansi" "2.0.0-rc.0" - "@parcel/source-map" "2.0.0-rc.6" - ansi-html "^0.0.7" - chalk "^4.1.0" - clone "^2.1.1" - fast-glob "3.1.1" - fastest-levenshtein "^1.0.8" - is-glob "^4.0.0" - is-url "^1.2.2" - json5 "^1.0.1" - lru-cache "^6.0.0" - micromatch "^3.0.4" - node-forge "^0.10.0" - nullthrows "^1.1.1" - open "^7.0.3" - -"@parcel/watcher@2.0.0-alpha.10": - version "2.0.0-alpha.10" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.0-alpha.10.tgz#99266189f5193512dbdf6b0faca20400c519a16e" - integrity sha512-8uA7Tmx/1XvmUdGzksg0+oN7uj24pXFFnKJqZr3L3mgYjdrL7CMs3PRIHv1k3LUz/hNRsb/p3qxztSkWz1IGZA== - dependencies: - node-addon-api "^3.0.2" - node-gyp-build "^4.2.3" - -"@parcel/workers@2.0.0-rc.0": - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.0.0-rc.0.tgz#6219bdd8ce55d2fb13768f0bd431922341aaa6c2" - integrity sha512-HYRr8wg+PwRpZJDFpAZ0te6jVJKQlg4QkfH9nV0u9BktBVs/fmRWH/t4qYZz2c4W2zF+xIe8EfZbkafeETH67Q== - dependencies: - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/logger" "2.0.0-rc.0" - "@parcel/types" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - chrome-trace-event "^1.0.2" - nullthrows "^1.1.1" - -"@swc/helpers@^0.2.11": - version "0.2.13" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.2.13.tgz#95d69aaed0998040d455832efbe1342ed79d0809" - integrity sha512-HxfZHtTgDlME7fH+KIwBrm1B1+2iB3UpbcSbPCZzDAHxZ3z+qfjflHverm33sXrdyQYx4s3J7r6ot76433mwEg== - -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - -"@types/http-proxy@^1.17.5": - version "1.17.7" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.7.tgz#30ea85cc2c868368352a37f0d0d3581e24834c6f" - integrity sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w== - dependencies: - "@types/node" "*" - -"@types/node@*": - version "16.10.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.3.tgz#7a8f2838603ea314d1d22bb3171d899e15c57bd5" - integrity sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ== - -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -abab@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - -abortcontroller-polyfill@^1.1.9: - version "1.7.3" - resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" - integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q== - -acorn-globals@^4.3.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" - -acorn-jsx@^5.2.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== - -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - -acorn@^6.0.1, acorn@^6.0.4: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-html@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" - integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" - integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== - dependencies: - es6-object-assign "^1.1.0" - is-nan "^1.2.1" - object-is "^1.0.1" - util "^0.12.0" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - -astring@^1.6.2: - version "1.7.5" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.7.5.tgz#a7d47fceaf32b052d33a3d07c511efeec67447ca" - integrity sha512-lobf6RWXb8c4uZ7Mdq0U12efYmpD1UFnyOWVJPTa3ukqZrMopav+2hdNu0hgBF0JIBFK9QgrBDfwYvh3DFJDAA== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - -babel-plugin-dynamic-import-node@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - -babel-plugin-polyfill-corejs2@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" - integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.2.2" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.2.2: - version "0.2.5" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz#2779846a16a1652244ae268b1e906ada107faf92" - integrity sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - core-js-compat "^3.16.2" - -babel-plugin-polyfill-regenerator@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" - integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.2.2" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.8: - version "3.0.8" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.8.tgz#1e1106c2537f0162e8b52474a557ebb09000018d" - integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bl@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" - integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== - dependencies: - buffer "^5.5.0" - inherits "^2.0.4" - readable-stream "^3.4.0" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - -boolbase@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.3, browserslist@^4.6.6: - version "4.17.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.3.tgz#2844cd6eebe14d12384b0122d217550160d2d624" - integrity sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ== - dependencies: - caniuse-lite "^1.0.30001264" - electron-to-chromium "^1.3.857" - escalade "^3.1.1" - node-releases "^1.1.77" - picocolors "^0.2.1" - -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001264: - version "1.0.30001265" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" - integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - -"chokidar@>=3.0.0 <4.0.0": - version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" - integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-spinners@^2.5.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" - integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -colord@^2.0.1, colord@^2.6: - version "2.8.0" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.8.0.tgz#64fb7aa03de7652b5a39eee50271a104c2783b12" - integrity sha512-kNkVV4KFta3TYQv0bzs4xNwLaeag261pxgzGQSh4cQ1rEhYjcTJfFRP0SDlbhLONg0eSoLzrDd79PosjbltufA== - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -command-exists@^1.2.6: - version "1.2.9" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - -commander@^7.0.0, commander@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" - integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -connect@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - -console-browserify@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -content-disposition@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= - -convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js-compat@^3.16.0, core-js-compat@^3.16.2: - version "3.18.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.18.2.tgz#e40c266fbd613948dd8d2d2156345da8ac03c142" - integrity sha512-25VJYCJtGjZwLguj7d66oiHfmnVw3TMOZ0zV8DyMJp/aeQ3OjR519iOOeck08HMyVVRAqXxafc2Hl+5QstJrsQ== - dependencies: - browserslist "^4.17.3" - semver "7.0.0" - -core-js@^3.2.1: - version "3.18.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.18.2.tgz#63a551e8a29f305cd4123754846e65896619ba5b" - integrity sha512-zNhPOUoSgoizoSQFdX1MeZO16ORRb9FFQLts8gSYbZU5FcgXhp24iMWMxnOQo5uIaIG7/6FA/IqJPwev1o9ZXQ== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^6.0.4, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" - integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA== - -css-declaration-sorter@^6.0.3: - version "6.1.3" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" - integrity sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA== - dependencies: - timsort "^0.3.0" - -css-modules-loader-core@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz#5908668294a1becd261ae0a4ce21b0b551f21d16" - integrity sha1-WQhmgpShvs0mGuCkziGwtVHyHRY= - dependencies: - icss-replace-symbols "1.1.0" - postcss "6.0.1" - postcss-modules-extract-imports "1.1.0" - postcss-modules-local-by-default "1.2.0" - postcss-modules-scope "1.1.0" - postcss-modules-values "1.3.0" - -css-select@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" - integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== - dependencies: - boolbase "^1.0.0" - css-what "^5.0.0" - domhandler "^4.2.0" - domutils "^2.6.0" - nth-check "^2.0.0" - -css-selector-tokenizer@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - -css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" - integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.4.tgz#359943bf00c5c8e05489f12dd25f3006f2c1cbd2" - integrity sha512-sPpQNDQBI3R/QsYxQvfB4mXeEcWuw0wGtKtmS5eg8wudyStYMgKOQT39G07EbW1LB56AOYrinRS9f0ig4Y3MhQ== - dependencies: - css-declaration-sorter "^6.0.3" - cssnano-utils "^2.0.1" - postcss-calc "^8.0.0" - postcss-colormin "^5.2.0" - postcss-convert-values "^5.0.1" - postcss-discard-comments "^5.0.1" - postcss-discard-duplicates "^5.0.1" - postcss-discard-empty "^5.0.1" - postcss-discard-overridden "^5.0.1" - postcss-merge-longhand "^5.0.2" - postcss-merge-rules "^5.0.2" - postcss-minify-font-values "^5.0.1" - postcss-minify-gradients "^5.0.2" - postcss-minify-params "^5.0.1" - postcss-minify-selectors "^5.1.0" - postcss-normalize-charset "^5.0.1" - postcss-normalize-display-values "^5.0.1" - postcss-normalize-positions "^5.0.1" - postcss-normalize-repeat-style "^5.0.1" - postcss-normalize-string "^5.0.1" - postcss-normalize-timing-functions "^5.0.1" - postcss-normalize-unicode "^5.0.1" - postcss-normalize-url "^5.0.2" - postcss-normalize-whitespace "^5.0.1" - postcss-ordered-values "^5.0.2" - postcss-reduce-initial "^5.0.1" - postcss-reduce-transforms "^5.0.1" - postcss-svgo "^5.0.2" - postcss-unique-selectors "^5.0.1" - -cssnano-utils@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" - integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== - -cssnano@^5.0.5, cssnano@^5.0.8: - version "5.0.8" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.8.tgz#39ad166256980fcc64faa08c9bb18bb5789ecfa9" - integrity sha512-Lda7geZU0Yu+RZi2SGpjYuQz4HI4/1Y+BhdD0jL7NXAQ5larCzVn+PUGuZbDMYz904AXXCOgO5L1teSvgu7aFg== - dependencies: - cssnano-preset-default "^5.1.4" - is-resolvable "^1.1.0" - lilconfig "^2.0.3" - yaml "^1.10.2" - -csso@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -cssom@0.3.x, cssom@^0.3.4: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^1.1.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== - dependencies: - cssom "0.3.x" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.0.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" - integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== - dependencies: - ms "2.1.2" - -debug@^4.1.0, debug@^4.1.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" - integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== - dependencies: - ms "2.1.2" - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dom-serializer@^1.0.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" - integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -domain-browser@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-3.5.0.tgz#3a11f5df52fd9d60d7f1c79a62fde2d158c42b09" - integrity sha512-zrzUu6auyZWRexjCEPJnfWc30Hupxh2lJZOJAF3qa2bCuD4O/55t0FvQt3ZMhEw++gjNkwdkOVZh8yA32w/Vfw== - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" - integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== - -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" - -domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" - integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== - dependencies: - domelementtype "^2.2.0" - -domutils@^2.5.2, domutils@^2.6.0, domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" - integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -ejs@^2.6.1: - version "2.7.4" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" - integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== - -electron-to-chromium@^1.3.857: - version "1.3.860" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.860.tgz#d612e54ed75fa524c12af8da3ad8121ebfe2802b" - integrity sha512-gWwGZ+Wv4Mou2SJRH6JQzhTPjL5f95SX7n6VkLTQ/Q/INsZLZNQ1vH2GlZjozKyvT0kkFuCmWTwIoCj+/hUDPw== - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - -emphasize@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/emphasize/-/emphasize-4.2.0.tgz#6b6fdc4d212cb7eafea1c7cdd595dfd6cfc508d9" - integrity sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg== - dependencies: - chalk "^4.0.0" - highlight.js "~10.4.0" - lowlight "~1.17.0" - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" - integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.18.5: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-object-assign@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" - integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escodegen@^1.11.0: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -eslint-config-prettier@^6.10.1: - version "6.15.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" - integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw== - dependencies: - get-stdin "^6.0.0" - -eslint-plugin-prettier@^3.1.3: - version "3.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5" - integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - -eslint-visitor-keys@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^4.1.1, estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -estraverse@^5.1.0, estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -events@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^3.1.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82" - integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - -fast-glob@^3.1.1: - version "3.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1" - integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fast-url-parser@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= - dependencies: - punycode "^1.3.2" - -fastest-levenshtein@^1.0.8: - version "1.0.12" - resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" - integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== - -fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - -fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - -fault@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" - integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== - dependencies: - format "^0.2.0" - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - -filesize@^6.1.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.4.0.tgz#914f50471dd66fdca3cefe628bd0cde4ef769bcd" - integrity sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -finalhandler@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - -follow-redirects@^1.0.0: - version "1.14.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" - integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -format@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" - integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - -generic-names@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" - integrity sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ== - dependencies: - loader-utils "^1.1.0" - -gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - -get-port@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" - integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== - -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - -globals@^13.2.0: - version "13.11.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7" - integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g== - dependencies: - type-fest "^0.20.2" - -globby@^11.0.3: - version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" - integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - -graceful-fs@^4.1.2, graceful-fs@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" - integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" - integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== - -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -highlight.js@~10.4.0: - version "10.4.1" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0" - integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - dependencies: - whatwg-encoding "^1.0.1" - -html-tags@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-1.2.0.tgz#c78de65b5663aa597989dd2b7ab49200d7e4db98" - integrity sha1-x43mW1Zjqll5id0rerSSANfk25g= - -htmlnano@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-1.1.1.tgz#aea50e1d7ac156370ea766d4cd75f2d3d1a953cc" - integrity sha512-diMNyqTPx4uGwlxrTs0beZCy8L/GxGIFGHWv20OYhthLcdYkDOP/d4Ja5MbGgVJZMakZUM21KpMk5qWZrBGSdw== - dependencies: - cosmiconfig "^7.0.1" - cssnano "^5.0.8" - postcss "^8.3.6" - posthtml "^0.16.5" - purgecss "^4.0.0" - relateurl "^0.2.7" - srcset "^4.0.0" - svgo "^2.6.1" - terser "^5.8.0" - timsort "^0.3.0" - uncss "^0.17.3" - -htmlparser2@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" - integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.0.0" - domutils "^2.5.2" - entities "^2.0.0" - -htmlparser2@^7.1.1: - version "7.1.2" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.1.2.tgz#587923d38f03bc89e03076e00cba2c7473f37f7c" - integrity sha512-d6cqsbJba2nRdg8WW2okyD4ceonFHn9jLFxhwlNcLhQWcFPdxXeJulgOLjLKtAK9T6ahd+GQNZwG9fjmGW7lyg== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.2" - domutils "^2.8.0" - entities "^3.0.1" - -http-proxy-middleware@^1.0.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz#43700d6d9eecb7419bf086a128d0f7205d9eb665" - integrity sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg== - dependencies: - "@types/http-proxy" "^1.17.5" - http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.2" - -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^4.0.0, icss-utils@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" - integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== - dependencies: - postcss "^7.0.14" - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -iferr@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" - integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg== - -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - -import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - -internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - -is-absolute-url@^3.0.1, is-absolute-url@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - -is-core-module@^2.2.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.7.0.tgz#3c0ef7d31b4acfc574f80c58409d568a836848e3" - integrity sha512-ByY+tjCciCr+9nLryBYcSD50EOGWt95c7tIsKTG1J2ixKKXPvF7Ej3AVd+UfDydAJom3biBGDBALaO79ktwgEQ== - dependencies: - has "^1.0.3" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-html@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-html/-/is-html-1.1.0.tgz#e04f1c18d39485111396f9a0273eab51af218464" - integrity sha1-4E8cGNOUhRETlvmgJz6rUa8hhGQ= - dependencies: - html-tags "^1.0.0" - -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - -is-json@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" - integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8= - -is-nan@^1.2.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" - integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - -is-negative-zero@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" - integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== - -is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-resolvable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.3, is-typed-array@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" - integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-url@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" - integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== - -is-weakref@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" - integrity sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ== - dependencies: - call-bind "^1.0.0" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jquery@^3.5.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" - integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" - integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== - dependencies: - abab "^2.0.0" - acorn "^6.0.4" - acorn-globals "^4.3.0" - array-equal "^1.0.0" - cssom "^0.3.4" - cssstyle "^1.1.1" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.0" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.1.3" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.5" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^2.5.0" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^6.1.2" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f" - integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.0, json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -lilconfig@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" - integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg== - -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -lmdb-store@^1.5.5: - version "1.6.8" - resolved "https://registry.yarnpkg.com/lmdb-store/-/lmdb-store-1.6.8.tgz#f57c1fa4a8e8e7a73d58523d2bfbcee96782311f" - integrity sha512-Ltok13VVAfgO5Fdj/jVzXjPJZjefl1iENEHerZyAfAlzFUhvOrA73UdKItqmEPC338U29mm56ZBQr5NJQiKXow== - dependencies: - mkdirp "^1.0.4" - nan "^2.14.2" - node-gyp-build "^4.2.3" - ordered-binary "^1.0.0" - weak-lru-cache "^1.0.0" - optionalDependencies: - msgpackr "^1.3.7" - -loader-utils@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" - integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^1.0.1" - -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - -lodash.clone@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" - integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= - -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -lowlight@~1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.17.0.tgz#a1143b2fba8239df8cd5893f9fe97aaf8465af4a" - integrity sha512-vmtBgYKD+QVNy7tIa7ulz5d//Il9R4MooOVh4nkOf9R9Cb/Dk5TXMSTieg/vDulkBkIWj59/BIlyFQxT9X1oAQ== - dependencies: - fault "^1.0.0" - highlight.js "~10.4.0" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^3.0.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.50.0: - version "1.50.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" - integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== - -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@2.1.18: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.33" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" - integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== - dependencies: - mime-db "1.50.0" - -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -msgpackr-extract@^1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-1.0.14.tgz#87d3fe825d226e7f3d9fe136375091137f958561" - integrity sha512-t8neMf53jNZRF+f0H9VvEUVvtjGZ21odSBRmFfjZiyxr9lKYY0mpY3kSWZAIc7YWXtCZGOvDQVx2oqcgGiRBrw== - dependencies: - nan "^2.14.2" - node-gyp-build "^4.2.3" - -msgpackr@^1.3.7: - version "1.4.4" - resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.4.4.tgz#872f03fc99eb8f8c1c99615072c7ea12205429be" - integrity sha512-MFK+aGsB3WqUWt1tb4hOTK+px4PvZE/kT7jQCr1exYQimkqPAfEkJ9OMFiW1XKBtWAvN93VwUPQWhOaPuSuZXQ== - optionalDependencies: - msgpackr-extract "^1.0.14" - -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -nan@^2.14.2: - version "2.15.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" - integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== - -nanocolors@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/nanocolors/-/nanocolors-0.1.12.tgz#8577482c58cbd7b5bb1681db4cf48f11a87fd5f6" - integrity sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ== - -nanoid@^3.1.28: - version "3.1.29" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.29.tgz#214fb2d7a33e1a5bef4757b779dfaeb6a4e5aeb4" - integrity sha512-dW2pUSGZ8ZnCFIlBIA31SV8huOGCHb6OwzVCc7A69rb/a+SgPBwfmLvK5TKQ3INPbRkcI8a/Owo0XbiTNH19wg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -ncp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" - integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-addon-api@^3.0.2: - version "3.2.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" - integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== - -node-forge@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" - integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== - -node-gyp-build@^4.2.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== - -node-releases@^1.1.77: - version "1.1.77" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" - integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-url@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" - integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== - -nth-check@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" - integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== - dependencies: - boolbase "^1.0.0" - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -nwsapi@^2.1.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.11.0, object-inspect@^1.9.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" - integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== - -object-is@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" - integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -open@^7.0.3: - version "7.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" - integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== - dependencies: - is-docker "^2.0.0" - is-wsl "^2.1.1" - -optionator@^0.8.1, optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -ora@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - -ordered-binary@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.1.3.tgz#11dbc0a4cb7f8248183b9845e031b443be82571e" - integrity sha512-tDTls+KllrZKJrqRXUYJtIcWIyoQycP7cVN7kzNNnhHKF2bMKHflcAQK+pF2Eb1iVaQodHxqZQr0yv4HWLGBhQ== - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parcel@^2.0.0-rc.0: - version "2.0.0-rc.0" - resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.0.0-rc.0.tgz#862d5568f13ed4b7d762f792b23d4445f6fddaf2" - integrity sha512-40brGCIJO+KPbFNduM9qGbi2GoZw3CeEV+Kgs3Vfxr2XfR9jkqjD4lzfDY/mnE3gAbsa+5pGdiB+JrOmnzSo5A== - dependencies: - "@parcel/config-default" "2.0.0-rc.0" - "@parcel/core" "2.0.0-rc.0" - "@parcel/diagnostic" "2.0.0-rc.0" - "@parcel/events" "2.0.0-rc.0" - "@parcel/fs" "2.0.0-rc.0" - "@parcel/logger" "2.0.0-rc.0" - "@parcel/package-manager" "2.0.0-rc.0" - "@parcel/reporter-cli" "2.0.0-rc.0" - "@parcel/reporter-dev-server" "2.0.0-rc.0" - "@parcel/utils" "2.0.0-rc.0" - chalk "^4.1.0" - commander "^7.0.0" - get-port "^4.2.0" - v8-compile-cache "^2.0.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-json@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-is-inside@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-to-regexp@2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" - integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picocolors@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" - integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" - integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== - -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" - integrity sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g== - dependencies: - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-colormin@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.0.tgz#2b620b88c0ff19683f3349f4cf9e24ebdafb2c88" - integrity sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - colord "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-convert-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" - integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg== - dependencies: - postcss-value-parser "^4.1.0" - -postcss-discard-comments@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" - integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg== - -postcss-discard-duplicates@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" - integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA== - -postcss-discard-empty@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" - integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw== - -postcss-discard-overridden@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" - integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== - -postcss-merge-longhand@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" - integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw== - dependencies: - css-color-names "^1.0.1" - postcss-value-parser "^4.1.0" - stylehacks "^5.0.1" - -postcss-merge-rules@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz#d6e4d65018badbdb7dcc789c4f39b941305d410a" - integrity sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg== - dependencies: - browserslist "^4.16.6" - caniuse-api "^3.0.0" - cssnano-utils "^2.0.1" - postcss-selector-parser "^6.0.5" - vendors "^1.0.3" - -postcss-minify-font-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" - integrity sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA== - dependencies: - postcss-value-parser "^4.1.0" - -postcss-minify-gradients@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.2.tgz#7c175c108f06a5629925d698b3c4cf7bd3864ee5" - integrity sha512-7Do9JP+wqSD6Prittitt2zDLrfzP9pqKs2EcLX7HJYxsxCOwrrcLt4x/ctQTsiOw+/8HYotAoqNkrzItL19SdQ== - dependencies: - colord "^2.6" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-minify-params@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" - integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw== - dependencies: - alphanum-sort "^1.0.2" - browserslist "^4.16.0" - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" - integrity sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og== - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - -postcss-modules-extract-imports@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" - integrity sha1-thTJcgvmgW6u41+zpfqh26agXds= - dependencies: - postcss "^6.0.1" - -postcss-modules-extract-imports@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" - integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== - dependencies: - postcss "^7.0.5" - -postcss-modules-local-by-default@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-local-by-default@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" - integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== - dependencies: - icss-utils "^4.1.1" - postcss "^7.0.32" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.1.0" - -postcss-modules-scope@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" - integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - -postcss-modules-values@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" - integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^6.0.1" - -postcss-modules-values@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" - integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== - dependencies: - icss-utils "^4.0.0" - postcss "^7.0.6" - -postcss-modules@^3.2.2: - version "3.2.2" - resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-3.2.2.tgz#ee390de0f9f18e761e1778dfb9be26685c02c51f" - integrity sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw== - dependencies: - generic-names "^2.0.1" - icss-replace-symbols "^1.1.0" - lodash.camelcase "^4.3.0" - postcss "^7.0.32" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.2.0" - postcss-modules-values "^3.0.0" - string-hash "^1.1.1" - -postcss-normalize-charset@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" - integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg== - -postcss-normalize-display-values@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd" - integrity sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-positions@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5" - integrity sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg== - dependencies: - postcss-value-parser "^4.1.0" - -postcss-normalize-repeat-style@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5" - integrity sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-string@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0" - integrity sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA== - dependencies: - postcss-value-parser "^4.1.0" - -postcss-normalize-timing-functions@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c" - integrity sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-unicode@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37" - integrity sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA== - dependencies: - browserslist "^4.16.0" - postcss-value-parser "^4.1.0" - -postcss-normalize-url@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz#ddcdfb7cede1270740cf3e4dfc6008bd96abc763" - integrity sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ== - dependencies: - is-absolute-url "^3.0.3" - normalize-url "^6.0.1" - postcss-value-parser "^4.1.0" - -postcss-normalize-whitespace@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" - integrity sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA== - dependencies: - postcss-value-parser "^4.1.0" - -postcss-ordered-values@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" - integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-reduce-initial@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" - integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw== - dependencies: - browserslist "^4.16.0" - caniuse-api "^3.0.0" - -postcss-reduce-transforms@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" - integrity sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA== - dependencies: - cssnano-utils "^2.0.1" - postcss-value-parser "^4.1.0" - -postcss-selector-parser@6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: - version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" - integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - -postcss-svgo@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.2.tgz#bc73c4ea4c5a80fbd4b45e29042c34ceffb9257f" - integrity sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A== - dependencies: - postcss-value-parser "^4.1.0" - svgo "^2.3.0" - -postcss-unique-selectors@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" - integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w== - dependencies: - alphanum-sort "^1.0.2" - postcss-selector-parser "^6.0.5" - uniqs "^2.0.0" - -postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" - integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== - -postcss@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.1.tgz#000dbd1f8eef217aa368b9a212c5fc40b2a8f3f2" - integrity sha1-AA29H47vIXqjaLmiEsX8QLKo8/I= - dependencies: - chalk "^1.1.3" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.1: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -postcss@^8.2.1, postcss@^8.3.0, postcss@^8.3.6: - version "8.3.9" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.9.tgz#98754caa06c4ee9eb59cc48bd073bb6bd3437c31" - integrity sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw== - dependencies: - nanoid "^3.1.28" - picocolors "^0.2.1" - source-map-js "^0.6.2" - -posthtml-parser@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.1.tgz#63c41931a9339cc2c32aba14f06286d98f107abf" - integrity sha512-i7w2QEHqiGtsvNNPty0Mt/+ERch7wkgnFh3+JnBI2VgDbGlBqKW9eDVd3ENUhE1ujGFe3e3E/odf7eKhvLUyDg== - dependencies: - htmlparser2 "^7.1.1" - -posthtml-parser@^0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.9.1.tgz#e20dc8992514151436b6effbc50b325d2db6adc8" - integrity sha512-sF8X2cuNQMrb9wdr1GYV8X4DdJhk2lvavLV3PRsVunYNKdU/DT+w2iTgTijgpzWm9xcEsV/sz6mFAl7sGvnjFQ== - dependencies: - htmlparser2 "^6.0.0" - -posthtml-render@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-2.0.6.tgz#f39035b133f1cea1a879cba3982a7eaa1fc06c34" - integrity sha512-AvjM4yfEtjhbpZdtLOWfnezgojEtgeejSxrjTAvfr5phXjPcZQyB5QiOvYeU+rrTF0u+eqqlJrs8HS3nrPexGQ== - dependencies: - is-json "^2.0.1" - -posthtml-render@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" - integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== - dependencies: - is-json "^2.0.1" - -posthtml@^0.16.4, posthtml@^0.16.5: - version "0.16.5" - resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.5.tgz#d32f5cf32436516d49e0884b2367d0a1424136f6" - integrity sha512-1qOuPsywVlvymhTFIBniDXwUDwvlDri5KUQuBqjmCc8Jj4b/HDSVWU//P6rTWke5rzrk+vj7mms2w8e1vD0nnw== - dependencies: - posthtml-parser "^0.10.0" - posthtml-render "^3.0.0" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.0.4: - version "2.4.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" - integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.3.2, punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -purgecss@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-4.0.3.tgz#8147b429f9c09db719e05d64908ea8b672913742" - integrity sha512-PYOIn5ibRIP34PBU9zohUcCI09c7drPJJtTDAc0Q6QlRz2/CHQ8ywGLdE7ZhxU2VTqB7p5wkvj5Qcm05Rz3Jmw== - dependencies: - commander "^6.0.0" - glob "^7.0.0" - postcss "^8.2.1" - postcss-selector-parser "^6.0.2" - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -querystring-es3@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -querystring@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" - integrity sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= - -react-refresh@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" - integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== - -"readable-stream@1 || 2": - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regenerate-unicode-properties@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" - integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== - dependencies: - regenerate "^1.4.2" - -regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - -regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - -regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpu-core@^4.7.1: - version "4.8.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" - integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^9.0.0" - regjsgen "^0.5.2" - regjsparser "^0.7.0" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - -regjsgen@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" - integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== - -regjsparser@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" - integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== - dependencies: - jsesc "~0.5.0" - -relateurl@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" - integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.14.2: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sass@^1.26.3, sass@^1.32.4: - version "1.42.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.42.1.tgz#5ab17bebc1cb1881ad2e0c9a932c66ad64e441e2" - integrity sha512-/zvGoN8B7dspKc5mC6HlaygyCBRvnyzzgD5khiaCfglWztY99cYoiTUksVx11NlnemrcfH5CEaCpsUKoW0cQqg== - dependencies: - chokidar ">=3.0.0 <4.0.0" - -saxes@^3.1.9: - version "3.1.11" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^5.4.1, semver@^5.5.0, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -serve-handler@^6.0.0: - version "6.1.3" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" - integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== - dependencies: - bytes "3.0.0" - content-disposition "0.5.2" - fast-url-parser "1.1.3" - mime-types "2.1.18" - minimatch "3.0.4" - path-is-inside "1.0.2" - path-to-regexp "2.2.1" - range-parser "1.2.0" - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - -signal-exit@^3.0.2: - version "3.0.5" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" - integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-js@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" - integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@~0.5.20: - version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" - integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@~0.7.2: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -split2@^3.1.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -srcset@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" - integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - -stream-http@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" - integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.4" - readable-stream "^3.6.0" - xtend "^4.0.2" - -string-hash@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" - integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= - -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string-width@^4.1.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - -string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - -string_decoder@^1.1.1, string_decoder@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-json-comments@^3.0.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -stylehacks@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" - integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA== - dependencies: - browserslist "^4.16.0" - postcss-selector-parser "^6.0.4" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0, supports-color@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -svgo@^2.3.0, svgo@^2.6.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.7.0.tgz#e164cded22f4408fe4978f082be80159caea1e2d" - integrity sha512-aDLsGkre4fTDCWvolyW+fs8ZJFABpzLXbtdK1y71CKnHzAnpDxKXPj2mNKj+pyOXUCzFHzuxRJ94XOFygOWV3w== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - nanocolors "^0.1.12" - stable "^0.1.8" - -symbol-tree@^3.2.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -term-size@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - -terser@^5.2.0, terser@^5.8.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.9.0.tgz#47d6e629a522963240f2b55fcaa3c99083d2c351" - integrity sha512-h5hxa23sCdpzcye/7b8YqbE5OwKca/ni0RQz1uRX3tGh8haaGHqcuSqbGRybuAKNdntZ0mDgFNXPJ48xQ2RXKQ== - dependencies: - commander "^2.20.0" - source-map "~0.7.2" - source-map-support "~0.5.20" - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -timers-browserify@^2.0.11: - version "2.0.12" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" - integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tty-browserify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" - integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - -unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - -uncss@^0.17.3: - version "0.17.3" - resolved "https://registry.yarnpkg.com/uncss/-/uncss-0.17.3.tgz#50fc1eb4ed573ffff763458d801cd86e4d69ea11" - integrity sha512-ksdDWl81YWvF/X14fOSw4iu8tESDHFIeyKIeDrK6GEVTQvqJc1WlOEXqostNwOCi3qAj++4EaLsdAgPmUbEyog== - dependencies: - commander "^2.20.0" - glob "^7.1.4" - is-absolute-url "^3.0.1" - is-html "^1.1.0" - jsdom "^14.1.0" - lodash "^4.17.15" - postcss "^7.0.17" - postcss-selector-parser "6.0.2" - request "^2.88.0" - -unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - -unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - -unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== - -unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util@^0.12.0, util@^0.12.3: - version "0.12.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" - integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - -utility-types@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" - integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -vendors@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vm-browserify@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -w3c-hr-time@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== - dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" - xml-name-validator "^3.0.0" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -weak-lru-cache@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.1.2.tgz#a909a97372aabdfbfe3eb33580af255b3b198834" - integrity sha512-Bi5ae8Bev3YulgtLTafpmHmvl3vGbanRkv+qqA2AX8c3qj/MUdvSuaHq7ukDYBcMDINIaRPTPEkXSNCqqWivuA== - -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" - integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.7" - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@^6.1.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" - integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== - dependencies: - async-limiter "~1.0.0" - -ws@^7.0.0: - version "7.5.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" - integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -xxhash-wasm@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" - integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yaml@^1.10.0, yaml@^1.10.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== diff --git a/src/Resources/public/assets/oney/account/index.css b/src/Resources/public/assets/oney/account/index.css deleted file mode 100644 index 98855057..00000000 --- a/src/Resources/public/assets/oney/account/index.css +++ /dev/null @@ -1 +0,0 @@ -.sylius-customer-account-saved-cards-grid .ui.table td span.expired{color:#db2828}@media screen and (max-width:767px){.ui.segment.sylius-customer-account-saved-cards-grid{background:none;border:0;-webkit-box-shadow:none;box-shadow:none;padding:0}.ui.basic.table tbody tr{background:#fff;border:1px solid rgba(34,36,38,.26);border-radius:.28571429rem;-webkit-box-shadow:0 1px 2px 0 rgba(34,36,38,.15)!important;box-shadow:0 1px 2px 0 rgba(34,36,38,.15)!important;margin:1rem 0 2rem;padding:1em;position:relative}.ui.basic.table tbody tr:first-child{margin-top:0}.ui.basic.table tbody tr:last-child{margin-bottom:0}.sylius-customer-account-saved-cards-grid .ui.table td:before{content:attr(data-label);float:left;font-weight:700}.sylius-customer-account-saved-cards-grid .ui.table td[data-label]>span{margin-left:3px}.sylius-customer-account-saved-cards-grid .ui.table:not(.unstackable) thead{clip:rect(0 0 0 0);border:none;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sylius-customer-account-saved-cards-grid .ui.table:not(.unstackable) tr>td{display:block;font-weight:400}.sylius-customer-account-saved-cards-grid .ui.table:not(.unstackable) tr>td.actions{margin-top:1rem;text-align:right}.sylius-customer-account-saved-cards-grid .ui.table:not(.unstackable) tr>td,.sylius-customer-account-saved-cards-grid .ui.table:not(.unstackable) tr>th{padding:0!important}} \ No newline at end of file diff --git a/src/Resources/public/assets/oney/cart/index.js b/src/Resources/public/assets/oney/cart/index.js deleted file mode 100644 index 61289143..00000000 --- a/src/Resources/public/assets/oney/cart/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var n={init:function(){n.position()},position:function(){var n=$(".oney-info");n.next().insertBefore(n)}};document.addEventListener("DOMContentLoaded",n.init,!1)}(); \ No newline at end of file diff --git a/src/Resources/public/assets/oney/common/index.css b/src/Resources/public/assets/oney/common/index.css deleted file mode 100644 index b5aacf63..00000000 --- a/src/Resources/public/assets/oney/common/index.css +++ /dev/null @@ -1 +0,0 @@ -[class*=oney] *{font-family:Poppins,Arial,sans-serif;line-height:1.25}[class*=oney] * p{color:#66727f;margin:0}[class*=oney] * small{font-size:90%}.oney-info{display:inline-block;margin:1em auto .5em;position:relative}.oney-info span{font-size:16px;text-transform:uppercase;vertical-align:text-bottom}.oney-info>img{cursor:pointer;margin:0 4px;vertical-align:middle}.oney-info.loading{pointer-events:none} \ No newline at end of file diff --git a/src/Resources/public/assets/oney/common/index.js b/src/Resources/public/assets/oney/common/index.js deleted file mode 100644 index b0104ca2..00000000 --- a/src/Resources/public/assets/oney/common/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";WebFont.load({google:{families:["Poppins:400,600"]}})}(); \ No newline at end of file diff --git a/src/Resources/public/assets/oney/payment/index.css b/src/Resources/public/assets/oney/payment/index.css deleted file mode 100644 index 8854e5be..00000000 --- a/src/Resources/public/assets/oney/payment/index.css +++ /dev/null @@ -1 +0,0 @@ -.oney-payment-choice,.payplug-payment-choice{display:none}.oney-payment-choice__container,.payplug-payment-choice__container{display:flex;margin:1rem 0}.oney-payment-choice__header p,.payplug-payment-choice__header p{color:#000;margin:.5em 0!important}.oney-payment-choice__item,.payplug-payment-choice__item{flex:1 1 auto}.oney-payment-choice__item--oney_x3_with_fees,.payplug-payment-choice__item--oney_x3_with_fees{margin-right:1em}.oney-payment-choice__item input,.payplug-payment-choice__item input{display:none}.oney-payment-choice__item input:checked+label,.payplug-payment-choice__item input:checked+label{background-color:rgba(129,188,0,.13);border-color:#81bc00}.oney-payment-choice__item input:checked+label.payplug-payment-choice__label,.payplug-payment-choice__item input:checked+label.payplug-payment-choice__label{background-color:rgba(143,210,184,.13);border-color:#8fd2b8}.oney-payment-choice__item label,.payplug-payment-choice__item label{border:1px solid #ccc;border-radius:.28571429rem;box-shadow:0 1px 2px 0 rgba(34,36,38,.15);cursor:pointer;display:flex;flex-direction:column;height:100%;padding:1em;position:relative;transition:border-color,background-color .3s ease-in-out;width:100%}.oney-payment-choice__item label img,.payplug-payment-choice__item label img{vertical-align:text-bottom}.oney-payment-choice__content,.payplug-payment-choice__content{display:contents}.oney-payment-choice__content p,.payplug-payment-choice__content p{border-bottom:1px solid #ccc;color:#000;display:flex;flex-wrap:wrap;justify-content:space-between;margin:0!important;padding:.75rem 0!important}.oney-payment-choice__content p:nth-last-of-type(2),.payplug-payment-choice__content p:nth-last-of-type(2){margin-bottom:1rem!important}.oney-payment-choice__content p:last-of-type,.payplug-payment-choice__content p:last-of-type{border:none;margin-bottom:0!important;margin-top:auto!important}.oney-payment-choice__content small,.payplug-payment-choice__content small{font-size:80%;margin-top:.5rem}.oney-payment-choice__tab{display:none}.oney-payment-choice__header{margin:0 auto;text-align:center}.payplug-payment-choice__container{flex-direction:column}.payplug-payment-choice__item{margin-bottom:1em}.payplug-payment-choice__header{align-items:center;display:flex;justify-content:space-between}.payplug-payment-choice__header .card-expiry span{font-weight:700}.oney-complete-info-popin{left:0;margin:auto!important;max-width:480px;position:fixed!important;right:0;text-align:center;top:50%;transform:translateY(-50%);z-index:4}.oney-complete-info-popin__header{text-align:right}.oney-complete-info-popin__header a.close>span{background-color:rgba(0,0,0,.05);border-radius:0;height:2px;margin:0;position:absolute;right:.5em;top:1em;width:15px}.oney-complete-info-popin__header a.close>span:first-of-type{transform:rotate(45deg)}.oney-complete-info-popin__header a.close>span:last-of-type{transform:rotate(-45deg)}.oney-complete-info-popin__content{text-align:left}.oney-complete-info-popin__content ul{list-style:none;padding:0}.oney-complete-info-popin__content ul li{background-color:#db2828;border-color:#db2828;border-radius:.28571429rem;color:#fff;display:inline-block;font-size:.85714286rem;font-weight:700;margin:0 .14285714em;padding:.5833em .833em}.oney-complete-info-popin__success{display:none}.oney-complete-info-popin__success i.icon{color:#21ba45;display:inline-block!important}.ui.container{position:relative}.inactive{pointer-events:none}.overlay{background:rgba(0,0,0,.25);display:block;height:100%;position:absolute;width:100%;z-index:3}@media screen and (max-width:991px){.oney-payment-choice__container,.payplug-payment-choice__container{display:block}.oney-payment-choice__content small,.payplug-payment-choice__content small{width:100%}.oney-payment-choice__tab{display:flex;justify-content:space-between}.oney-payment-choice__tab .tablink{border:1px solid #ccc;border-bottom:0;flex:1;padding:1rem 0;text-align:center}.oney-payment-choice__tab .tablink.active{border-bottom:5px solid #81bc00}.oney-payment-choice__tab .tablink p{color:#000}.oney-payment-choice__tab .tablink:first-of-type{border-right:0}.oney-payment-choice__header,.oney-payment-choice__item{display:none}.oney-payment-choice__item input:checked+label{background-color:#fff;border-color:#ccc}.oney-payment-choice__item label{border-top-left-radius:0;border-top-right-radius:0}.oney-payment-choice__item--oney_x3_with_fees{display:block;margin-bottom:1rem;margin-right:0}}@media screen and (max-width:480px){.payplug-payment-choice__header,.payplug-payment-choice__header .card-expiry,.payplug-payment-choice__header .card-type{display:block}} \ No newline at end of file diff --git a/src/Resources/public/assets/oney/payment/index.js b/src/Resources/public/assets/oney/payment/index.js deleted file mode 100644 index 716aa105..00000000 --- a/src/Resources/public/assets/oney/payment/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var e={options:{trigger:".payment-method-choice",completeInfo:{modal:".oney-complete-info-popin",area:".ui.steps + .ui.grid"}},init:function(t){void 0===t&&(t=this.options),this.options=$.extend(!0,{},t),e.toggleGateway(),"undefined"!=typeof completeInfoRoute&&e.modalAppear(),e.tabs(),$(window).on("resize",(function(){setTimeout(e.tabs,100)})),e.tabsHandler()},toggleGateway:function(){var e=$(this.options.trigger).data("payment-input-id");$("#".concat(e,":checked")).length&&$('.payment-method-choice[data-payment-input-id="'+e+'"]').show(),$("input[id*=sylius_checkout_select_payment]").on("change",(function(e){var t=$(e.currentTarget).attr("id");$(".payment-method-choice").slideUp(),$('.payment-method-choice[data-payment-input-id="'+t+'"]').slideDown()}))},tabs:function(){window.innerWidth<=991?($(".oney-payment-choice__item").hide(),setTimeout((function(){$.each($(".oney-payment-choice__input"),(function(e,t){$(t).is(":checked")&&($(t).parent().show(),$("a.tablink[data-id=".concat($(t).val(),"]")).addClass("active"))}))}),1)):($(".oney-payment-choice__item").show(),$("a.tablink").removeClass("active"))},tabsHandler:function(){$.each($("a.tablink"),(function(e,t){$(t).click((function(e){$("a.tablink").removeClass("active"),$(this).addClass("active"),$(".oney-payment-choice__item").hide(),$("#".concat($(this).data("id"))).show(),$("input[value=".concat($(this).data("id"))).prop("checked",!0)}))}))},modalAppear:function(){var e=this,t=completeInfoRoute;$.get(t).then((function(t){$("body .pusher").append("
"),$(e.options.completeInfo.area).addClass("inactive"),$(e.options.completeInfo.area).parent().append(t),e.modalEvents()}))},modalFadeaway:function(){var e=this;$(this.options.completeInfo.modal).fadeOut(300,(function(){$(e.options.completeInfo.area).removeClass("inactive"),$(".overlay").hide()}))},modalSubmit:function(e){var t=this;e.preventDefault(),$(e.currentTarget).addClass("loading"),$.ajax({method:"post",url:completeInfoRoute,data:$(e.currentTarget).serialize(),success:function(e){Array.isArray(e)?($(t.options.completeInfo.modal+"__content").fadeOut((function(){$(t.options.completeInfo.modal+"__success").show()})),setTimeout((function(){t.modalFadeaway()}),2500)):$(t.options.completeInfo.modal).html(e),t.modalEvents()},error:function(e){console.log(e)}})},modalEvents:function(){var e=this;$(".close").on("click",(function(){e.modalFadeaway()})),$("form[name=form]").on("submit",(function(t){e.modalSubmit(t)}))}};document.addEventListener("DOMContentLoaded",(function(t){e.init(),$('form[name="sylius_checkout_select_payment"] button[type="submit"]').on("click",(function(e){$(".checkbox-oney :radio:checked").length?$(".checkbox-payplug").closest(".payment-item").find(".payment-choice__input:checked").prop("checked",!1):$(".checkbox-payplug :radio:checked").length&&$(".checkbox-oney").closest(".payment-item").find(".payment-choice__input:checked").prop("checked",!1),$("input#payplug_choice_card_other").attr("disabled",!0),$('form[name="sylius_checkout_select_payment"]').submit()}))}),!1)}(); \ No newline at end of file diff --git a/src/Resources/public/assets/oney/popin/index.css b/src/Resources/public/assets/oney/popin/index.css deleted file mode 100644 index 4c54a2ce..00000000 --- a/src/Resources/public/assets/oney/popin/index.css +++ /dev/null @@ -1 +0,0 @@ -.oney-popin{background-color:#fff;display:none;left:calc(-20em - 32px);max-width:20em;padding:10px;position:absolute;top:0;transform:translateY(calc(-33.33333% + 10px));z-index:99}.oney-popin:after{border-bottom:20px solid transparent;border-top:20px solid transparent;content:"";display:inline-block;height:0;position:absolute;right:-20px;top:calc(33.33333% - 10px);width:0}.oney-popin.enabled{border:1px solid #81bc00}.oney-popin.enabled hr{border-color:#81bc00}.oney-popin.enabled:after{border-left:20px solid #81bc00}.oney-popin.enabled a.close>span{background:#81bc00}.oney-popin.enabled .oney-popin__content>p{color:#81bc00}.oney-popin.disabled{border:1px solid #ccc}.oney-popin.disabled hr{border-color:#ccc}.oney-popin.disabled:after{border-left:20px solid #ccc}.oney-popin.disabled a.close>span{background:#ccc}.oney-popin.disabled .oney-popin__content>p{color:#66727f}.oney-popin__header{text-align:right}.oney-popin__header a.close{height:40px;position:absolute;right:0;top:0;width:40px}.oney-popin__header a.close>span{border-radius:0;height:2px;margin:0;position:absolute;right:.5em;top:1em;width:15px}.oney-popin__header a.close>span:first-of-type{transform:rotate(55deg)}.oney-popin__header a.close>span:last-of-type{transform:rotate(-55deg)}.oney-popin__content>p:not(.reasons){font-size:16px;margin-bottom:0;text-transform:uppercase}.oney-popin__content>p:not(.reasons):last-of-type{margin-bottom:1em}.oney-popin__content>p.reasons{max-width:95%}.oney-popin__footer{margin-top:1em}.oney-popin__footer>p{text-align:justify}.oney-popin section{align-items:flex-start;display:flex}.oney-popin img{height:auto;margin-right:.5em}.oney-popin hr{border-bottom:0;border-left:0;border-right:0;border-top-style:solid;border-top-width:1px;margin:1.25em 0}@media screen and (max-width:768px){.oney-popin{left:0;top:60px;transform:none}.oney-popin__header a.close{padding:10px 50px}.oney-popin:after{right:calc(50% - 10px);top:-30px;transform:rotate(-90deg)}} \ No newline at end of file diff --git a/src/Resources/public/assets/oney/popin/index.js b/src/Resources/public/assets/oney/popin/index.js deleted file mode 100644 index cdf3460b..00000000 --- a/src/Resources/public/assets/oney/popin/index.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var n={handlers:{info:".oney-info",popin:".oney-popin",codes:"#payplug-product-variant-codes"},triggers:{option:"cartItem_variant",quantity:"cartItem_quantity"},productMeta:[],storage:[],init:function(){"undefined"!=typeof productMeta&&n.watch(),n.fade(),n.closeHandler()},watch:function(){var n=this,t=function(t){var a=$("[id*=".concat(n.triggers[t]));a.length>0&&n.handleProductOptionsChange(a,t),productMeta[t]=a.val(),a.on("input",n.debounce((function(e){e.preventDefault(),a.length>0&&n.handleProductOptionsChange(a,t),productMeta[t]=$(e.currentTarget).val(),n.check()}),500))};for(var a in this.triggers)t(a);this.productMeta=productMeta},handleProductOptionsChange:function(n,t){if("option"===t){var a="";return n.each((function(n,t){var e=$(t),o=e.find("option:selected").val();a+="[data-".concat(e.attr("data-option"),'="').concat(o,'"]')})),productMeta.product_variant_code=$(this.handlers.codes).find(a).attr("data-value")}},check:function(){var n=this;this.storage=[],$.ajax({url:this.productMeta.url,data:this.productMeta,success:function(t){$(n.handlers.info).find("img:first").attr("src",n.productMeta.img[t.isEligible]),t.isEligible?$(n.handlers.popin).removeClass("disabled").addClass("enabled"):$(n.handlers.popin).removeClass("enabled").addClass("disabled")}})},debounce:function(n,t){var a;return function(){for(var e=arguments.length,o=new Array(e),i=0;i\n \n \n \n \n
\n

').concat(translations.reason,"

\n
\n "))},complete:function(){t.toggleLoader(),$(t.handlers.popin).fadeIn(),n.closeHandler()}})},toggleLoader:function(){$(this.handlers.info).toggleClass("loading").find(".dimmer").toggleClass("active")},closeHandler:function(){var n=this;$("html").not(this.handlers.popin).on("click",(function(t){t.stopPropagation(),$(n.handlers.popin).fadeOut()})),$(this.handlers.popin).find("a.close").on("click",(function(t){t.stopPropagation(),$(n.handlers.popin).fadeOut()}))}};document.addEventListener("DOMContentLoaded",n.init,!1)}(); \ No newline at end of file diff --git a/src/Resources/translations/validators.en.yml b/src/Resources/translations/validators.en.yml deleted file mode 100644 index 5f9b8273..00000000 --- a/src/Resources/translations/validators.en.yml +++ /dev/null @@ -1,13 +0,0 @@ -payplug_sylius_payplug_plugin: - secret_key: - not_blank: The secret key cannot be empty. - not_valid: This is not a valid PayPlug secret key. - oney: - not_enabled: | - Attention. To use the payment method “Oney by PayPlug“ in LIVE mode, - please contact us at support@payplug.com - not_valid_phone_number: This is not a valid cell phone number. - one_click: - can_not_save_cards: | - You do not have access to this feature. For more information, - please contact us at: support@payplug.com diff --git a/src/Resources/translations/validators.fr.yml b/src/Resources/translations/validators.fr.yml deleted file mode 100644 index b741bbb0..00000000 --- a/src/Resources/translations/validators.fr.yml +++ /dev/null @@ -1,13 +0,0 @@ -payplug_sylius_payplug_plugin: - secret_key: - not_blank: La clé secrète ne peut pas être vide. - not_valid: Ce n'est pas une clé secrète PayPlug valide. - oney: - not_enabled: | - Attention ! Pour utiliser la méthode de paiement “Oney by PayPlug” en mode LIVE, - merci de nous contacter à support@payplug.com - not_valid_phone_number: Cette valeur n'est pas un numéro de téléphone portable valide. - one_click: - can_not_save_cards: | - Vous n'avez pas accès à cette fonctionnalité. Pour plus d'informations, - veuillez nous contacter à : support@payplug.com diff --git a/src/Resources/translations/validators.it.yml b/src/Resources/translations/validators.it.yml deleted file mode 100644 index edbb21a7..00000000 --- a/src/Resources/translations/validators.it.yml +++ /dev/null @@ -1,13 +0,0 @@ -payplug_sylius_payplug_plugin: - secret_key: - not_blank: Il campo dell’ID segreto non può essere vuoto. - not_valid: ID segreto PayPlug non valido. - oney: - not_enabled: | - Attenzione! Per utilizzare il metodo di pagamento “Oney by PayPlug” in modalità LIVE, - contattaci al seguente indirizzo: support@payplug.com - not_valid_phone_number: Numero di cellulare non valido. - one_click: - can_not_save_cards: | - Non hai accesso a questa funzionalità. Per ulteriori informazioni, - contattaci al seguente indirizzo e-mail: support@payplug.com diff --git a/src/Resources/views/SyliusAdminBundle/Order/Show/_payment.html.twig b/src/Resources/views/SyliusAdminBundle/Order/Show/_payment.html.twig deleted file mode 100755 index 8fe665bf..00000000 --- a/src/Resources/views/SyliusAdminBundle/Order/Show/_payment.html.twig +++ /dev/null @@ -1,42 +0,0 @@ -{% import "@SyliusAdmin/Common/Macro/money.html.twig" as money %} -{% import '@SyliusUi/Macro/labels.html.twig' as label %} - -
-
- {{ label.default(('sylius.ui.'~payment.state)|trans) }} -
- -
-
- {{ payment.method }} -
-
- {{ money.format(payment.amount, payment.order.currencyCode) }} -
-
- {% if (payment.method.gatewayConfig.factoryName == constant('\\PayPlug\\SyliusPayPlugPlugin\\Gateway\\PayPlugGatewayFactory::FACTORY_NAME') - or payment.method.gatewayConfig.factoryName == constant('\\PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::FACTORY_NAME')) - and payment.details.payment_id is defined %} -
- {{ 'payplug_sylius_payplug_plugin.ui.payplug_id'|trans({'%paymentId%': payment.details.payment_id}) }} - {% if payment.method.gatewayConfig.factoryName == constant('\\PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::FACTORY_NAME') %} -
{{ 'payplug_sylius_payplug_plugin.ui.oney'|trans }} - {% endif %} - {% if payment.details.is_live is defined and payment.details.is_live == false %} -
{{ 'payplug_sylius_payplug_plugin.ui.test_mode'|trans }} - {% endif %} - {% if payment.details.failure is defined and payment.details.failure.message is defined %} -
{{ payment.details.failure.message }} - {% endif %} -
- {% endif %} - {% if sm_can(payment, 'complete', 'sylius_payment') %} -
-
- - - -
-
- {% endif %} -
diff --git a/src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_header.html.twig b/src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_header.html.twig deleted file mode 100644 index f9f75099..00000000 --- a/src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_header.html.twig +++ /dev/null @@ -1,6 +0,0 @@ -

- {{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.title'|trans }} -
{{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.sub_title'|trans }}
- - {{ sylius_template_event('sylius.shop.account.saved_cards.index.header.content') }} -

\ No newline at end of file diff --git a/src/Resources/views/SyliusShopBundle/Checkout/SelectPayment/_choice.html.twig b/src/Resources/views/SyliusShopBundle/Checkout/SelectPayment/_choice.html.twig deleted file mode 100644 index 5614f780..00000000 --- a/src/Resources/views/SyliusShopBundle/Checkout/SelectPayment/_choice.html.twig +++ /dev/null @@ -1,65 +0,0 @@ -{% set oneyFactoryName = constant('PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::FACTORY_NAME') %} -{% set payplugFactoryName = constant('PayPlug\\SyliusPayPlugPlugin\\Gateway\\PayplugGatewayFactory::FACTORY_NAME') %} - -{% set checkboxClass = '' %} -{% if method.gatewayConfig.factoryName == oneyFactoryName %} - {% set checkboxClass = 'checkbox-oney' %} -{% elseif method.gatewayConfig.factoryName == payplugFactoryName %} - {% set checkboxClass = 'checkbox-payplug' %} -{% endif %} - -{% set showOney = false %} -{% set showPayplug = false %} - -{% if method.gatewayConfig.factoryName == oneyFactoryName and form.parent.parent.oney_payment_choice is defined %} - {% set showOney = true %} -{% elseif is_granted('ROLE_USER') - and method.gatewayConfig.factoryName == payplugFactoryName - and form.parent.parent.payplug_card_choice is defined - and is_save_card_enabled(method) - and sylius.customer.cards is not empty -%} - {% set showPayplug = true %} -{% endif %} - -
-
-
- {{ form_widget(form, sylius_test_form_attribute('payment-method-select')) }} -
-
-
- - {% if method.gatewayConfig.factoryName == oneyFactoryName %} - - {% elseif method.gatewayConfig.factoryName == payplugFactoryName %} - {{ form_label(form, null, {'label_attr': {'data-test-payment-method-label': '', 'data-gateway': 'payplug'}}) }} - {% else %} - {{ form_label(form, null, {'label_attr': {'data-test-payment-method-label': ''}}) }} - {% endif %} - - {% if method.description is not null %} -
-

{{ method.description }}

-
- {% endif %} - {% if showOney %} -
- {{ form_row(form.parent.parent.oney_payment_choice) }} -
- {% if app.session is not null and app.session.get('oney_has_error') == true %} - - {% endif %} - {% elseif showPayplug %} -
- {{ form_row(form.parent.parent.payplug_card_choice) }} -
- {% endif %} -
-
diff --git a/src/Resources/views/SyliusShopBundle/_scripts.html.twig b/src/Resources/views/SyliusShopBundle/_scripts.html.twig deleted file mode 100644 index db8d4a8d..00000000 --- a/src/Resources/views/SyliusShopBundle/_scripts.html.twig +++ /dev/null @@ -1,3 +0,0 @@ -{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'assets/shop/js/app.js'} %} -{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/payplugsyliuspayplugplugin/assets/oney/payment/index.js'} %} - diff --git a/src/Resources/views/SyliusShopBundle/_styles.html.twig b/src/Resources/views/SyliusShopBundle/_styles.html.twig deleted file mode 100644 index 75c68235..00000000 --- a/src/Resources/views/SyliusShopBundle/_styles.html.twig +++ /dev/null @@ -1,2 +0,0 @@ -{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'assets/shop/css/style.css'} %} -{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/payplugsyliuspayplugplugin/assets/oney/payment/index.css'} %} diff --git a/src/Resources/views/SyliusUiBundle/Modal/_confirmation.html.twig b/src/Resources/views/SyliusUiBundle/Modal/_confirmation.html.twig deleted file mode 100644 index 5e0dc0fa..00000000 --- a/src/Resources/views/SyliusUiBundle/Modal/_confirmation.html.twig +++ /dev/null @@ -1,26 +0,0 @@ -{% set currentRoute = payplug_get_current_route() %} - diff --git a/src/Resources/views/card/index.html.twig b/src/Resources/views/card/index.html.twig deleted file mode 100644 index 68614718..00000000 --- a/src/Resources/views/card/index.html.twig +++ /dev/null @@ -1,10 +0,0 @@ -{% extends '@PayPlugSyliusPayPlugPlugin/card/layout.html.twig' %} - -{% import '@SyliusUi/Macro/messages.html.twig' as messages %} -{% import '@SyliusUi/Macro/buttons.html.twig' as buttons %} - -{% block title %}{{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.title'|trans }} | {{ parent() }}{% endblock %} - -{% block subcontent %} - {{ sylius_template_event('sylius.shop.account.saved_cards.index.subcontent', {'savedCards': savedCards}) }} -{% endblock %} diff --git a/src/Resources/views/card/layout.html.twig b/src/Resources/views/card/layout.html.twig deleted file mode 100644 index fc9f4bf4..00000000 --- a/src/Resources/views/card/layout.html.twig +++ /dev/null @@ -1,32 +0,0 @@ -{% extends '@SyliusShop/Account/layout.html.twig' %} - -{% block stylesheets %} - {{ parent() }} - {{ sylius_template_event('sylius.shop.account.saved_cards.layout.stylesheets') }} -{% endblock %} - -{% block content %} - {% block breadcrumb %} - - {% endblock %} - -
-
- {{ sylius_template_event('sylius.shop.account.layout.menu') }} -
-
- {{ sylius_template_event('sylius.shop.account.layout.before_subcontent') }} - - {% block subcontent %} - {% endblock %} - - {{ sylius_template_event('sylius.shop.account.layout.after_subcontent') }} -
-
-{% endblock %} diff --git a/src/Resources/views/form/complete_info_popin.html.twig b/src/Resources/views/form/complete_info_popin.html.twig deleted file mode 100644 index b7ec8455..00000000 --- a/src/Resources/views/form/complete_info_popin.html.twig +++ /dev/null @@ -1,44 +0,0 @@ -
-
- - - -
-
-
-

{{ 'payplug_sylius_payplug_plugin.form.complete_info.missing_title'|trans }}

-
- {{ form_start(form, {'attr': {'class': 'ui form loadable', 'novalidate': 'novalidate'}}) }} - {% set phoneField = form.billing_phone ?? form.shipping_phone ?? form.phone ?? null %} - {% if phoneField is not null %} -
- - {{ form_widget(phoneField, {attr: {class: 'required'}}) }} - {{ form_errors(phoneField) }} -
- {% endif %} - {% if form.email is defined %} -
- - {{ form_widget(form.email, {attr: {class: 'required'}}) }} - {{ form_errors(form.email) }} -
- {% endif %} -
- {{ form_widget(form.submit, { label: 'payplug_sylius_payplug_plugin.form.complete_info.submit', attr: { class: 'ui large primary button' }}) }} - {{ 'payplug_sylius_payplug_plugin.ui.cancel'|trans }} -
- {{ form_rest(form) }} - {{ form_end(form) }} -
-
-
- -

{{ 'payplug_sylius_payplug_plugin.form.complete_info.success_title'|trans }}

-
-

{{ 'payplug_sylius_payplug_plugin.form.complete_info.success_instruction'|trans }}

-
-
diff --git a/src/Resources/views/javascripts/oney_common.html.twig b/src/Resources/views/javascripts/oney_common.html.twig deleted file mode 100644 index d40a7e8e..00000000 --- a/src/Resources/views/javascripts/oney_common.html.twig +++ /dev/null @@ -1 +0,0 @@ -{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'bundles/payplugsyliuspayplugplugin/assets/oney/common/index.js'} %} diff --git a/src/Resources/views/javascripts/webfont_loader.html.twig b/src/Resources/views/javascripts/webfont_loader.html.twig deleted file mode 100644 index 3c3c060c..00000000 --- a/src/Resources/views/javascripts/webfont_loader.html.twig +++ /dev/null @@ -1 +0,0 @@ -{% include '@SyliusUi/_javascripts.html.twig' with {'path': 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js'} %} diff --git a/src/Resources/views/oney/cart/pay_with_oney.html.twig b/src/Resources/views/oney/cart/pay_with_oney.html.twig deleted file mode 100644 index 67e4a26f..00000000 --- a/src/Resources/views/oney/cart/pay_with_oney.html.twig +++ /dev/null @@ -1,40 +0,0 @@ -{% if is_oney_enabled() and can_show_mea() %} - {% set logo_name = '3x4x-alt.svg' %} - {% set data = [] %} - {% if oney_cart_eligible() %} - {% set logo_name = '3x4x.svg' %} - {% else %} - {% set data = oney_ineligible_reasons() %} - {% endif %} -
- {{ 'payplug_sylius_payplug_plugin.ui.or_pay_with_oney'|trans }} - oney-logo -
-
-
-
{% if data is not empty %} -
- - - -
-
- {% for reason in data.reasons %} -

{{ reason|trans(data.trans_params) }}

- {% endfor %} -
- {% endif %}
- - - - -
-{% endif %} diff --git a/src/Resources/views/oney/popin.html.twig b/src/Resources/views/oney/popin.html.twig deleted file mode 100644 index afdfc0d8..00000000 --- a/src/Resources/views/oney/popin.html.twig +++ /dev/null @@ -1,65 +0,0 @@ -{% import "@SyliusShop/Common/Macro/money.html.twig" as money %} -{% if data is empty %} - {% set data = ineligibilityData %} - {% set logo_name = '3x4x.svg' %} -
- - - -
-
- {% for reason in data.reasons %} -

{{ reason|trans(data.trans_params) }}

- {% else %} -

{{ 'payplug_sylius_payplug_plugin.ui.oney_unavailable'|trans }}

- {% endfor %} -
-{% else %} -
- - - -
-
- oney-logo -

{{ 'payplug_sylius_payplug_plugin.ui.pay'|trans }}

-

{{ 'payplug_sylius_payplug_plugin.ui.by_credit_cart'|trans }}

-
-
- payment in 3x -
-
- {{ 'payplug_sylius_payplug_plugin.ui.popin_paiement_desc'|trans({ - '%apport%': money.convertAndFormat(data['x3_with_fees']['down_payment_amount']), - '%nb_mensuality%': data['x3_with_fees']['installments']|length, - '%mensuality%': money.convertAndFormat(data['x3_with_fees']['installments'][0]['amount']), - '%cost%': money.convertAndFormat(data['x3_with_fees']['total_cost']), - '%percentage%': data['x3_with_fees']['effective_annual_percentage_rate'] - })|raw }} -
-
-
-
-
- payment in 4x -
-
- {{ 'payplug_sylius_payplug_plugin.ui.popin_paiement_desc'|trans({ - '%apport%': money.convertAndFormat(data['x4_with_fees']['down_payment_amount']), - '%nb_mensuality%': data['x4_with_fees']['installments']|length, - '%mensuality%': money.convertAndFormat(data['x4_with_fees']['installments'][0]['amount']), - '%cost%': money.convertAndFormat(data['x4_with_fees']['total_cost']), - '%percentage%': data['x4_with_fees']['effective_annual_percentage_rate'] - })|raw }} -
-
- -
-{% endif %} diff --git a/src/Resources/views/oney/product/pay_with_oney.html.twig b/src/Resources/views/oney/product/pay_with_oney.html.twig deleted file mode 100644 index 2e666cc0..00000000 --- a/src/Resources/views/oney/product/pay_with_oney.html.twig +++ /dev/null @@ -1,39 +0,0 @@ -{% if is_oney_enabled() and can_show_mea() %} - {% set logo_name = '3x4x-alt.svg' %} - {% if oney_product_eligible() %} - {% set logo_name = '3x4x.svg' %} - {% endif %} -
- {{ 'payplug_sylius_payplug_plugin.ui.or_pay_with_oney'|trans }} - oney-logo -
-
-
-
-
-
- - -
- {% for variantCodes in sylius_product_variant_codes(product, sylius.channel) %} -
- {% endfor %} -
- -{% endif %} diff --git a/src/Resources/views/stylesheets/oney_common.html.twig b/src/Resources/views/stylesheets/oney_common.html.twig deleted file mode 100644 index cee58d85..00000000 --- a/src/Resources/views/stylesheets/oney_common.html.twig +++ /dev/null @@ -1 +0,0 @@ -{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/payplugsyliuspayplugplugin/assets/oney/common/index.css'} %} diff --git a/src/Resources/views/stylesheets/saved_cards.html.twig b/src/Resources/views/stylesheets/saved_cards.html.twig deleted file mode 100644 index c793b091..00000000 --- a/src/Resources/views/stylesheets/saved_cards.html.twig +++ /dev/null @@ -1 +0,0 @@ -{% include '@SyliusUi/_stylesheets.html.twig' with {'path': 'bundles/payplugsyliuspayplugplugin/assets/oney/account/index.css'} %} \ No newline at end of file diff --git a/src/StateMachine/Transition/OrderPaymentTransitions.php b/src/StateMachine/Transition/OrderPaymentTransitions.php index 5ff74ed6..3711db32 100644 --- a/src/StateMachine/Transition/OrderPaymentTransitions.php +++ b/src/StateMachine/Transition/OrderPaymentTransitions.php @@ -4,9 +4,9 @@ namespace PayPlug\SyliusPayPlugPlugin\StateMachine\Transition; -interface OrderPaymentTransitions -{ - public const GRAPH = 'payplug_sylius_order_payment'; +use Sylius\Component\Core\OrderPaymentTransitions as BaseOrderPaymentTransitions; - public const TRANSITION_REQUEST_PAYMENT = 'request_payment'; +interface OrderPaymentTransitions extends BaseOrderPaymentTransitions +{ + public const TRANSITION_ONEY_REQUEST_PAYMENT = 'oney_request_payment'; } diff --git a/src/Twig/GetCurrentRouteExtension.php b/src/Twig/GetCurrentRouteExtension.php index a2f3a93d..c396db49 100644 --- a/src/Twig/GetCurrentRouteExtension.php +++ b/src/Twig/GetCurrentRouteExtension.php @@ -11,28 +11,25 @@ final class GetCurrentRouteExtension extends AbstractExtension { - /** @var Request|null */ - private $request; - public function __construct( - RequestStack $requestStack + private RequestStack $requestStack, ) { - $this->request = $requestStack->getCurrentRequest(); } public function getFunctions(): array { return [ - new TwigFunction('payplug_get_current_route', [$this, 'payplugGetCurrentRoute']), + new TwigFunction('payplug_get_current_route', $this->payplugGetCurrentRoute(...)), ]; } public function payplugGetCurrentRoute(): string { - if (!$this->request instanceof Request) { + $currentRequest = $this->requestStack->getCurrentRequest(); + if (!$currentRequest instanceof Request) { return ''; } - return $this->request->get('_route'); + return $currentRequest->get('_route', ''); } } diff --git a/src/Twig/GetPayPlugApiUrlExtension.php b/src/Twig/GetPayPlugApiUrlExtension.php index 236308bc..f345cff6 100644 --- a/src/Twig/GetPayPlugApiUrlExtension.php +++ b/src/Twig/GetPayPlugApiUrlExtension.php @@ -12,7 +12,7 @@ final class GetPayPlugApiUrlExtension extends AbstractExtension public function getFunctions(): array { return [ - new TwigFunction('payplug_get_api_url', [$this, 'getApiUrl']), + new TwigFunction('payplug_get_api_url', $this->getApiUrl(...)), ]; } diff --git a/src/Twig/OneyExtension.php b/src/Twig/OneyExtension.php index 4e2c9a7d..e7952400 100644 --- a/src/Twig/OneyExtension.php +++ b/src/Twig/OneyExtension.php @@ -14,34 +14,18 @@ final class OneyExtension extends AbstractExtension { - /** @var \Sylius\Component\Resource\Repository\RepositoryInterface */ - private $gatewayConfigRepository; - - /** @var \Sylius\Component\Resource\Repository\RepositoryInterface */ - private $paymentMethodRepository; - - /** @var \Sylius\Component\Channel\Context\ChannelContextInterface */ - private $channelContext; - - /** @var \PayPlug\SyliusPayPlugPlugin\Checker\OneyChecker */ - private $oneyChecker; - public function __construct( - RepositoryInterface $gatewayConfigRepository, - RepositoryInterface $paymentMethodRepository, - ChannelContextInterface $channelContext, - OneyChecker $oneyChecker + private RepositoryInterface $gatewayConfigRepository, + private RepositoryInterface $paymentMethodRepository, + private ChannelContextInterface $channelContext, + private OneyChecker $oneyChecker, ) { - $this->gatewayConfigRepository = $gatewayConfigRepository; - $this->paymentMethodRepository = $paymentMethodRepository; - $this->channelContext = $channelContext; - $this->oneyChecker = $oneyChecker; } public function getFunctions(): array { return [ - new TwigFunction('is_oney_enabled', [$this, 'isOneyEnabled']), + new TwigFunction('is_oney_enabled', $this->isOneyEnabled(...)), ]; } diff --git a/src/Twig/OneyRulesExtension.php b/src/Twig/OneyRulesExtension.php index f90b7cb3..fe2116e7 100644 --- a/src/Twig/OneyRulesExtension.php +++ b/src/Twig/OneyRulesExtension.php @@ -15,6 +15,7 @@ use Sylius\Component\Core\Repository\ProductRepositoryInterface; use Sylius\Component\Currency\Model\CurrencyInterface; use Sylius\Component\Order\Context\CartContextInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Symfony\Component\HttpFoundation\RequestStack; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -22,52 +23,29 @@ final class OneyRulesExtension extends AbstractExtension { - /** @var CartContextInterface */ - private $cartContext; - - /** @var OneyCheckerInterface */ - private $oneyChecker; - - /** @var PayPlugApiClientInterface */ - private $oneyClient; - - /** @var MoneyFormatterInterface */ - private $moneyFormatter; - - /** @var ProductRepositoryInterface */ - private $productRepository; - - /** @var RequestStack */ - private $requestStack; - public function __construct( - OneyCheckerInterface $oneyChecker, - CartContextInterface $cartContext, - PayPlugApiClientInterface $oneyClient, - MoneyFormatterInterface $moneyFormatter, - ProductRepositoryInterface $productRepository, - RequestStack $requestStack + private OneyCheckerInterface $oneyChecker, + private CartContextInterface $cartContext, + #[Autowire('@payplug_sylius_payplug_plugin.api_client.oney')] + private PayPlugApiClientInterface $oneyClient, + private MoneyFormatterInterface $moneyFormatter, + private ProductRepositoryInterface $productRepository, + private RequestStack $requestStack, ) { - $this->oneyChecker = $oneyChecker; - $this->cartContext = $cartContext; - $this->oneyClient = $oneyClient; - $this->moneyFormatter = $moneyFormatter; - $this->productRepository = $productRepository; - $this->requestStack = $requestStack; } public function getFunctions(): array { return [ - new TwigFunction('oney_cart_eligible', [$this, 'isCartEligible']), - new TwigFunction('oney_product_eligible', [$this, 'isProductEligible']), - new TwigFunction('oney_ineligible_reasons', [$this, 'getReasonsOfIneligibility']), + new TwigFunction('oney_cart_eligible', $this->isCartEligible(...)), + new TwigFunction('oney_product_eligible', $this->isProductEligible(...)), + new TwigFunction('oney_ineligible_reasons', $this->getReasonsOfIneligibility(...)), ]; } public function isCartEligible(?OrderInterface $currentCart = null): bool { - if (null === $currentCart) { + if (!$currentCart instanceof \Sylius\Component\Core\Model\OrderInterface) { /** @var OrderInterface $currentCart */ $currentCart = $this->cartContext->getCart(); } @@ -91,7 +69,7 @@ public function isCartEligible(?OrderInterface $currentCart = null): bool if (null === $currencyCode) { throw new \LogicException('No currency code found'); } - } catch (\Throwable $throwable) { + } catch (\Throwable) { // unable to find currency_code return false; } @@ -104,7 +82,7 @@ public function getReasonsOfIneligibility(?OrderInterface $currentCart = null): $data = []; $transParam = []; - if (null === $currentCart) { + if (!$currentCart instanceof \Sylius\Component\Core\Model\OrderInterface) { /** @var OrderInterface $currentCart */ $currentCart = $this->cartContext->getCart(); } @@ -137,18 +115,18 @@ public function getReasonsOfIneligibility(?OrderInterface $currentCart = null): '%min_amount%' => $this->moneyFormatter->format( $account['configuration']['oney']['min_amounts'][$currencyCode], $currencyCode, - $currentCart->getLocaleCode() + $currentCart->getLocaleCode(), ), ]; $transParam[] = [ '%max_amount%' => $this->moneyFormatter->format( $account['configuration']['oney']['max_amounts'][$currencyCode], $currencyCode, - $currentCart->getLocaleCode() + $currentCart->getLocaleCode(), ), ]; } - } catch (\Throwable $throwable) { + } catch (\Throwable) { // do nothing } @@ -164,7 +142,7 @@ public function isProductEligible(): bool $currentCart = $this->cartContext->getCart(); $request = $this->requestStack->getCurrentRequest(); - if (null === $request || 'sylius_shop_product_show' !== $request->get('_route')) { + if (!$request instanceof \Symfony\Component\HttpFoundation\Request || 'sylius_shop_product_show' !== $request->get('_route')) { return false; } @@ -183,17 +161,22 @@ public function isProductEligible(): bool if (null === $currencyCode) { throw new \LogicException('No currency code found'); } - } catch (\Throwable $throwable) { + } catch (\Throwable) { // unable to find currency_code return false; } Assert::notNull($currentCart->getLocaleCode()); + Assert::isArray($request->get('_route_params')); + Assert::keyExists($request->get('_route_params'), 'slug'); + Assert::string($request->get('_route_params')['slug']); + $product = $this->productRepository->findOneByChannelAndSlug( $channel, $currentCart->getLocaleCode(), - $request->get('_route_params')['slug'] + $request->get('_route_params')['slug'], ); + Assert::isInstanceOf($product, ProductInterface::class); /** @var ProductVariantInterface|null $firstVariant */ diff --git a/src/Twig/OneySimulationExtension.php b/src/Twig/OneySimulationExtension.php index 6f2d7097..45c3a651 100644 --- a/src/Twig/OneySimulationExtension.php +++ b/src/Twig/OneySimulationExtension.php @@ -4,7 +4,9 @@ namespace PayPlug\SyliusPayPlugPlugin\Twig; +use PayPlug\SyliusPayPlugPlugin\Gateway\OneyGatewayFactory; use PayPlug\SyliusPayPlugPlugin\Provider\OneySimulation\OneySimulationDataProviderInterface; +use PayPlug\SyliusPayPlugPlugin\Provider\OneySupportedPaymentChoiceProvider; use Sylius\Component\Core\Model\OrderInterface; use Sylius\Component\Core\Repository\OrderRepositoryInterface; use Sylius\Component\Order\Context\CartContextInterface; @@ -12,37 +14,25 @@ use Symfony\Component\HttpFoundation\RequestStack; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; +use Webmozart\Assert\Assert; final class OneySimulationExtension extends AbstractExtension { - /** @var \Sylius\Component\Order\Context\CartContextInterface */ - private $cartContext; - - /** @var \PayPlug\SyliusPayPlugPlugin\Provider\OneySimulation\OneySimulationDataProviderInterface */ - private $oneySimulationDataProvider; - - /** @var \Symfony\Component\HttpFoundation\RequestStack */ - private $requestStack; - - /** @var \Sylius\Component\Core\Repository\OrderRepositoryInterface */ - private $orderRepository; - public function __construct( - CartContextInterface $cartContext, - OneySimulationDataProviderInterface $oneySimulationDataProvider, - RequestStack $requestStack, - OrderRepositoryInterface $orderRepository + private CartContextInterface $cartContext, + private OneySimulationDataProviderInterface $oneySimulationDataProvider, + private RequestStack $requestStack, + private OrderRepositoryInterface $orderRepository, + private OneySupportedPaymentChoiceProvider $oneySupportedPaymentChoiceProvider, ) { - $this->cartContext = $cartContext; - $this->oneySimulationDataProvider = $oneySimulationDataProvider; - $this->requestStack = $requestStack; - $this->orderRepository = $orderRepository; } public function getFunctions(): array { return [ - new TwigFunction('oney_simulation_data', [$this, 'getSimulationData']), + new TwigFunction('oney_simulation_data', $this->getSimulationData(...)), + new TwigFunction('oney_supported_choices', $this->getSupportedPaymentChoices(...)), + new TwigFunction('is_oney_without_fees', $this->isPaymentChoiceWithoutFees(...)), ]; } @@ -55,14 +45,17 @@ private function getCartOrOrder(): OrderInterface { $currentRequest = $this->requestStack->getCurrentRequest(); - if (!$currentRequest instanceof Request || $currentRequest->get('_route') !== 'sylius_shop_order_show') { + if (!$currentRequest instanceof Request || 'sylius_shop_order_show' !== $currentRequest->get('_route')) { /** @var OrderInterface $cart */ $cart = $this->cartContext->getCart(); return $cart; } - $order = $this->orderRepository->findOneByTokenValue($currentRequest->get('tokenValue')); + $tokenValue = $currentRequest->get('tokenValue'); + Assert::string($tokenValue); + + $order = $this->orderRepository->findOneByTokenValue($tokenValue); if (!$order instanceof OrderInterface) { throw new \Exception('No order found.'); @@ -70,4 +63,17 @@ private function getCartOrOrder(): OrderInterface return $order; } + + public function getSupportedPaymentChoices(): array + { + return $this->oneySupportedPaymentChoiceProvider->getSupportedPaymentChoices(); + } + + public function isPaymentChoiceWithoutFees(): bool + { + return \array_filter( + $this->getSupportedPaymentChoices(), + fn (string $choice) => \in_array($choice, OneyGatewayFactory::ONEY_WITHOUT_FEES_CHOICES, true), + ) !== []; + } } diff --git a/src/Twig/PayPlugExtension.php b/src/Twig/PayPlugExtension.php index 494dc7de..9ebfcfc7 100644 --- a/src/Twig/PayPlugExtension.php +++ b/src/Twig/PayPlugExtension.php @@ -4,6 +4,7 @@ namespace PayPlug\SyliusPayPlugPlugin\Twig; +use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientFactory; use PayPlug\SyliusPayPlugPlugin\Checker\CanSaveCardCheckerInterface; use Sylius\Component\Core\Model\PaymentMethodInterface; use Twig\Extension\AbstractExtension; @@ -11,18 +12,17 @@ final class PayPlugExtension extends AbstractExtension { - /** @var CanSaveCardCheckerInterface */ - private $canSaveCardChecker; - - public function __construct(CanSaveCardCheckerInterface $canSaveCardChecker) - { - $this->canSaveCardChecker = $canSaveCardChecker; + public function __construct( + private CanSaveCardCheckerInterface $canSaveCardChecker, + private PayPlugApiClientFactory $apiClientFactory, + ) { } public function getFunctions(): array { return [ - new TwigFunction('is_save_card_enabled', [$this, 'isSaveCardAllowed']), + new TwigFunction('is_save_card_enabled', $this->isSaveCardAllowed(...)), + new TwigFunction('is_payplug_test_mode_enabled', $this->isTest(...)), ]; } @@ -30,4 +30,11 @@ public function isSaveCardAllowed(PaymentMethodInterface $paymentMethod): bool { return $this->canSaveCardChecker->isAllowed($paymentMethod); } + + public function isTest(PaymentMethodInterface $paymentMethod): bool + { + $client = $this->apiClientFactory->createForPaymentMethod($paymentMethod); + + return !(bool) $client->getAccount()['is_live']; + } } diff --git a/src/Twig/ProductVariantsCodesExtension.php b/src/Twig/ProductVariantsCodesExtension.php index 3dc49e47..df1b6b55 100644 --- a/src/Twig/ProductVariantsCodesExtension.php +++ b/src/Twig/ProductVariantsCodesExtension.php @@ -15,7 +15,7 @@ final class ProductVariantsCodesExtension extends AbstractExtension public function getFunctions(): array { return [ - new TwigFunction('sylius_product_variant_codes', [$this, 'provideVariantsCodes']), + new TwigFunction('sylius_product_variant_codes', $this->provideVariantsCodes(...)), ]; } diff --git a/src/Twig/ShowMeaExtension.php b/src/Twig/ShowMeaExtension.php index 4a1aca72..e74e601f 100644 --- a/src/Twig/ShowMeaExtension.php +++ b/src/Twig/ShowMeaExtension.php @@ -6,30 +6,26 @@ use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use Sylius\Component\Locale\Context\LocaleContextInterface; +use Symfony\Component\DependencyInjection\Attribute\Autowire; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; final class ShowMeaExtension extends AbstractExtension { - /** @var PayPlugApiClientInterface */ - private $oneyClient; - - /** @var LocaleContextInterface */ - private $localeContext; - /** @var string */ public $localeCode; - public function __construct(LocaleContextInterface $localeContext, PayPlugApiClientInterface $oneyClient) - { - $this->localeContext = $localeContext; - $this->oneyClient = $oneyClient; + public function __construct( + private LocaleContextInterface $localeContext, + #[Autowire('@payplug_sylius_payplug_plugin.api_client.oney')] + private PayPlugApiClientInterface $oneyClient, + ) { } public function getFunctions(): array { return [ - new TwigFunction('can_show_mea', [$this, 'canShowMEA']), + new TwigFunction('can_show_mea', $this->canShowMEA(...)), ]; } @@ -42,11 +38,7 @@ public function canShowMEA(): bool return false; } - if ($this->getLocaleCode() === $this->oneyClient->getAccount()['country']) { - return true; - } - - return false; + return $this->getLocaleCode() === $this->oneyClient->getAccount()['country']; } private function getLocaleCode(): string diff --git a/src/Validator/OneyInvalidDataRetriever.php b/src/Validator/OneyInvalidDataRetriever.php index fdef13e3..6ada2326 100644 --- a/src/Validator/OneyInvalidDataRetriever.php +++ b/src/Validator/OneyInvalidDataRetriever.php @@ -52,8 +52,8 @@ public function getForOrder(OrderInterface $order): array private function isCustomerEmailValid(CustomerInterface $customer): bool { - return $customer->getEmail() !== null && - \mb_strpos($customer->getEmail(), '+') === false; + return null !== $customer->getEmail() && + false === \mb_strpos($customer->getEmail(), '+'); } private function isPhoneAddressValid(AddressInterface $address): bool @@ -69,8 +69,8 @@ private function isPhoneAddressValid(AddressInterface $address): bool return false; } - return $this->phoneNumberUtil->getNumberType($parsedNumber) === PhoneNumberType::MOBILE; - } catch (\Throwable $throwable) { + return PhoneNumberType::MOBILE === $this->phoneNumberUtil->getNumberType($parsedNumber); + } catch (\Throwable) { return false; } } diff --git a/src/Validator/PaymentMethodValidator.php b/src/Validator/PaymentMethodValidator.php new file mode 100644 index 00000000..bb88cf29 --- /dev/null +++ b/src/Validator/PaymentMethodValidator.php @@ -0,0 +1,101 @@ +getGatewayConfig()) { + return; + } + + $errors = match ($paymentMethod->getGatewayConfig()->getFactoryName()) { + PayPlugGatewayFactory::FACTORY_NAME => $this->processPayplug($paymentMethod), + OneyGatewayFactory::FACTORY_NAME => $this->processOney($paymentMethod), + BancontactGatewayFactory::FACTORY_NAME => $this->processBancontact($paymentMethod), + AmericanExpressGatewayFactory::FACTORY_NAME => $this->processAmex($paymentMethod), + ApplePayGatewayFactory::FACTORY_NAME => $this->processApplePay($paymentMethod), + default => throw new \InvalidArgumentException("Unsupported payment method"), + }; + + foreach ($errors as $error) { + $this->requestStack->getSession()->getFlashBag()->add('payplug_error', $error->getMessage()); + } + if (0 !== count($errors)) { + $paymentMethod->disable(); + $this->requestStack->getSession()->getFlashBag()->add('payplug_error', 'payplug_sylius_payplug_plugin.admin.payment_method_disabled'); + } + $this->entityManager->flush(); + } + + private function processPayplug(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface + { + $config = $paymentMethod->getGatewayConfig()?->getConfig() ?? []; + $constraintList = [new IsCanSavePaymentMethod()]; + + if (true === $config[PayPlugGatewayFactory::ONE_CLICK]) { + $constraintList[] = new PayplugPermission(Permission::CAN_SAVE_CARD); + } + if (true === $config[PayPlugGatewayFactory::DEFERRED_CAPTURE]) { + $constraintList[] = new PayplugPermission(Permission::CAN_CREATE_DEFERRED_PAYMENT); + } + if (true === $config[PayPlugGatewayFactory::INTEGRATED_PAYMENT]) { + $constraintList[] = new PayplugPermission(Permission::CAN_USE_INTEGRATED_PAYMENTS); + } + + return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); + } + + private function processOney(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface + { + $constraintList = [new IsOneyEnabled()]; + return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); + } + + private function processBancontact(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface + { + $constraintList = [new IsCanSavePaymentMethod()]; + return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); + } + + private function processAmex(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface + { + $constraintList = [new IsCanSavePaymentMethod()]; + return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); + } + + private function processApplePay(PaymentMethodInterface $paymentMethod): ConstraintViolationListInterface + { + $constraintList = [new IsCanSavePaymentMethod()]; + return $this->validator->validate($paymentMethod, $constraintList, self::VALIDATION_GROUPS); + } +} diff --git a/templates/admin/payment_method/form/deferred_capture.html.twig b/templates/admin/payment_method/form/deferred_capture.html.twig new file mode 100644 index 00000000..be0c32d2 --- /dev/null +++ b/templates/admin/payment_method/form/deferred_capture.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.deferredCapture %} + +
+ {{ form_row(form) }} +
\ No newline at end of file diff --git a/templates/admin/payment_method/form/fees_for.html.twig b/templates/admin/payment_method/form/fees_for.html.twig new file mode 100644 index 00000000..5d1be6ac --- /dev/null +++ b/templates/admin/payment_method/form/fees_for.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.fees_for %} + +
+ {{ form_row(form) }} +
\ No newline at end of file diff --git a/templates/admin/payment_method/form/integrated_payment.html.twig b/templates/admin/payment_method/form/integrated_payment.html.twig new file mode 100644 index 00000000..26c8c373 --- /dev/null +++ b/templates/admin/payment_method/form/integrated_payment.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.integratedPayment %} + +
+ {{ form_row(form) }} +
\ No newline at end of file diff --git a/templates/admin/payment_method/form/live_checkbox.html.twig b/templates/admin/payment_method/form/live_checkbox.html.twig new file mode 100644 index 00000000..82c955e9 --- /dev/null +++ b/templates/admin/payment_method/form/live_checkbox.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.live %} + +
+ {{ form_row(form) }} +
diff --git a/templates/admin/payment_method/form/one_click.html.twig b/templates/admin/payment_method/form/one_click.html.twig new file mode 100644 index 00000000..9b8ca882 --- /dev/null +++ b/templates/admin/payment_method/form/one_click.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.oneClick %} + +
+ {{ form_row(form) }} +
\ No newline at end of file diff --git a/templates/admin/payment_method/form/renew_oauth.html.twig b/templates/admin/payment_method/form/renew_oauth.html.twig new file mode 100644 index 00000000..ee30d8f9 --- /dev/null +++ b/templates/admin/payment_method/form/renew_oauth.html.twig @@ -0,0 +1,5 @@ +{% set form = hookable_metadata.context.form.gatewayConfig.config.renew_oauth %} + +
+ {{ form_row(form, {attr: {name:"renew_oauth"}}) }} +
diff --git a/templates/admin/shared/flashes.html.twig b/templates/admin/shared/flashes.html.twig new file mode 100644 index 00000000..9e656426 --- /dev/null +++ b/templates/admin/shared/flashes.html.twig @@ -0,0 +1,30 @@ +{% set session = _context.app.session|default(null) %} + +
+{% for flash in session.flashbag.get('payplug_error') %} + +{% endfor %} +
diff --git a/templates/form/complete_info_popin.html.twig b/templates/form/complete_info_popin.html.twig new file mode 100644 index 00000000..80165aaa --- /dev/null +++ b/templates/form/complete_info_popin.html.twig @@ -0,0 +1,26 @@ +{% form_theme form '@SyliusShop/form/theme.html.twig' %} + +
+
+ {{ form_start(form, {'attr': {'class': 'ui form loadable', 'novalidate': 'novalidate'}}) }} + {% set phoneField = form.billing_phone ?? form.shipping_phone ?? form.phone ?? null %} + {% if phoneField is not null %} + {{ form_row(phoneField, {attr: {class: 'required'}}) }} + {% endif %} + {% if form.email is defined %} + {{ form_row(form.email, {attr: {class: 'required'}}) }} + {% endif %} +
+ {{ form_row(form.submit, { label: 'payplug_sylius_payplug_plugin.form.complete_info.submit', attr: { class: 'btn btn-primary' }}) }} +
+ {{ form_rest(form) }} + {{ form_end(form) }} +
+
+
+ +

{{ 'payplug_sylius_payplug_plugin.form.complete_info.success_title'|trans }}

+
+

{{ 'payplug_sylius_payplug_plugin.form.complete_info.success_instruction'|trans }}

+
+
diff --git a/templates/form/form_gateway_config_row.html.twig b/templates/form/form_gateway_config_row.html.twig new file mode 100644 index 00000000..e4737b58 --- /dev/null +++ b/templates/form/form_gateway_config_row.html.twig @@ -0,0 +1,33 @@ +{% block _sylius_admin_payment_method_gatewayConfig_factoryName_help %} +
+ {% set isOney = constant('\\PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::FACTORY_NAME') in form.vars.value %} + {% if isOney %} + + {% endif %} +
+{% endblock %} + +{% block _sylius_admin_payment_method_gatewayConfig_config_payplug_checkbox_widget %} +
+ {{- form_widget(form) -}} +
+{% endblock %} + +{% block _sylius_admin_payment_method_gatewayConfig_config_fees_for_row %} +
+ {{ form_label(form) }} + {%- for child in form %} +
+ {{- form_widget(child, {'attr': 'client' in child.vars.value ? {'checked': 'checked'} : {}}, sylius_test_form_attribute('option')) -}} + {{- form_label(child, null, {translation_domain: choice_translation_domain}) -}} +
+ {% endfor -%} +
+ {{- form_errors(form) -}} +{% endblock %} + +{% block _sylius_admin_payment_method_gatewayConfig_config_fees_for_label %} + {{ label|trans }} +{% endblock %} diff --git a/src/Resources/views/form/form_gateway_config_row.html.twig b/templates/form/sylius_checkout_select_payment_row.html.twig similarity index 52% rename from src/Resources/views/form/form_gateway_config_row.html.twig rename to templates/form/sylius_checkout_select_payment_row.html.twig index 010c66b8..6c27adff 100644 --- a/src/Resources/views/form/form_gateway_config_row.html.twig +++ b/templates/form/sylius_checkout_select_payment_row.html.twig @@ -1,55 +1,18 @@ -{% block _sylius_payment_method_gatewayConfig_config_secretKey_row %} -
- {{- form_label(form) -}} - {{- form_widget(form) -}} - - {{- form_help(form) -}} - - {{- form_errors(form) -}} -
-{% endblock %} - -{% block _sylius_payment_method_gatewayConfig_config_oneClick_row %} -
-
- {{- form_label(form) -}} - {{- form_widget(form) -}} -
- - - {{- form_help(form) -}} - - {% for error in errors %} -
- {{ error.message|raw }} -
- {% endfor %} -
-{% endblock %} - -{% block _sylius_payment_method_enabled_errors %} - {% for error in errors %} -
- {{ error.message|raw }} -
- {% endfor %} -{% endblock %} - -{% block _sylius_checkout_select_payment_payments_entry_oney_payment_choice_row %} +{% block oney_payment_choice_row %} {% set data = oney_simulation_data() %} - {% import "@SyliusShop/Common/Macro/money.html.twig" as money %} + {% import "@SyliusShop/shared/macro/money.html.twig" as money %} +
{% for keyChoice, choice in form.vars.choices %} {% if data is not empty %} @@ -58,35 +21,44 @@ {% endif %}
@@ -95,7 +67,7 @@
{% endblock %} -{% block _sylius_checkout_select_payment_payments_entry_payplug_card_choice_row %} +{% block payplug_saved_cards %}
{% for card in sylius.customer.cards %} {% set cardExpirationDate = ("%04d"|format(card.expirationYear) ~ '-' ~ "%02d"|format(card.expirationMonth))|date("Y-m") %} @@ -106,11 +78,15 @@ id="payplug_choice_card_{{ card.id }}" name="{{ form.vars.full_name }}" class="payplug-payment-choice__input payment-choice__input" - {% if form.vars.value is not empty %} - {{ form.vars.value == card.id ? 'checked="checked"' : '' }} - {% elseif loop.index is same as(1) %} - checked="checked" - {% endif %} + {{ + stimulus_action('@payplug/sylius-payplug-plugin/checkout-select-payment', 'enableNextStepButton', 'change') | + stimulus_action('@payplug/sylius-payplug-plugin/integrated-payment', 'handleHide', 'change') + }} + {% if form.vars.value is not empty %} + {{ form.vars.value == card.id ? 'checked="checked"' : '' }} + {% elseif loop.index is same as(1) %} + checked="checked" + {% endif %} >
{% endblock %} + +{% block _sylius_shop_checkout_select_payment_payments_entry_payplug_card_choice_row %} + {{ block('payplug_saved_cards') }} +{% endblock %} + +{% block _sylius_checkout_select_payment_payments_entry_payplug_card_choice_row %} + {{ block('payplug_saved_cards') }} +{% endblock %} diff --git a/templates/shared/form/select_payment/payment/choice.html.twig b/templates/shared/form/select_payment/payment/choice.html.twig new file mode 100644 index 00000000..19a28816 --- /dev/null +++ b/templates/shared/form/select_payment/payment/choice.html.twig @@ -0,0 +1,14 @@ +{% set form = hookable_metadata.context.form %} + +
+ {{ form_errors(form.method) }} + + {% for key, choice_form in form.method %} + {% hook 'choice' with { 'form': choice_form, 'method': form.method.vars.choices[key].data } %} + {% else %} + {% hook 'choice#unavailable' %} + {% endfor %} +
diff --git a/templates/shared/modal/index.html.twig b/templates/shared/modal/index.html.twig new file mode 100644 index 00000000..50e29481 --- /dev/null +++ b/templates/shared/modal/index.html.twig @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/src/Resources/views/shop/1click.html.twig b/templates/shop/1click.html.twig similarity index 100% rename from src/Resources/views/shop/1click.html.twig rename to templates/shop/1click.html.twig diff --git a/templates/shop/integrated/index.html.twig b/templates/shop/integrated/index.html.twig new file mode 100644 index 00000000..61a4b1d2 --- /dev/null +++ b/templates/shop/integrated/index.html.twig @@ -0,0 +1,121 @@ +{% set initRouteParam = {'paymentMethodId': paymentMethod.id} %} +{% if order is defined and order.getCheckoutCompletedAt is not null and order.tokenValue is not null %} + {% set initRouteParam = initRouteParam|merge({'orderToken': order.tokenValue}) %} +{% endif %} + + + +
+
+ {{ 'sylius.ui.loading'|trans }} +
+
+
+ + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.card_holder.error'|trans }} + + + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.empty'|trans }} + +
+
+
{{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.scheme.label'|trans }}
+ {# @todo: adding radio prop name will lead to an invalid model name but it doesn't matter for now #} +
+ + + +
+
+
+
+ + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.pan.error'|trans }} + + + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.empty'|trans }} + +
+
+
+
+ + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.exp.error'|trans }} + + + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.empty'|trans }} + +
+
+ + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.cvv.error'|trans }} + + + {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.empty'|trans }} + +
+ {% if is_save_card_enabled(paymentMethod) %} +
+ {# No name to not trigger LiveComponent #} + +
+ {% endif %} + +
+ +
+ {% set config = paymentMethod.gatewayConfig.config %} + {% if config.deferredCapture is defined and config.deferredCapture is same as true %} +
+ {{ 'payplug_sylius_payplug_plugin.ui.deferred_capture.process_order_info'|trans }} +
+ {% endif %} +
+ +
+ {{ 'payplug_sylius_payplug_plugin.ui.integrated_payment.transaction_secure.label'|trans }} +
+ +
+ +
+ + diff --git a/templates/shop/oney/cart/pay_with_oney.html.twig b/templates/shop/oney/cart/pay_with_oney.html.twig new file mode 100644 index 00000000..c68e8ae9 --- /dev/null +++ b/templates/shop/oney/cart/pay_with_oney.html.twig @@ -0,0 +1,55 @@ +{% if is_oney_enabled() and can_show_mea() %} + {% set data = [] %} + {% set logo_disabled = '3x4x-alt.svg' %} + {% set logo_enabled = '3x4x.svg' %} + {% if is_oney_without_fees() %} + {% set logo_enabled = '3x4x-without-fees.svg' %} + {% set logo_disabled = '3x4x-without-fees-alt.svg' %} + {% endif %} + {% if oney_cart_eligible() %} + {% set logo_name = logo_enabled %} + {% if is_oney_without_fees() %} + {% set logo_enabled = '3x4x-without-fees.svg' %} + {% endif %} + {% else %} + {% set data = oney_ineligible_reasons() %} + {% set logo_name = logo_disabled %} + {% endif %} +
+
+ {{ 'sylius.ui.loading'|trans }} +
+ {{ 'payplug_sylius_payplug_plugin.ui.or_pay_with_oney'|trans }} + +
+ {% if data is not empty %} +
+ + + +
+
+ {% for reason in data.reasons %} +

{{ reason|trans(data.trans_params) }}

+ {% endfor %} +
+ {% endif %} +
+
+{% endif %} diff --git a/templates/shop/oney/popin.html.twig b/templates/shop/oney/popin.html.twig new file mode 100644 index 00000000..f0b48837 --- /dev/null +++ b/templates/shop/oney/popin.html.twig @@ -0,0 +1,60 @@ +{% import "@SyliusShop/shared/macro/money.html.twig" as money %} + +{% if data is empty %} + {% set data = ineligibilityData %} +
+ + + +
+
+ {% for reason in data.reasons %} +

{{ reason|trans(data.trans_params) }}

+ {% else %} +

{{ 'payplug_sylius_payplug_plugin.ui.oney_unavailable'|trans }}

+ {% endfor %} +
+{% else %} +
+ + + +
+
+ oney-logo +

+ {{ 'payplug_sylius_payplug_plugin.ui.pay'|trans }} + {% if is_oney_without_fees() %} + {{ 'payplug_sylius_payplug_plugin.ui.without_fees'|trans }} + {% endif %} +

+

{{ 'payplug_sylius_payplug_plugin.ui.by_credit_cart'|trans }}

+ {% for key, choice in oney_supported_choices() %} +
+
+ {{ ('payplug_sylius_payplug_plugin.ui.oney_x' ~ (key + 3) ~ '_with_fees_payment')|trans }} +
+
+ {{ 'payplug_sylius_payplug_plugin.ui.popin_paiement_desc'|trans({ + '%apport%': money.convertAndFormat(data[choice]['down_payment_amount']), + '%nb_mensuality%': data[choice]['installments']|length, + '%mensuality%': money.convertAndFormat(data[choice]['installments'][0]['amount']), + '%cost%': money.convertAndFormat(data[choice]['total_cost']), + '%percentage%': data[choice]['effective_annual_percentage_rate'] + })|raw }} +
+
+ {% endfor %} + +
+{% endif %} diff --git a/templates/shop/oney/product/pay_with_oney.html.twig b/templates/shop/oney/product/pay_with_oney.html.twig new file mode 100644 index 00000000..490f8064 --- /dev/null +++ b/templates/shop/oney/product/pay_with_oney.html.twig @@ -0,0 +1,53 @@ +{% if is_oney_enabled() and can_show_mea() %} + {% set logo_disabled = '3x4x-alt.svg' %} + {% set logo_enabled = '3x4x.svg' %} + {% if is_oney_without_fees() %} + {% set logo_enabled = '3x4x-without-fees.svg' %} + {% set logo_disabled = '3x4x-without-fees-alt.svg' %} + {% endif %} + {% if oney_product_eligible() %} + {% set logo_name = logo_enabled %} + {% if is_oney_without_fees() %} + {% set logo_enabled = '3x4x-without-fees.svg' %} + {% endif %} + {% else %} + {% set logo_name = logo_disabled %} + {% endif %} +
+
+ {{ 'sylius.ui.loading'|trans }} +
+ {{ 'payplug_sylius_payplug_plugin.ui.or_pay_with_oney'|trans }} + +
+
+ {% for variant_codes in sylius_product_variant_codes(hookable_metadata.context.product, sylius.channel) %} +
+ {% endfor %} +
+
+{% endif %} diff --git a/templates/shop/saved_cards/index.html.twig b/templates/shop/saved_cards/index.html.twig new file mode 100644 index 00000000..226cb743 --- /dev/null +++ b/templates/shop/saved_cards/index.html.twig @@ -0,0 +1,10 @@ +{% extends '@PayPlugSyliusPayPlugPlugin/shop/saved_cards/layout.html.twig' %} + +{% import '@SyliusShop/shared/messages.html.twig' as messages %} +{% import '@SyliusShop/shared/buttons.html.twig' as buttons %} + +{% block title %}{{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.title'|trans }} | {{ parent() }}{% endblock %} + +{% block subcontent %} + {% hook 'sylius.shop.account.saved_cards.index.subcontent' with { _prefixes: [], savedCards: savedCards } %} +{% endblock %} diff --git a/templates/shop/saved_cards/index/_header.html.twig b/templates/shop/saved_cards/index/_header.html.twig new file mode 100644 index 00000000..63628de6 --- /dev/null +++ b/templates/shop/saved_cards/index/_header.html.twig @@ -0,0 +1,4 @@ +
+

{{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.title'|trans }}

+ {{ 'payplug_sylius_payplug_plugin.ui.account.saved_cards.sub_title'|trans }} +
\ No newline at end of file diff --git a/src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_subcontent.html.twig b/templates/shop/saved_cards/index/_subcontent.html.twig similarity index 68% rename from src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_subcontent.html.twig rename to templates/shop/saved_cards/index/_subcontent.html.twig index e3fdf002..e4412e13 100644 --- a/src/Resources/views/SyliusShopBundle/Account/SavedCards/Index/_subcontent.html.twig +++ b/templates/shop/saved_cards/index/_subcontent.html.twig @@ -1,22 +1,23 @@ -{% import '@SyliusUi/Macro/buttons.html.twig' as buttons %} -{% import '@SyliusUi/Macro/messages.html.twig' as messages %} +{% import '@SyliusShop/shared/buttons.html.twig' as buttons %} +{% import '@SyliusShop/shared/messages.html.twig' as messages %} +{% set savedCards = get_hookable_context().savedCards %} - -
- {% if savedCards|length == 0 %} - {{ messages.info('payplug_sylius_payplug_plugin.ui.account.saved_cards.no_results_to_display') }} - {% else %} - - {% endif %} -
+ + + + {% endif %} + + \ No newline at end of file diff --git a/templates/shop/saved_cards/layout.html.twig b/templates/shop/saved_cards/layout.html.twig new file mode 100644 index 00000000..190d26e9 --- /dev/null +++ b/templates/shop/saved_cards/layout.html.twig @@ -0,0 +1,29 @@ +{% extends '@SyliusShop/account/common/index.html.twig' %} + +{% set prefixes = ['sylius_shop.account.saved_card'] %} +{% from '@SyliusShop/shared/breadcrumbs.html.twig' import breadcrumbs as breadcrumbs %} + +{% block content %} +
+
+ {% block breadcrumb %} +
+ {{ breadcrumbs([ + { label: 'sylius.ui.home'|trans, path: path('sylius_shop_homepage')}, + { label: 'sylius.ui.my_account'|trans, path: path('sylius_shop_account_dashboard')}, + { label: 'payplug_sylius_payplug_plugin.ui.account.saved_cards.title'|trans, active: true} + ]) }} +
+ {% endblock %} + +
+ {% hook 'sylius_shop.account.common.index.content.menu' %} +
+ +
+ {% block subcontent %} + {% endblock %} +
+
+
+{% endblock %} diff --git a/templates/shop/select_payment/_american_express.html.twig b/templates/shop/select_payment/_american_express.html.twig new file mode 100644 index 00000000..03754436 --- /dev/null +++ b/templates/shop/select_payment/_american_express.html.twig @@ -0,0 +1,7 @@ +{% set form = hookable_metadata.context.form %} + +
diff --git a/templates/shop/select_payment/_apple_pay.html.twig b/templates/shop/select_payment/_apple_pay.html.twig new file mode 100644 index 00000000..fd8a56d2 --- /dev/null +++ b/templates/shop/select_payment/_apple_pay.html.twig @@ -0,0 +1,39 @@ +{% set form = hookable_metadata.context.form %} +{% set method = hookable_metadata.context.method %} +{% set order = hookable_metadata.context.order %} + +{% set applePaySettings = { + 'countryCode': sylius.channel.defaultLocale.code|length == 2 ? sylius.channel.defaultLocale.code : sylius.channel.defaultLocale.code|slice(3, 2), + 'currencyCode': sylius.channel.baseCurrency.code, + 'merchantCapabilities': ['supports3DS'], + 'supportedNetworks': ['cartesBancaires', 'visa', 'masterCard'], + 'total': { + 'label': sylius.channel.name, + 'type': 'final', + 'amount': (order is not null ? order.total / 100 : 0) + }, + 'applePayDomain': sylius.channel.hostname +} %} + +
+ + +
diff --git a/templates/shop/select_payment/_bancontact.html.twig b/templates/shop/select_payment/_bancontact.html.twig new file mode 100644 index 00000000..daf895e5 --- /dev/null +++ b/templates/shop/select_payment/_bancontact.html.twig @@ -0,0 +1,7 @@ +{% set form = hookable_metadata.context.form %} + +
diff --git a/templates/shop/select_payment/_oney.html.twig b/templates/shop/select_payment/_oney.html.twig new file mode 100644 index 00000000..97ae38c5 --- /dev/null +++ b/templates/shop/select_payment/_oney.html.twig @@ -0,0 +1,45 @@ +{% set form = hookable_metadata.context.form %} +{% set method = hookable_metadata.context.method %} +{% set order = hookable_metadata.context.order %} +{% set factoryName = method.gatewayConfig.factoryName %} +{% set code = method.code %} + +{% set oneyFactoryName = constant('PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::FACTORY_NAME') %} +{% set checkboxClass = 'checkbox-oney' %} + +{% set showOney = false %} +{% if form.parent.parent.oney_payment_choice is defined %} + {% set showOney = true %} +{% endif %} + +{% set values = { + modal: '.oney-complete-info-popin', + area: 'body[data-route=sylius_shop_checkout_select_payment]' +} %} + +{% if app.session is not null and app.session.flashbag.get('oney_has_error')|first is same as true %} + {% set completeInfoRoute = {route: path('payplug_sylius_oney_complete_info') ~ '?tokenValue=' ~ order.tokenValue} %} + {% set values = values|merge(completeInfoRoute) %} +{% endif %} + +{% set logo_path = 'bundles/payplugsyliuspayplugplugin/assets/oney/3x4x-without-fees.svg' %} +{% if ((form.parent.parent.oney_payment_choice.vars.choices|last).value|split('oney_')|last) not in constant('PayPlug\\SyliusPayPlugPlugin\\Gateway\\OneyGatewayFactory::ONEY_WITHOUT_FEES_CHOICES') %} + {% set logo_path = 'bundles/payplugsyliuspayplugplugin/assets/oney/3x4x.svg' %} +{% endif %} +
+ {% if showOney %} +
+ {{ form_row(form.parent.parent.oney_payment_choice) }} +
+ {% endif %} +
diff --git a/templates/shop/select_payment/_payplug.html.twig b/templates/shop/select_payment/_payplug.html.twig new file mode 100644 index 00000000..cb5fa9e5 --- /dev/null +++ b/templates/shop/select_payment/_payplug.html.twig @@ -0,0 +1,39 @@ +{% set form = hookable_metadata.context.form %} +{% set method = hookable_metadata.context.method %} +{% set order = hookable_metadata.context.order %} +{% set factoryName = method.gatewayConfig.factoryName %} +{% set code = method.code %} + +{% set payplugFactoryName = constant('PayPlug\\SyliusPayPlugPlugin\\Gateway\\PayplugGatewayFactory::FACTORY_NAME') %} +{% set checkboxClass = 'checkbox-payplug' %} + +{% set hasSavedCards = false %} +{% if is_granted('ROLE_USER') + and form.parent.parent.payplug_card_choice is defined + and is_save_card_enabled(method) + and sylius.customer.cards is not empty +%} + {% set hasSavedCards = true %} +{% endif %} + +{% set integratedPayment = false %} +{% if method.gatewayConfig.config.integratedPayment is defined and method.gatewayConfig.config.integratedPayment is same as true %} + {% set integratedPayment = true %} +{% endif %} + +
+ {% if hasSavedCards %} +
+ {{ form_row(form.parent.parent.payplug_card_choice) }} +
+ {% endif %} + + {% if integratedPayment %} + {% include '@PayPlugSyliusPayPlugPlugin/shop/integrated/index.html.twig' with { + 'paymentMethod': method, + 'payment': order.getLastPayment('cart'), + 'hasSavedCards': hasSavedCards, + 'paymentInputId': form.vars.id, + } %} + {% endif %} +
diff --git a/templates/shop/select_payment/choice.html.twig b/templates/shop/select_payment/choice.html.twig new file mode 100644 index 00000000..9e39f4f6 --- /dev/null +++ b/templates/shop/select_payment/choice.html.twig @@ -0,0 +1,12 @@ +{% set form = hookable_metadata.context.form %} +{% set method = hookable_metadata.context.method %} +{% set order = hookable_metadata.context.order %} +{% set factoryName = method.gatewayConfig.factoryName %} + +
+ {% hook '#' ~ factoryName %} +
diff --git a/tests/Behat/Context/Cli/UpdatePaymentStateContext.php b/tests/Behat/Context/Cli/UpdatePaymentStateContext.php index b030afc0..84137afa 100644 --- a/tests/Behat/Context/Cli/UpdatePaymentStateContext.php +++ b/tests/Behat/Context/Cli/UpdatePaymentStateContext.php @@ -48,7 +48,7 @@ public function __construct( PayPlugApiMocker $payPlugApiMocker, PaymentFactoryInterface $paymentFactory, PaymentRepositoryInterface $paymentRepository, - SharedStorageInterface $sharedStorage + SharedStorageInterface $sharedStorage, ) { $this->kernel = $kernel; $this->payPlugApiMocker = $payPlugApiMocker; diff --git a/tests/Behat/Context/Setup/OrderContext.php b/tests/Behat/Context/Setup/OrderContext.php index d9e7caf2..7e96fe2b 100644 --- a/tests/Behat/Context/Setup/OrderContext.php +++ b/tests/Behat/Context/Setup/OrderContext.php @@ -27,7 +27,7 @@ final class OrderContext implements Context public function __construct( ObjectManager $objectManager, StateMachineFactoryInterface $stateMachineFactory, - RegistryInterface $payum + RegistryInterface $payum, ) { $this->objectManager = $objectManager; $this->stateMachineFactory = $stateMachineFactory; diff --git a/tests/Behat/Context/Setup/PayPlugContext.php b/tests/Behat/Context/Setup/PayPlugContext.php index e8560c93..493e38b6 100644 --- a/tests/Behat/Context/Setup/PayPlugContext.php +++ b/tests/Behat/Context/Setup/PayPlugContext.php @@ -36,7 +36,7 @@ public function __construct( PaymentMethodRepositoryInterface $paymentMethodRepository, ExampleFactoryInterface $paymentMethodExampleFactory, FactoryInterface $paymentMethodTranslationFactory, - ObjectManager $paymentMethodManager + ObjectManager $paymentMethodManager, ) { $this->sharedStorage = $sharedStorage; $this->paymentMethodRepository = $paymentMethodRepository; @@ -48,13 +48,15 @@ public function __construct( /** * @Given the store has a payment method :paymentMethodName with a code :paymentMethodCode and PayPlug payment gateway */ - public function theStoreHasAPaymentMethodWithACodeAndPayPlugPaymentGateway(string $paymentMethodName, string $paymentMethodCode): void - { + public function theStoreHasAPaymentMethodWithACodeAndPayPlugPaymentGateway( + string $paymentMethodName, + string $paymentMethodCode, + ): void { $paymentMethod = $this->createPaymentMethodPayPlug( $paymentMethodName, $paymentMethodCode, PayPlugGatewayFactory::FACTORY_NAME, - 'PayPlug' + 'PayPlug', ); $paymentMethod->getGatewayConfig()->setConfig([ @@ -68,13 +70,15 @@ public function theStoreHasAPaymentMethodWithACodeAndPayPlugPaymentGateway(strin /** * @Given the store has a payment method :paymentMethodName with a code :paymentMethodCode and Oney payment gateway */ - public function theStoreHasAPaymentMethodWithACodeAndOneyPaymentGateway(string $paymentMethodName, string $paymentMethodCode): void - { + public function theStoreHasAPaymentMethodWithACodeAndOneyPaymentGateway( + string $paymentMethodName, + string $paymentMethodCode, + ): void { $paymentMethod = $this->createPaymentMethodPayPlug( $paymentMethodName, $paymentMethodCode, OneyGatewayFactory::FACTORY_NAME, - 'Oney' + 'Oney', ); $paymentMethod->getGatewayConfig()->setConfig([ @@ -88,13 +92,15 @@ public function theStoreHasAPaymentMethodWithACodeAndOneyPaymentGateway(string $ /** * @Given the store has a payment method :paymentMethodName with a code :paymentMethodCode other than PayPlug payment gateway */ - public function theStoreHasAPaymentMethodWithACodeOtherThanPayplugPaymentGateway(string $paymentMethodName, string $paymentMethodCode): void - { + public function theStoreHasAPaymentMethodWithACodeOtherThanPayplugPaymentGateway( + string $paymentMethodName, + string $paymentMethodCode, + ): void { $this->createPaymentMethodPayPlug( $paymentMethodName, $paymentMethodCode, $paymentMethodCode, - '' + '', ); $this->paymentMethodManager->flush(); @@ -106,7 +112,7 @@ private function createPaymentMethodPayPlug( string $factoryName, string $description = '', bool $addForCurrentChannel = true, - int $position = null + int $position = null, ): PaymentMethodInterface { /** @var PaymentMethodInterface $paymentMethod */ $paymentMethod = $this->paymentMethodExampleFactory->create([ diff --git a/tests/Behat/Context/Ui/Admin/ManagingPaymentMethodContext.php b/tests/Behat/Context/Ui/Admin/ManagingPaymentMethodContext.php index 80da429f..0227c28f 100644 --- a/tests/Behat/Context/Ui/Admin/ManagingPaymentMethodContext.php +++ b/tests/Behat/Context/Ui/Admin/ManagingPaymentMethodContext.php @@ -37,7 +37,7 @@ public function iShouldBeNotifiedThatCannotBeBlank(string $fields): void foreach ($fields as $field) { Assert::true($this->createPage->containsErrorWithMessage(sprintf( 'The %s cannot be empty.', - strtolower(trim($field)) + strtolower(trim($field)), ))); } } diff --git a/tests/Behat/Context/Ui/Admin/RefundContext.php b/tests/Behat/Context/Ui/Admin/RefundContext.php index 6f4e2c16..59e393cd 100644 --- a/tests/Behat/Context/Ui/Admin/RefundContext.php +++ b/tests/Behat/Context/Ui/Admin/RefundContext.php @@ -4,6 +4,7 @@ namespace Tests\PayPlug\SyliusPayPlugPlugin\Behat\Context\Ui\Admin; +use App\Entity\Payment\Payment; use Behat\Behat\Context\Context; use DateTime; use Doctrine\ORM\EntityManagerInterface; @@ -15,7 +16,6 @@ use Sylius\Behat\NotificationType; use Sylius\Behat\Service\NotificationCheckerInterface; use Sylius\Component\Core\Model\OrderInterface; -use Sylius\Component\Core\Model\Payment; use Tests\PayPlug\SyliusPayPlugPlugin\Behat\Mocker\PayPlugApiMocker; use Tests\Sylius\RefundPlugin\Behat\Context\Ui\RefundingContext; @@ -49,7 +49,7 @@ public function __construct( NotifyAction $notifyAction, NotificationCheckerInterface $notificationChecker, EntityManagerInterface $entityManager, - RefundHistoryRepositoryInterface $payplugRefundHistoryRepository + RefundHistoryRepositoryInterface $payplugRefundHistoryRepository, ) { $this->payPlugApiMocker = $payPlugApiMocker; $this->managingOrdersContext = $managingOrdersContext; @@ -77,7 +77,7 @@ public function decideToRefundProduct( OrderInterface $order, int $unitNumber, string $productName, - string $paymentMethod + string $paymentMethod, ): void { $this->payPlugApiMocker->mockApiRetrieveNotRefundablePayment(function () use ( $order, @@ -127,7 +127,7 @@ public function iShouldSeeAnErrorMessage(string $errorMessage) { $this->notificationChecker->checkNotification( $errorMessage, - NotificationType::failure() + NotificationType::failure(), ); } @@ -138,7 +138,7 @@ public function iShouldSeeASuccessMessage(string $successMessage) { $this->notificationChecker->checkNotification( $successMessage, - NotificationType::success() + NotificationType::success(), ); } @@ -149,7 +149,7 @@ public function decideToRefundProductAfter48Hours( OrderInterface $order, int $unitNumber, string $productName, - string $paymentMethod + string $paymentMethod, ): void { $this->payPlugApiMocker->mockApiRetrievePayment(function () use ( $order, diff --git a/tests/Behat/Context/Ui/Shop/CheckoutContext.php b/tests/Behat/Context/Ui/Shop/CheckoutContext.php index 712955bc..ae35eef1 100644 --- a/tests/Behat/Context/Ui/Shop/CheckoutContext.php +++ b/tests/Behat/Context/Ui/Shop/CheckoutContext.php @@ -31,7 +31,7 @@ public function __construct( CompletePageInterface $summaryPage, ShowPageInterface $orderDetails, PayPlugApiMocker $payPlugApiMocker, - PaymentPageInterface $paymentPage + PaymentPageInterface $paymentPage, ) { $this->summaryPage = $summaryPage; $this->orderDetails = $orderDetails; @@ -40,8 +40,8 @@ public function __construct( } /** - * @When I confirm my order with PayPlug payment * @Given I have confirmed my order with PayPlug payment + * @When I confirm my order with PayPlug payment */ public function iConfirmMyOrderWithPayPlugPayment(): void { @@ -57,10 +57,12 @@ public function iConfirmMyOrderWithPayPlugPayment(): void */ public function iSignInToPayPlugAndPaySuccessfully(): void { - $this->payPlugApiMocker->mockPayPlugApiGetGatewayFactoryName(function () { - $this->payPlugApiMocker->mockApiSuccessfulPayment(function () { - $this->paymentPage->notify(['id' => 1]); - $this->paymentPage->capture(); + $this->payPlugApiMocker->mockMultipleApiCancelledPayment(function () { + $this->payPlugApiMocker->mockPayPlugApiGetGatewayFactoryName(function () { + $this->payPlugApiMocker->mockApiSuccessfulPayment(function () { + $this->paymentPage->notify(['id' => 1]); + $this->paymentPage->capture(); + }); }); }); } @@ -70,19 +72,21 @@ public function iSignInToPayPlugAndPaySuccessfully(): void */ public function iHaveFailedPayPlugPayment() { - $this->payPlugApiMocker->mockApiFailedPayment(function () { - $this->paymentPage->notify(['id' => 1]); - $this->paymentPage->capture(); + $this->payPlugApiMocker->mockMultipleApiCancelledPayment(function () { + $this->payPlugApiMocker->mockApiFailedPayment(function () { + $this->paymentPage->notify(['id' => 1]); + $this->paymentPage->capture(); + }); }); } /** - * @When I cancel my PayPlug payment * @Given I have cancelled PayPlug payment + * @When I cancel my PayPlug payment */ public function iCancelMyPayPlugPayment(): void { - $this->payPlugApiMocker->mockApiCancelledPayment(function () { + $this->payPlugApiMocker->mockMultipleApiCancelledPayment(function () { $this->paymentPage->capture(['status' => PayPlugApiClientInterface::STATUS_CANCELED]); }); } @@ -98,8 +102,8 @@ public function iLeaveMyPayPlugPaymentPage(): void } /** - * @When PayPlug notified that the payment is expired * @Given I have left PayPlug payment page for more than 15 minutes + * @When PayPlug notified that the payment is expired */ public function PayPlugExpiredThePayment(): void { @@ -113,9 +117,11 @@ public function PayPlugExpiredThePayment(): void */ public function iTryToPayAgainPayPlugPayment(): void { - $this->payPlugApiMocker->mockPayPlugApiGetGatewayFactoryName(function () { - $this->payPlugApiMocker->mockApiCreatePayment(function () { - $this->orderDetails->pay(); + $this->payPlugApiMocker->mockMultipleApiCancelledPayment(function () { + $this->payPlugApiMocker->mockPayPlugApiGetGatewayFactoryName(function () { + $this->payPlugApiMocker->mockApiCreatePayment(function () { + $this->orderDetails->pay(); + }); }); }); } diff --git a/tests/Behat/Mocker/PayPlugApiClient.php b/tests/Behat/Mocker/PayPlugApiClient.php index e11ada05..f3d35e31 100644 --- a/tests/Behat/Mocker/PayPlugApiClient.php +++ b/tests/Behat/Mocker/PayPlugApiClient.php @@ -40,6 +40,11 @@ public function createPayment(array $data): Payment return $this->container->get($this->serviceName)->createPayment($data); } + public function abortPayment(string $paymentId): Payment + { + return $this->container->get($this->serviceName)->abortPayment($paymentId); + } + public function refundPayment(string $paymentId): Refund { return $this->container->get($this->serviceName)->refundPayment($paymentId); diff --git a/tests/Behat/Mocker/PayPlugApiClientFactory.php b/tests/Behat/Mocker/PayPlugApiClientFactory.php new file mode 100644 index 00000000..a143f64d --- /dev/null +++ b/tests/Behat/Mocker/PayPlugApiClientFactory.php @@ -0,0 +1,29 @@ +container = $container; + $this->serviceName = $serviceName; + } + + public function create(string $factoryName, ?string $key = null): PayPlugApiClientInterface + { + return new PayPlugApiClient($this->container, $this->serviceName); + } +} diff --git a/tests/Behat/Mocker/PayPlugApiMocker.php b/tests/Behat/Mocker/PayPlugApiMocker.php index b5fd5808..f6e07ce5 100644 --- a/tests/Behat/Mocker/PayPlugApiMocker.php +++ b/tests/Behat/Mocker/PayPlugApiMocker.php @@ -8,49 +8,45 @@ use Payplug\Resource\Refund; use PayPlug\SyliusPayPlugPlugin\ApiClient\PayPlugApiClientInterface; use PayPlug\SyliusPayPlugPlugin\Gateway\PayPlugGatewayFactory; -use Sylius\Behat\Service\Mocker\MockerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; final class PayPlugApiMocker { - /** @var ContainerInterface */ - private $container; - - /** @var MockerInterface */ - private $mocker; - - public function __construct(MockerInterface $mocker, ContainerInterface $container) + public function __construct(private ContainerInterface $container) { - $this->mocker = $mocker; - $this->container = $container; } - public function getPayPlugApiClient() + public function getPayPlugApiClient(): PayPlugApiClient { - return new PayPlugApiClient($this->container, 'payplug_sylius_payplug_plugin.api_client.payplug'); + return new PayPlugApiClient( + $this->container, + 'payplug_sylius_payplug_plugin.api_client.payplug', + ); } public function mockApiRefundedPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); $mock ->shouldReceive('refundPayment') ->andReturn(\Mockery::mock('refund', Refund::class)) ; $action(); - $this->mocker->unmockAll(); } public function mockApiRefundedWithAmountPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; $payment->is_paid = true; $payment->created_at = 1598273578; $mock @@ -69,17 +65,17 @@ public function mockApiRefundedWithAmountPayment(callable $action): void ->andReturn($refund) ; $action(); - $this->mocker->unmockAll(); } public function mockApiCreatePayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); $payment = \Mockery::mock('payment', Payment::class); - $payment->id = 1; + $payment->id = 'pay_1'; $payment->is_live = false; $payment->hosted_payment = (object) [ 'payment_url' => 'test', @@ -89,17 +85,17 @@ public function mockApiCreatePayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiSuccessfulPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ->shouldReceive('createPayment') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise', 'createPayment'); $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; $payment->is_paid = true; $payment->created_at = 1598273578; $mock @@ -111,14 +107,13 @@ public function mockApiSuccessfulPayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiRetrievePayment(callable $action): void { - $mock = $this->mocker->mockService( + $mock = \Mockery::mock( 'payplug_sylius_payplug_plugin.api_client.oney', - PayPlugApiClientInterface::class + PayPlugApiClientInterface::class, ); $payment = \Mockery::mock('payment', Payment::class); $payment->refundable_until = (new \DateTime())->add(new \DateInterval('P2D'))->getTimestamp(); @@ -128,14 +123,13 @@ public function mockApiRetrievePayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiRetrieveNotRefundablePayment(callable $action): void { - $mock = $this->mocker->mockService( + $mock = \Mockery::mock( 'payplug_sylius_payplug_plugin.api_client.oney', - PayPlugApiClientInterface::class + PayPlugApiClientInterface::class, ); $payment = \Mockery::mock('payment', Payment::class); $payment->refundable_until = (new \DateTime())->add(new \DateInterval('P2D'))->getTimestamp(); @@ -145,34 +139,38 @@ public function mockApiRetrieveNotRefundablePayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiFailedPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; $payment->is_paid = false; $mock ->shouldReceive('treat') ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiExpiredPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); + $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; $payment->status = 'failure'; $payment->is_paid = false; + $failure = new \stdClass(); $failure->code = 'timeout'; $failure->message = 'The customer has not tried to pay and left the payment page.'; @@ -182,16 +180,18 @@ public function mockApiExpiredPayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiCreatedPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); + $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; $payment->status = 'created'; $payment->is_paid = false; $mock @@ -199,47 +199,80 @@ public function mockApiCreatedPayment(callable $action): void ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function mockApiCancelledPayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); + + $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; + $payment->state = 'abort'; + $payment->is_paid = false; $mock - ->shouldReceive('initialise') + ->shouldReceive('abortPayment')->once() + ->withArgs(['pay_1']) + ->andReturn($payment) ; + + $action(); + } + + public function mockMultipleApiCancelledPayment(callable $action): void + { + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); + + $payment = \Mockery::mock('payment', Payment::class); + $payment->id = 'pay_1'; + $payment->state = 'abort'; + $payment->is_paid = false; + $mock + ->shouldReceive('abortPayment') + ->withArgs(['pay_1']) + ->andReturn($payment) + ; + $action(); - $this->mocker->unmockAll(); } public function mockApiStatePayment(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); $mock->shouldReceive('initialise'); $payment = \Mockery::mock('payment', Payment::class); $payment->state = 'failed'; $payment->is_paid = false; $payment->failure = true; $mock - ->shouldReceive('retrieve')//->withArgs(['paymentId' => '123456']) + ->shouldReceive('retrieve') ->andReturn($payment) ; $action(); - $this->mocker->unmockAll(); } public function refundPaymentWithAmount(callable $action): void { $action(); - $this->mocker->unmockAll(); } public function mockApiRefundedFromPayPlugPortal(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); - $mock - ->shouldReceive('initialise') - ; + $mock = \Mockery::mock( + 'payplug_sylius_payplug_plugin.api_client.payplug', + PayPlugApiClientInterface::class, + ); + $mock->shouldReceive('initialise'); $refund = \Mockery::mock('refund', Refund::class); $refund->amount = 34000; $refund->currency = 'EUR'; @@ -251,19 +284,18 @@ public function mockApiRefundedFromPayPlugPortal(callable $action): void ->andReturn($refund) ; $action(); - $this->mocker->unmockAll(); } public function mockApiRefundPartiallyFromPayPlugPortal(callable $action, int $amount): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); + $mock = \Mockery::mock('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); $mock ->shouldReceive('initialise') ; $refund = \Mockery::mock('refund', Refund::class); $refund->amount = $amount; $refund->currency = 'EUR'; - $refund->id = \bin2hex(\random_bytes(10)); + $refund->id = 'pay_' . \bin2hex(\random_bytes(10)); $refund->payment_id = 'pay_2PykkdCqJLzJ7nYM5gV4RZ'; $refund->metadata = ['requested_by' => 'payplug']; $mock @@ -271,12 +303,11 @@ public function mockApiRefundPartiallyFromPayPlugPortal(callable $action, int $a ->andReturn($refund) ; $action(); - $this->mocker->unmockAll(); } public function mockPayPlugApiGetGatewayFactoryName(callable $action): void { - $mock = $this->mocker->mockService('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); + $mock = \Mockery::mock('payplug_sylius_payplug_plugin.api_client.payplug', PayPlugApiClientInterface::class); $mock ->shouldReceive([ 'getGatewayFactoryName' => PayPlugGatewayFactory::FACTORY_NAME, @@ -284,15 +315,14 @@ public function mockPayPlugApiGetGatewayFactoryName(callable $action): void ; $action(); - $this->mocker->unmockAll(); } public function enableOney(): void { $this->mocker->unmockAll(); - $mock = $this->mocker->mockService( + $mock = \Mockery::mock( 'payplug_sylius_payplug_plugin.api_client.oney', - PayPlugApiClientInterface::class + PayPlugApiClientInterface::class, ); $mock->shouldReceive([ 'getPermissions' => ['can_use_oney' => true], @@ -318,10 +348,9 @@ public function enableOney(): void public function disableOney(): void { - $this->mocker->unmockAll(); - $mock = $this->mocker->mockService( + $mock = \Mockery::mock( 'payplug_sylius_payplug_plugin.api_client.oney', - PayPlugApiClientInterface::class + PayPlugApiClientInterface::class, ); $mock->shouldReceive([ 'getPermissions' => ['can_use_oney' => false], diff --git a/tests/Behat/Page/Shop/Payum/PaymentPage.php b/tests/Behat/Page/Shop/Payum/PaymentPage.php index daae435f..b2b63b21 100644 --- a/tests/Behat/Page/Shop/Payum/PaymentPage.php +++ b/tests/Behat/Page/Shop/Payum/PaymentPage.php @@ -22,7 +22,7 @@ public function __construct( Session $session, $parameters, RepositoryInterface $securityTokenRepository, - KernelBrowser $client + KernelBrowser $client, ) { parent::__construct($session, $parameters); diff --git a/tests/Behat/Resources/services.xml b/tests/Behat/Resources/services.xml index 17aaf2a8..561a4c21 100644 --- a/tests/Behat/Resources/services.xml +++ b/tests/Behat/Resources/services.xml @@ -18,7 +18,7 @@ - + diff --git a/tests/Behat/Resources/services/contexts/setup.xml b/tests/Behat/Resources/services/contexts/setup.xml index d135a3d3..91d432e6 100644 --- a/tests/Behat/Resources/services/contexts/setup.xml +++ b/tests/Behat/Resources/services/contexts/setup.xml @@ -13,11 +13,11 @@ - - - - - - + + + + + + diff --git a/tests/Behat/Resources/services/contexts/ui.xml b/tests/Behat/Resources/services/contexts/ui.xml index 654fc942..bba842a6 100644 --- a/tests/Behat/Resources/services/contexts/ui.xml +++ b/tests/Behat/Resources/services/contexts/ui.xml @@ -9,7 +9,7 @@ - + diff --git a/tests/Behat/Resources/suites/ui/paying_with_payplug_for_order.yml b/tests/Behat/Resources/suites/ui/paying_with_payplug_for_order.yml index 8f06e1fb..659d5003 100644 --- a/tests/Behat/Resources/suites/ui/paying_with_payplug_for_order.yml +++ b/tests/Behat/Resources/suites/ui/paying_with_payplug_for_order.yml @@ -31,7 +31,7 @@ default: - payplug_sylius_payplug_plugin.behat.context.setup.payplug - - sylius.behat.context.ui.paypal +# - sylius.behat.context.ui.paypal - sylius.behat.context.ui.shop.cart - sylius.behat.context.ui.shop.checkout - sylius.behat.context.ui.shop.checkout.addressing diff --git a/tests/Behat/Resources/suites/ui/refunding_payplug_payment.yml b/tests/Behat/Resources/suites/ui/refunding_payplug_payment.yml index 71120c5f..decb7841 100644 --- a/tests/Behat/Resources/suites/ui/refunding_payplug_payment.yml +++ b/tests/Behat/Resources/suites/ui/refunding_payplug_payment.yml @@ -3,7 +3,6 @@ default: ui_refunding_payplug_payment: contexts: - sylius.behat.context.hook.doctrine_orm - - sylius.behat.context.hook.email_spool - sylius.behat.context.setup.channel - sylius.behat.context.setup.currency @@ -24,7 +23,7 @@ default: - sylius.behat.context.setup.user - payplug_sylius_payplug_plugin.behat.context.setup.payplug - - payplug_sylius_payplug_plugin.behat.context.setup.order +# - payplug_sylius_payplug_plugin.behat.context.setup.order - sylius.behat.context.transform.address - sylius.behat.context.transform.channel diff --git a/tests/PHPUnit/PhoneNumberFormatTest.php b/tests/PHPUnit/PhoneNumberFormatTest.php index c6d4f0bd..8fcbcd01 100644 --- a/tests/PHPUnit/PhoneNumberFormatTest.php +++ b/tests/PHPUnit/PhoneNumberFormatTest.php @@ -19,7 +19,7 @@ public function testFormatNumberMethod(string $input, string $isoCode, array $ex $phoneNumberUtil = PhoneNumberUtil::getInstance(); $parsed = $phoneNumberUtil->parse($input, $isoCode); - self::assertEquals($expectedOutput['is_mobile'], $phoneNumberUtil->getNumberType($parsed) === PhoneNumberType::MOBILE); + self::assertEquals($expectedOutput['is_mobile'], PhoneNumberType::MOBILE === $phoneNumberUtil->getNumberType($parsed)); } public function landlinePhoneNumbersDataProvider(): \Generator diff --git a/tests/TestApplication/.env b/tests/TestApplication/.env new file mode 100644 index 00000000..8b9cf095 --- /dev/null +++ b/tests/TestApplication/.env @@ -0,0 +1,7 @@ +DATABASE_URL=mysql://root@127.0.0.1/test_application_%kernel.environment% + +SYLIUS_TEST_APP_CONFIGS_TO_IMPORT="@PayPlugSyliusPayPlugPlugin/tests/TestApplication/config/config.yaml" +SYLIUS_TEST_APP_ROUTES_TO_IMPORT="@PayPlugSyliusPayPlugPlugin/tests/TestApplication/config/routing.yaml" +SYLIUS_TEST_APP_BUNDLES_PATH="tests/TestApplication/config/bundles.php" + +SYLIUS_MESSENGER_TRANSPORT_PAYMENT_REQUEST_DSN="sync://" diff --git a/tests/TestApplication/config/bundles.php b/tests/TestApplication/config/bundles.php new file mode 100644 index 00000000..48514e52 --- /dev/null +++ b/tests/TestApplication/config/bundles.php @@ -0,0 +1,8 @@ + ['all' => true], + Knp\Bundle\SnappyBundle\KnpSnappyBundle::class => ['all' => true], + Sylius\RefundPlugin\SyliusRefundPlugin::class => ['all' => true], + PayPlug\SyliusPayPlugPlugin\PayPlugSyliusPayPlugPlugin::class => ['all' => true], +]; diff --git a/tests/TestApplication/config/config.yaml b/tests/TestApplication/config/config.yaml new file mode 100644 index 00000000..1acc0396 --- /dev/null +++ b/tests/TestApplication/config/config.yaml @@ -0,0 +1,87 @@ +imports: + - { resource: "@SyliusRefundPlugin/config/config.yaml" } + - { resource: "@PayPlugSyliusPayPlugPlugin/config/config.yml" } + +parameters: + locale: fr_FR + currency: EUR + sylius_refund.supported_gateways: + - payplug + - payplug_oney + - cash_on_delivery + +sylius_refund: + pdf_generator: + enabled: false + +doctrine: + orm: + entity_managers: + default: + mappings: + TestApplication: + is_bundle: false + type: attribute + dir: '%kernel.project_dir%/../../../tests/TestApplication/src/Entity' + prefix: Tests\PayPlug\SyliusPayPlugPlugin +sylius_customer: + resources: + customer: + classes: + model: Tests\PayPlug\SyliusPayPlugPlugin\Entity\Customer +sylius_payment: + resources: + payment_method: + classes: + model: Tests\PayPlug\SyliusPayPlugPlugin\Entity\PaymentMethod + payment: + classes: + model: Tests\PayPlug\SyliusPayPlugPlugin\Entity\Payment +sylius_fixtures: + suites: + default: + fixtures: + geographical: + options: + countries: + - 'US' + - 'FR' + - 'DE' + - 'AU' + - 'CA' + - 'MX' + - 'NZ' + - 'PT' + - 'ES' + - 'CN' + - 'GB' + - 'PL' + zones: + FR: + name: 'France' + countries: + - 'FR' + + channel: + options: + custom: + fashion_web_store: + name: 'Fashion Web Store' + code: 'FASHION_WEB' + locales: + - '%locale%' + currencies: + - 'EUR' + enabled: true + hostname: '%env(resolve:SYLIUS_FIXTURES_HOSTNAME)%' + theme_name: '%env(resolve:SYLIUS_FIXTURES_THEME_NAME)%' + shop_billing_data: + company: 'Sylius' + tax_id: '0001112222' + country_code: 'FR' + street: 'Test St. 15' + city: 'eCommerce Town' + postcode: '00 33 22' + menu_taxon: 'MENU_CATEGORY' + contact_phone_number: '+41 123 456 789' + contact_email: 'contact@example.com' diff --git a/tests/TestApplication/config/routing.yaml b/tests/TestApplication/config/routing.yaml new file mode 100644 index 00000000..54af5a42 --- /dev/null +++ b/tests/TestApplication/config/routing.yaml @@ -0,0 +1,5 @@ +sylius_refund: + resource: "@SyliusRefundPlugin/config/routes.yaml" + +sylius_payplug: + resource: "@PayPlugSyliusPayPlugPlugin/config/routing.yaml" diff --git a/tests/TestApplication/package.json b/tests/TestApplication/package.json new file mode 100644 index 00000000..0280f00d --- /dev/null +++ b/tests/TestApplication/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@payplug/sylius-payplug-plugin": "file:../../../assets" + } +} diff --git a/tests/TestApplication/src/Entity/Customer.php b/tests/TestApplication/src/Entity/Customer.php new file mode 100644 index 00000000..05196860 --- /dev/null +++ b/tests/TestApplication/src/Entity/Customer.php @@ -0,0 +1,16 @@ +refundHistories = new ArrayCollection(); + } +} diff --git a/install/Application/src/Entity/Payment/PaymentMethod.php b/tests/TestApplication/src/Entity/PaymentMethod.php similarity index 79% rename from install/Application/src/Entity/Payment/PaymentMethod.php rename to tests/TestApplication/src/Entity/PaymentMethod.php index 20a46927..7dad0a1c 100644 --- a/install/Application/src/Entity/Payment/PaymentMethod.php +++ b/tests/TestApplication/src/Entity/PaymentMethod.php @@ -2,18 +2,17 @@ declare(strict_types=1); -namespace App\Entity\Payment; +namespace Tests\PayPlug\SyliusPayPlugPlugin\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use PayPlug\SyliusPayPlugPlugin\Entity\Traits\PaymentMethodTrait; use Sylius\Component\Core\Model\PaymentMethod as BasePaymentMethod; use Sylius\Component\Payment\Model\PaymentMethodTranslationInterface; +use Sylius\Component\Payment\Model\PaymentMethodTranslation; -/** - * @ORM\Entity - * @ORM\Table(name="sylius_payment_method") - */ +#[ORM\Entity] +#[ORM\Table(name: 'sylius_payment_method')] class PaymentMethod extends BasePaymentMethod { use PaymentMethodTrait; diff --git a/src/Resources/translations/flashes.en.yml b/translations/flashes.en.yml similarity index 57% rename from src/Resources/translations/flashes.en.yml rename to translations/flashes.en.yml index 68820d60..1faaa11a 100644 --- a/src/Resources/translations/flashes.en.yml +++ b/translations/flashes.en.yml @@ -5,3 +5,7 @@ payplug_sylius_payplug_plugin: transaction_failed_1click: The transaction was not completed and your card was not charged. warning: payment_success_no_card_saved: The payment was successful but we were unable to save your credit card details. + admin: + oauth_callback_success: The OAuth connection was established successfully. + payment_method_disabled: ⚠️ The payment method has been disabled because some validation criteria are not met. + oauth_setup_error: An error occurred while setting up the OAuth connection. Please try again. diff --git a/src/Resources/translations/flashes.fr.yml b/translations/flashes.fr.yml similarity index 57% rename from src/Resources/translations/flashes.fr.yml rename to translations/flashes.fr.yml index 6449312e..b05b5110 100644 --- a/src/Resources/translations/flashes.fr.yml +++ b/translations/flashes.fr.yml @@ -5,3 +5,7 @@ payplug_sylius_payplug_plugin: transaction_failed_1click: La transaction a échoué, votre carte de paiement ne sera pas débitée. warning: payment_success_no_card_saved: Le paiement a été effectué avec succès, mais nous n'avons pas pu enregistrer votre carte bancaire. + admin: + oauth_callback_success: La connexion OAuth a été établie avec succès. + payment_method_disabled: ⚠️ La méthode de paiement a été désactivée car certains critères de validation ne sont pas remplis. + oauth_setup_error: Une erreur s'est produite lors de la configuration de la connexion OAuth. Veuillez réessayer. diff --git a/src/Resources/translations/flashes.it.yml b/translations/flashes.it.yml similarity index 57% rename from src/Resources/translations/flashes.it.yml rename to translations/flashes.it.yml index 7a9ac5db..10cd5113 100644 --- a/src/Resources/translations/flashes.it.yml +++ b/translations/flashes.it.yml @@ -5,3 +5,7 @@ payplug_sylius_payplug_plugin: transaction_failed_1click: La transazione non è stata conclusa e non è stato effettuato alcun addebito sulla tua carta. warning: payment_success_no_card_saved: Il pagamento è andato a buon fine ma non è stato possibile salvare la tua carta di credito. + admin: + oauth_callback_success: La connessione OAuth è stata stabilita con successo. + payment_method_disabled: ⚠️ Il metodo di pagamento è stato disattivato perché alcuni criteri di validazione non sono soddisfatti. + oauth_setup_error: Si è verificato un errore durante la configurazione della connessione OAuth. Per favore riprova. diff --git a/src/Resources/translations/messages.en.yml b/translations/messages.en.yml similarity index 59% rename from src/Resources/translations/messages.en.yml rename to translations/messages.en.yml index fb129f59..c62ba008 100644 --- a/src/Resources/translations/messages.en.yml +++ b/translations/messages.en.yml @@ -1,4 +1,10 @@ payplug_sylius_payplug_plugin: + admin: + ui: + oney_x3_with_fees_payment: Oney 3x + oney_x4_with_fees_payment: Oney 4x + oney_x3_without_fees_payment: Oney 3x Without Fees + oney_x4_without_fees_payment: Oney 4x Without Fees ui: account: saved_cards: @@ -17,25 +23,31 @@ payplug_sylius_payplug_plugin: deleted_error: An error occurred. Please retry in few seconds. confirmation_modal: confirm_card_deletion: Are you sure you want to delete this card? + bancontact_gateway_label: Bancontact by Payplug + apple_pay_gateway_label: Apple Pay by Payplug + american_express_gateway_label: American Express by Payplug + apple_pay_not_available: Apple Pay is not available on this browser or device. error: billing.postcode: The postal code %postalCode% entered for the billing address is invalid shipping.postcode: The postal code %postalCode% entered for the delivery address is invalid - secret_key: Secret key - payplug_gateway_label: PayPlug + payplug_gateway_label: Payplug payment_refund_locally: The payment refund was made locally only. - retrieve_secret_key_in_api_configuration_portal: Find your LIVE and TEST Secret Keys in your PayPlug portal test_mode: TEST Mode payplug_id: | - PayPlug ID: %paymentId% - payplug_refund_gateway_is_not_activated: PayPlug has not been activated as a refund method + Payplug ID: %paymentId% + payplug_refund_gateway_is_not_activated: Payplug has not been activated as a refund method impossible_to_refund_this_payment: This payment cannot be refunded - oney_gateway_label: Oney by PayPlug + oney_gateway_label: Oney by Payplug oney: Oney oney_transaction_less_than_forty_eight_hours: The refund will be possible 48 hours after the last payment or refund transaction. or_pay_with_oney: Or pay in pay: Payment 3x_payment: Pay in 3 installments 4x_payment: Pay in 4 installments + oney_x3_with_fees_payment: Payment in 3x + oney_x4_with_fees_payment: Payment in 4x + oney_x3_without_fees_payment: Payment in 3x without fees + oney_x4_without_fees_payment: Payment in 4x without fees by_credit_cart: By credit card cancel: Cancel popin_close: Close @@ -71,6 +83,38 @@ payplug_sylius_payplug_plugin: invalid_cart_price: To pay with Oney, the total amount of your cart must be between %min_amount% and %max_amount%. refund_minimum_amount_requirement_not_met: The amount to be refunded must be at least €0.10 oney_unavailable: Your payment schedule simulation is temporarily unavailable. You will find this information at the payment stage. + oney_gateway_config: + info: | + Allow customers to spread out payments over 3 or 4 installments from 100€ to 3000€. + Learn more + fees_for: + title: 'The fees are:' + client: Split between you and your customers + merchant: For you + integrated_payment: + card_holder.title: 'Cardholder name' + card_holder.error: 'Invalid Name and/or Last Name.' + pan.title: 'Card number' + pan.error: 'Invalid card number.' + cvv.title: '123' + cvv.error: 'Invalid CVV.' + exp.title: 'MM/YY' + exp.error: 'Invalid expiration date.' + empty: 'Mandatory field.' + scheme.label: 'Your card' + place_order.label: 'Place order' + transaction_secure.label: 'Transaction secured by' + privacy_policy.label: 'Privacy Policy' + deferred_capture: + process_order_info: | + You will be charged when your order is processed. + live: LIVE Mode + live_help: | + When this option is enabled, LIVE mode is used.
+ If disabled, TEST mode will be applied + renew_oauth: Force OAuth reconnection + renew_oauth_help: | + If this option is checked, a new authentication flow will be started when clicking the "Update" button. form: oney_error: Some missing information is required to pay using Oney by Payplug complete_info: @@ -84,7 +128,14 @@ payplug_sylius_payplug_plugin: submit: Confirm and continue base_currency_not_euro: | Channel #channel_code#: #payment_method# is only available on channels with EURO as a currency - only_one_gateway_allowed: Please note that the %gateway_title% payment method has already been set. To change it, go to your payment methods. + only_one_gateway_allowed: | + Please note that the %gateway_title% payment method has already been set. To change it, go to your payment methods. one_click_enable: Enable One click one_click_help: | Allow your customers to save their credit card details for later + + integrated_payment_enable: Enable payment integrated + + deferred_capture_enable: Enable deferred capture + deferred_capture_help: | + Please ensure that a delayed capture trigger has been added to the project source code. diff --git a/src/Resources/translations/messages.fr.yml b/translations/messages.fr.yml similarity index 52% rename from src/Resources/translations/messages.fr.yml rename to translations/messages.fr.yml index a1e62fe4..9a9de68e 100644 --- a/src/Resources/translations/messages.fr.yml +++ b/translations/messages.fr.yml @@ -1,4 +1,10 @@ payplug_sylius_payplug_plugin: + admin: + ui: + oney_x3_with_fees_payment: Oney 3x + oney_x4_with_fees_payment: Oney 4x + oney_x3_without_fees_payment: Oney 3x Sans Frais + oney_x4_without_fees_payment: Oney 4x Sans Frais ui: account: saved_cards: @@ -17,25 +23,30 @@ payplug_sylius_payplug_plugin: deleted_error: Une erreur s'est produite. Veuillez réessayer dans quelques secondes. confirmation_modal: confirm_card_deletion: Êtes-vous sûr(e) de vouloir supprimer cette carte ? + bancontact_gateway_label: Bancontact by Payplug + apple_pay_gateway_label: Apple Pay by Payplug + american_express_gateway_label: American Express by Payplug + apple_pay_not_available: Apple Pay n'est pas disponible sur ce navigateur ou appareil. error: billing.postcode: Le code postal %postalCode% renseigné pour l'adresse de facturation est invalide shipping.postcode: Le code postal %postalCode% renseigné pour l'adresse de livraison est invalide - secret_key: Clé secrète - payplug_gateway_label: PayPlug + payplug_gateway_label: Payplug payment_refund_locally: Le remboursement du paiement a été effectué uniquement localement. - retrieve_secret_key_in_api_configuration_portal: Retrouvez vos Secret Key LIVE et TEST dans votre portail PayPlug test_mode: Mode TEST payplug_id: | - ID PayPlug : %paymentId% - payplug_refund_gateway_is_not_activated: PayPlug n'a pas été activé comme méthode de remboursement + ID Payplug : %paymentId% + payplug_refund_gateway_is_not_activated: Payplug n'a pas été activé comme méthode de remboursement impossible_to_refund_this_payment: Impossible de rembourser ce paiement - oney_gateway_label: Oney by PayPlug + oney_gateway_label: Oney by Payplug oney: Oney oney_transaction_less_than_forty_eight_hours: Le remboursement sera possible 48h après la dernière transaction de paiement ou de remboursement. or_pay_with_oney: Ou payez en pay: Paiement - 3x_payment: Paiement en 3x - 4x_payment: Paiement en 4x + without_fees: sans frais + oney_x3_with_fees_payment: Paiement en 3x + oney_x4_with_fees_payment: Paiement en 4x + oney_x3_without_fees_payment: Paiement en 3x sans frais + oney_x4_without_fees_payment: Paiement en 4x sans frais by_credit_cart: Par carte bancaire card_expires_on: "Expire le :" pay_with_another_card: Payer avec une autre carte @@ -66,6 +77,23 @@ payplug_sylius_payplug_plugin: 170 Croix - 546 380 197 RCS Lille Métro- pole - n° Orias 07 023 261 www.orias.fr. + Correspondance : CS 60 006 - 59895 + Lille Cedex - www.oney.fr + + popin_legal_mention_without_fees: | + + Offre de financement sans assurance avec apport + obligatoire, réservée aux particuliers + et valable pour tout achat de %min_amount% à + %max_amount%. Sous réserve d’acceptation par + Oney Bank. Vous disposez d’un délai + de 14 jours pour renoncer à votre + crédit. Oney Bank - SA au capital de + 50 741 215€ - 40 Avenue de Flandre 59 + + 170 Croix - 546 380 197 RCS Lille Métro- + pole - n° Orias 07 023 261 www.orias.fr. + Correspondance : CS 60 006 - 59895 Lille Cedex - www.oney.fr @@ -73,6 +101,40 @@ payplug_sylius_payplug_plugin: invalid_cart_price: Le montant total de votre panier doit être compris entre %min_amount% et %max_amount% pour payer avec Oney. refund_minimum_amount_requirement_not_met: Le montant à rembourser doit être d'au moins 0.10€ oney_unavailable: La simulation de votre échéancier est temporairement indisponible. Vous retrouverez cette information à l'étape du paiement. + oney_gateway_config: + info: | + Permettez à vos clients d’échelonner le paiement de leurs commandes en 3x, 4x à partir de 100€ jusqu’à 3000€. + En savoir plus + fees_for: + title: 'Les frais sont :' + client: Répartis entre vous et vos clients + merchant: À votre charge + integrated_payment: + card_holder.title: 'Nom du titulaire de la carte' + card_holder.error: 'Nom et/ou prénom invalide(s).' + pan.title: 'Numero de carte' + pan.error: 'Numéro de carte invalide.' + cvv.title: '123' + cvv.error: 'CVV invalide.' + exp.title: "MM/AA" + exp.error: "Date d'expiration invalide." + empty: 'Champ obligatoire.' + scheme.label: 'Votre carte' + save_card.label: 'Enregistrer ma carte bancaire' + place_order.label: 'Confirmer le paiement' + transaction_secure.label: 'Transaction sécurisée par' + privacy_policy.label: 'Politique de confidentialité' + deferred_capture: + process_order_info: | + Vous serez prélevé(é) lors du traitement de votre commande. + + live: Mode LIVE + live_help: | + Lorsque cette option est activée, le mode LIVE est utilisé.
+ Si elle est désactivée, le mode TEST sera appliqué + renew_oauth: Forcer la reconnexion OAuth + renew_oauth_help: | + Si cette option est cochée, un nouveau flux d’authentification sera lancé lors du clic sur le bouton "Mise à jour". form: oney_error: Il y a des informations manquantes pour pouvoir payer en utilisant Oney by Payplug complete_info: @@ -80,14 +142,20 @@ payplug_sylius_payplug_plugin: success_title: Informations enregistrées success_instruction: Cliquez à nouveau sur "Suivant" pour continuer email: | - Merci de saisir votre adresse email : + Veuillez saisir une adresse email valide : phone: | Merci de saisir votre numéro de téléphone portable : submit: Valider et continuer base_currency_not_euro: | Canal #channel_code# : #payment_method# n’est disponible que sur des canaux dont la devise est l’EURO - only_one_gateway_allowed: Attention, le moyen de paiement %gateway_title% existe déjà. Pour le modifier, rendez-vous sur vos moyens de paiement. + only_one_gateway_allowed: | + Attention, le moyen de paiement %gateway_title% existe déjà. Pour le modifier, rendez-vous sur vos moyens de paiement. one_click_enable: Activer le One click one_click_help: | Permettez à vos clients d'enregistrer leurs coordonnées de carte de paiement pour effectuer ultérieurement d'autres transactions + + integrated_payment_enable: Activer le Paiement Integré + deferred_capture_enable: Activer la capture différée + deferred_capture_help: | + Attention, assurez vous qu'un déclencheur de la capture différée a bien été ajouté dans le code source du projet diff --git a/src/Resources/translations/messages.it.yml b/translations/messages.it.yml similarity index 58% rename from src/Resources/translations/messages.it.yml rename to translations/messages.it.yml index 891a93e7..cc97e1ed 100644 --- a/src/Resources/translations/messages.it.yml +++ b/translations/messages.it.yml @@ -1,4 +1,10 @@ payplug_sylius_payplug_plugin: + admin: + ui: + oney_x3_with_fees_payment: Oney 3x + oney_x4_with_fees_payment: Oney 4x + oney_x3_without_fees_payment: Oney 3x Nessuna Commissione + oney_x4_without_fees_payment: Oney 4x Nessuna Commissione ui: account: saved_cards: @@ -17,25 +23,31 @@ payplug_sylius_payplug_plugin: deleted_error: C'è stato un errore. Per favore riprova tra qualche secondo. confirmation_modal: confirm_card_deletion: Desideri cancellare questa carta? + bancontact_gateway_label: Bancontact by Payplug + apple_pay_gateway_label: Apple Pay by Payplug + american_express_gateway_label: American Express by Payplug + apple_pay_not_available: Apple Pay non è disponibile su questo browser o dispositivo. error: billing.postcode: Il codice postale %postalCode% inserito per l’indirizzo di fatturazione non è valido shipping.postcode: Il codice postale %postalCode% inserito per l’indirizzo di consegna non è valido - secret_key: ID segreto - payplug_gateway_label: PayPlug + payplug_gateway_label: Payplug payment_refund_locally: Il rimborso del pagamento è stato effettuato solo a livello locale (interno). - retrieve_secret_key_in_api_configuration_portal: Trova il tuo ID segreto LIVE e TEST nel tuo portale PayPlug test_mode: Modalità TEST payplug_id: | - ID PayPlug : %paymentId% - payplug_refund_gateway_is_not_activated: PayPlug non è stato attivato come metodo di rimborso + ID Payplug : %paymentId% + payplug_refund_gateway_is_not_activated: Payplug non è stato attivato come metodo di rimborso impossible_to_refund_this_payment: Non è possibile rimborsare questo pagamento - oney_gateway_label: Oney by PayPlug + oney_gateway_label: Oney by Payplug oney: Oney oney_transaction_less_than_forty_eight_hours: Il rimborso sarà possibile 48 ore dopo l’ultima operazione di pagamento o rimborso. or_pay_with_oney: Oppure paga in pay: Pagamento 3x_payment: Pagamento in 3x 4x_payment: Pagamento in 4x + oney_x3_with_fees_payment: Pagamento in 3x + oney_x4_with_fees_payment: Pagamento in 4x + oney_x3_without_fees_payment: Pagamento in 3x senza nessuna commissione + oney_x4_without_fees_payment: Pagamento in 4x senza nessuna commissione by_credit_cart: Con carta di credito cancel: Annulla popin_close: Chiudi @@ -71,6 +83,38 @@ payplug_sylius_payplug_plugin: invalid_cart_price: L’importo totale del tuo carrello deve essere compreso tra %min_amount% e %max_amount% per poter pagare con Oney. refund_minimum_amount_requirement_not_met: L’importo da rimborsare non può essere inferiore a 0.10€ oney_unavailable: La simulazione del tuo piano di finanziamento non è per il momento disponibile. Queste informazioni ti saranno fornite al momento del pagamento. + oney_gateway_config: + info: | + Permetti ai tuoi clienti di scaglionare il pagamento dei loro ordini in 3x, 4x a partire da 100€ e fino a 3000€. + Per saperne di più + fees_for: + title: 'Le spese sono:' + client: Ripartite tra te e i tuoi clienti + merchant: A tuo carico + integrated_payment: + card_holder.title: 'Titolare della carta' + card_holder.error: 'Nome e/o Cognome non valido(i).' + pan.title: 'Numero di carta' + pan.error: 'Numero di carta non valido.' + cvv.title: '123' + cvv.error: 'CVV non valido.' + exp.title: "MM/AA" + exp.error: "Data di scadenza non valida." + empty: 'Campo obbligatorio.' + scheme.label: 'La tua carta' + place_order.label: 'Ordine' + transaction_secure.label: 'Transazione protetta da' + privacy_policy.label: 'Politica di confidenzialità' + deferred_capture: + process_order_info: | + L'addebito avverrà al momento dell'elaborazione dell'ordine. + live: Modalità LIVE + live_help: | + Quando questa opzione è attivata, viene utilizzata la modalità LIVE.
+ Se disattivata, verrà applicata la modalità TEST + renew_oauth: Forza la riconnessione OAuth + renew_oauth_help: | + Se questa opzione è selezionata, un nuovo flusso di autenticazione verrà avviato quando si fa clic sul pulsante "Aggiorna". form: oney_error: Mancano alcune informazioni per poter pagare con “Oney by Payplug” complete_info: @@ -84,7 +128,13 @@ payplug_sylius_payplug_plugin: submit: Convalida e continua base_currency_not_euro: | Il canale #channel_code# : #payment_method# è disponibile solo per i canali la cui valuta è in EURO - only_one_gateway_allowed: 'Attenzione: il metodo di pagamento %gateway_title% è già definito. Per modificarlo, vai ai tuoi metodi di pagamento.' + only_one_gateway_allowed: | + Attenzione: il metodo di pagamento %gateway_title% è già definito. Per modificarlo, vai ai tuoi metodi di pagamento. one_click_enable: Attiva un clic one_click_help: | Consenti ai tuoi clienti di salvare i dettagli della loro carta di credito per dopo + + integrated_payment_enable: Abilita il pagamento integrato + deferred_capture_enable: Abilita la cattura differita + deferred_capture_help: | + Assicurarsi che nel codice sorgente del progetto sia stato aggiunto un trigger di acquisizione ritardata diff --git a/translations/validators.en.yml b/translations/validators.en.yml new file mode 100644 index 00000000..8ca73234 --- /dev/null +++ b/translations/validators.en.yml @@ -0,0 +1,45 @@ +payplug_sylius_payplug_plugin: + secret_key: + not_blank: The secret key cannot be empty. + not_valid: This is not a valid Payplug secret key. + oney: + not_enabled: | + Attention. To use the payment method “Oney by Payplug“ in LIVE mode, + please contact us at support@payplug.com + not_valid_phone_number: This is not a valid cell phone number. + permission: + error: | + You do not have access to this feature. For more information, + please contact us at: support@payplug.com + + one_click: # deprecated + can_not_save_cards: | + You do not have access to this feature. For more information, + please contact us at: support@payplug.com + payplug_bancontact: + can_not_save_method_with_test_key: | + The Bancontact payment method is not available for the TEST mode. + Please activate the LIVE mode. + can_not_save_method_no_access: | + You don't have access to this feature yet. + To activate Bancontact, please fill in + this form + and activate the LIVE mode. + payplug_apple_pay: + can_not_save_method_with_test_key: | + The Apple Pay payment method is not available for the TEST mode. + Please activate the LIVE mode. + can_not_save_method_no_access: | + You don't have access to this feature yet. + To activate Apple Pay, please fill in + this form + and activate the LIVE mode. + payplug_american_express: + can_not_save_method_with_test_key: | + The American Express payment method is not available for the TEST mode. + Please activate the LIVE mode. + can_not_save_method_no_access: | + You don't have access to this feature yet. + To activate American Express, please fill in + this form + and activate the LIVE mode. diff --git a/translations/validators.fr.yml b/translations/validators.fr.yml new file mode 100644 index 00000000..4da2b61b --- /dev/null +++ b/translations/validators.fr.yml @@ -0,0 +1,44 @@ +payplug_sylius_payplug_plugin: + secret_key: + not_blank: La clé secrète ne peut pas être vide. + not_valid: Ce n'est pas une clé secrète Payplug valide. + oney: + not_enabled: | + Vous n'avez pas encore accès à la fonctionnalité du PayLater. + Pour utiliser la méthode de paiement 3x 4x Oney par Payplug en mode LIVE, merci de nous contacter à support@payplug.com + not_valid_phone_number: Cette valeur n'est pas un numéro de téléphone portable valide. + permission: + error: | + Vous n'avez pas accès à cette fonctionnalité. Pour plus d'informations, + veuillez nous contacter à : support@payplug.com + one_click: + can_not_save_cards: | + Vous n'avez pas accès à cette fonctionnalité. Pour plus d'informations, + veuillez nous contacter à : support@payplug.com + payplug_bancontact: + can_not_save_method_with_test_key: | + Le paiement par Bancontact n’est pas disponible en mode TEST. + Veuillez activer le mode LIVE. + can_not_save_method_no_access: | + Vous n'avez pas accès à cette fonctionnalité. + Pour activer Bancontact, rendez-vous sur + ce formulaire + et activez le mode LIVE. + payplug_apple_pay: + can_not_save_method_with_test_key: | + Le paiement par Apple Pay n’est pas disponible en mode TEST. + Veuillez activer le mode LIVE. + can_not_save_method_no_access: | + Vous n'avez pas accès à cette fonctionnalité. + Pour activer Apple Pay, rendez-vous sur + ce formulaire + et activez le mode LIVE. + payplug_american_express: + can_not_save_method_with_test_key: | + Le paiement par American Express n’est pas disponible en mode TEST. + Veuillez activer le mode LIVE. + can_not_save_method_no_access: | + Vous n'avez pas accès à cette fonctionnalité. + Pour activer American Express, rendez-vous sur + ce formulaire + et activez le mode LIVE. diff --git a/translations/validators.it.yml b/translations/validators.it.yml new file mode 100644 index 00000000..fdd6fe52 --- /dev/null +++ b/translations/validators.it.yml @@ -0,0 +1,44 @@ +payplug_sylius_payplug_plugin: + secret_key: + not_blank: Il campo dell’ID segreto non può essere vuoto. + not_valid: ID segreto Payplug non valido. + oney: + not_enabled: | + Attenzione! Per utilizzare il metodo di pagamento “Oney by Payplug” in modalità LIVE, + contattaci al seguente indirizzo: support@payplug.com + not_valid_phone_number: Numero di cellulare non valido. + permission: + error: | + Non hai accesso a questa funzionalità. Per ulteriori informazioni, + contattaci al seguente indirizzo e-mail: support@payplug.com + one_click: + can_not_save_cards: | + Non hai accesso a questa funzionalità. Per ulteriori informazioni, + contattaci al seguente indirizzo e-mail: support@payplug.com + payplug_bancontact: + can_not_save_method_with_test_key: | + Il metodo di pagamento Bancontact non è disponibile in modalità TEST. + Attiva la modalità LIVE. + can_not_save_method_no_access: | + Non puoi ancora accedere a questa funzionalità. + Per attivare Bancontact, compila + questo modulo + e attiva la modalità LIVE. + payplug_american_express: + can_not_save_method_with_test_key: | + Il pagamento Apple Pay non è disponibile in modalità TEST. + Attiva la modalità LIVE. + can_not_save_method_no_access: | + Non puoi ancora accedere a questa funzionalità. + Per attivare Apple Pay, compila + questo modulo + e attiva la modalità LIVE. + american_express: + can_not_save_method_with_test_key: | + Il pagamento American Express non è disponibile in modalità TEST. + Attiva la modalità LIVE. + can_not_save_method_no_access: | + Non puoi ancora accedere a questa funzionalità. + Per attivare American Express, compila + questo modulo + e attiva la modalità LIVE.