mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
Merge branch '1.9' into constraint-doctrine-dbal
This commit is contained in:
commit
b7b7095432
618 changed files with 6022 additions and 27923 deletions
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
|
@ -1,6 +1,6 @@
|
|||
| Q | A
|
||||
| --------------- | -----
|
||||
| Branch? | 1.7, 1.8 or master <!-- see the comment below -->
|
||||
| Branch? | 1.9, 1.10 or master <!-- see the comment below -->
|
||||
| Bug fix? | no/yes
|
||||
| New feature? | no/yes
|
||||
| BC breaks? | no/yes
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
| License | MIT
|
||||
|
||||
<!--
|
||||
- Bug fixes must be submitted against the 1.7 or 1.8 branch (the lowest possible)
|
||||
- Bug fixes must be submitted against the 1.9 or 1.10 branch (the lowest possible)
|
||||
- Features and deprecations must be submitted against the master branch
|
||||
- Make sure that the correct base branch is set
|
||||
|
||||
|
|
|
|||
18
.github/workflows/application.yml
vendored
18
.github/workflows/application.yml
vendored
|
|
@ -22,7 +22,7 @@ on:
|
|||
|
||||
jobs:
|
||||
static-checks:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "Static checks (PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }})"
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ jobs:
|
|||
name: Restrict Symfony version
|
||||
if: matrix.symfony != ''
|
||||
run: |
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10"
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:1.13.4"
|
||||
composer config extra.symfony.require "${{ matrix.symfony }}"
|
||||
|
||||
-
|
||||
|
|
@ -76,7 +76,7 @@ jobs:
|
|||
|
||||
-
|
||||
name: Validate composer.json
|
||||
run: composer validate --strict
|
||||
run: composer validate --strict --no-check-version
|
||||
if: always() && steps.end-of-setup.outcome == 'success'
|
||||
|
||||
-
|
||||
|
|
@ -110,7 +110,7 @@ jobs:
|
|||
if: always() && steps.end-of-setup.outcome == 'success'
|
||||
|
||||
test-application-without-frontend:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "Test non-JS application (PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }})"
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ jobs:
|
|||
name: Restrict Symfony version
|
||||
if: matrix.symfony != ''
|
||||
run: |
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10"
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:1.13.4"
|
||||
composer config extra.symfony.require "${{ matrix.symfony }}"
|
||||
|
||||
-
|
||||
|
|
@ -243,7 +243,7 @@ jobs:
|
|||
if-no-files-found: ignore
|
||||
|
||||
test-application-with-frontend:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "Test JS application (PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }})"
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ jobs:
|
|||
matrix:
|
||||
php: [7.3, 7.4]
|
||||
symfony: [^4.4, ^5.2]
|
||||
node: [10.x]
|
||||
node: [14.x]
|
||||
mysql: [5.7, 8.0]
|
||||
|
||||
exclude:
|
||||
|
|
@ -295,7 +295,7 @@ jobs:
|
|||
name: Restrict Symfony version
|
||||
if: matrix.symfony != ''
|
||||
run: |
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10"
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:1.13.4"
|
||||
composer config extra.symfony.require "${{ matrix.symfony }}"
|
||||
|
||||
-
|
||||
|
|
@ -396,7 +396,7 @@ jobs:
|
|||
if-no-files-found: ignore
|
||||
|
||||
notify-about-build-failure:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: failure() && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release')
|
||||
|
||||
|
|
|
|||
2
.github/workflows/auto-merge.yml
vendored
2
.github/workflows/auto-merge.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
|
||||
jobs:
|
||||
auto-merge:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
|
|
|
|||
4
.github/workflows/documentation.yml
vendored
4
.github/workflows/documentation.yml
vendored
|
|
@ -18,7 +18,7 @@ on:
|
|||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "Build"
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
run: docker run --rm sylius-docs
|
||||
|
||||
notify-about-build-failure:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: failure() && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release')
|
||||
|
||||
|
|
|
|||
8
.github/workflows/packages.yml
vendored
8
.github/workflows/packages.yml
vendored
|
|
@ -20,7 +20,7 @@ on:
|
|||
|
||||
jobs:
|
||||
list:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "Create a list of packages"
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
test:
|
||||
needs: list
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: "${{ matrix.package }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}"
|
||||
|
||||
|
|
@ -82,7 +82,7 @@ jobs:
|
|||
name: Restrict Symfony version
|
||||
if: matrix.symfony != ''
|
||||
run: |
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10"
|
||||
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:1.13.4"
|
||||
composer config extra.symfony.require "${{ matrix.symfony }}"
|
||||
working-directory: "src/Sylius/${{ matrix.package }}"
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ jobs:
|
|||
run: bin/test-package src/Sylius/${{ matrix.package }}
|
||||
|
||||
notify-about-build-failure:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: failure() && (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,42 @@
|
|||
# CHANGELOG FOR `1.8.X`
|
||||
|
||||
## v1.8.12 (2021-04-22)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12469](https://github.com/Sylius/Sylius/issues/12469) Extract sylius/admin-api-bundle out of Sylius Core (but keep it installed by default in existing minor releases) ([@pamil](https://github.com/pamil))
|
||||
- [#12489](https://github.com/Sylius/Sylius/issues/12489) Build fix Change int to string in GenerateCouponsCommand ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12493](https://github.com/Sylius/Sylius/issues/12493) Update model.rst ([@mariogalan](https://github.com/mariogalan))
|
||||
- [#12501](https://github.com/Sylius/Sylius/issues/12501) [BUG] Product options null value returns 400 instead of 500 ([@lchrusciel](https://github.com/lchrusciel), [@SirDomin](https://github.com/SirDomin))
|
||||
- [#12504](https://github.com/Sylius/Sylius/issues/12504) Change app.php to index.php ([@stefandoorn](https://github.com/stefandoorn))
|
||||
- [#12516](https://github.com/Sylius/Sylius/issues/12516) Fix CustomerComponent Typo ([@DennisdeBest](https://github.com/DennisdeBest))
|
||||
- [#12522](https://github.com/Sylius/Sylius/issues/12522) Revert BC break in ProductVariantInterface ([@pamil](https://github.com/pamil))
|
||||
- [#12523](https://github.com/Sylius/Sylius/issues/12523) Remove Admin API Bundle-related tests ([@pamil](https://github.com/pamil))
|
||||
|
||||
## v1.8.11 (2021-03-22)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12468](https://github.com/Sylius/Sylius/issues/12468) Fix the build by conflicting with doctrine/doctrine-bundle 2.3.0 ([@pamil](https://github.com/pamil))
|
||||
|
||||
## v1.8.10 (2021-03-18)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12126](https://github.com/Sylius/Sylius/issues/12126) Fix incorrect money format being used ([@kayue](https://github.com/kayue))
|
||||
- [#12289](https://github.com/Sylius/Sylius/issues/12289) [Docs] Add docs for LoyaltyRule[Api] ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12312](https://github.com/Sylius/Sylius/issues/12312) [CI] Ignore changes in "adr" directory ([@pamil](https://github.com/pamil))
|
||||
- [#12313](https://github.com/Sylius/Sylius/issues/12313) Change package type from "project" to "library" ([@vvasiloi](https://github.com/vvasiloi))
|
||||
- [#12324](https://github.com/Sylius/Sylius/issues/12324) Removing hard timeout on edit while load selected values ([@christopherhero](https://github.com/christopherhero))
|
||||
- [#12352](https://github.com/Sylius/Sylius/issues/12352) [Frontend] add box with info about api identifiers ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12363](https://github.com/Sylius/Sylius/issues/12363) [Maintenance] Run test suite for MySQL 8.0 ([@lchrusciel](https://github.com/lchrusciel), [@GSadee](https://github.com/GSadee))
|
||||
- [#12367](https://github.com/Sylius/Sylius/issues/12367) change swagger API info color to blue ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12376](https://github.com/Sylius/Sylius/issues/12376) Pass path delimiter up to parent taxon ([@Jeroen-G](https://github.com/Jeroen-G), [@Jeroen](https://github.com/Jeroen), [@pamil](https://github.com/pamil))
|
||||
- [#12384](https://github.com/Sylius/Sylius/issues/12384) Doc: Fix Doctrine project url ([@n3wborn](https://github.com/n3wborn))
|
||||
- [#12397](https://github.com/Sylius/Sylius/issues/12397) Do not fail when mb_detect_encoding returns false ([@stefandoorn](https://github.com/stefandoorn))
|
||||
- [#12404](https://github.com/Sylius/Sylius/issues/12404) Fix nested accordion initialisation ([@DjLeChuck](https://github.com/DjLeChuck))
|
||||
- [#12407](https://github.com/Sylius/Sylius/issues/12407) [AttributeBundle] custom locale_code fixed ([@Mateuszry](https://github.com/Mateuszry))
|
||||
|
||||
## v1.8.9 (2021-02-01)
|
||||
|
||||
#### TL;DR
|
||||
|
|
|
|||
174
CHANGELOG-1.9.md
174
CHANGELOG-1.9.md
|
|
@ -1,5 +1,179 @@
|
|||
# CHANGELOG FOR `1.9.X`
|
||||
|
||||
## v1.9.8 (2021-09-30)
|
||||
|
||||
- [#12222](https://github.com/Sylius/Sylius/issues/12222) logo path corrected ([@Snowbaha](https://github.com/Snowbaha), [@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12452](https://github.com/Sylius/Sylius/issues/12452) [Doc] Customizing admin routes prefix ([@oallain](https://github.com/oallain), [@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12637](https://github.com/Sylius/Sylius/issues/12637) Missing Behat directory on the path to be excluded ([@tonicospinelli](https://github.com/tonicospinelli))
|
||||
- [#12824](https://github.com/Sylius/Sylius/issues/12824) [Documentation] Fixed logo customization (, [@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12849](https://github.com/Sylius/Sylius/issues/12849) [Docs] Webpack - Display logo on login page ([@Jibbarth](https://github.com/Jibbarth))
|
||||
- [#12863](https://github.com/Sylius/Sylius/issues/12863) Add yaml configuration examples to the "Custom Payment Gateway" cookbook ([@DennisCodeBuds](https://github.com/DennisCodeBuds))
|
||||
- [#12892](https://github.com/Sylius/Sylius/issues/12892) [DOCS] Add note about docker builder ([@arti0090](https://github.com/arti0090))
|
||||
- [#13070](https://github.com/Sylius/Sylius/issues/13070) [Minor][DI] Add interface alias to UriBasedSectionProvider ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#13102](https://github.com/Sylius/Sylius/issues/13102) Check if the form is submitted before validation ([@jacquesbh](https://github.com/jacquesbh))
|
||||
- [#13154](https://github.com/Sylius/Sylius/issues/13154) [API] Do not allow to address empty cart ([@Zales0123](https://github.com/Zales0123))
|
||||
|
||||
## v1.9.7 (2021-09-02)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#11623](https://github.com/Sylius/Sylius/issues/11623) Fix #11603, Update documentation to replace use of removed function ([@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12085](https://github.com/Sylius/Sylius/issues/12085) [Doc] Add contact email ([@MatthieuCutin](https://github.com/MatthieuCutin), [@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12223](https://github.com/Sylius/Sylius/issues/12223) Remove security.yaml change when disabling localized URLs ([@maximehuran](https://github.com/maximehuran))
|
||||
- [#12852](https://github.com/Sylius/Sylius/issues/12852) [API] Do not check command arguments if there is an object to populate ([@GSadee](https://github.com/GSadee))
|
||||
- [#12873](https://github.com/Sylius/Sylius/issues/12873) [Docs] sylius performance boost ([@SirDomin](https://github.com/SirDomin), [@arti0090](https://github.com/arti0090))
|
||||
- [#12875](https://github.com/Sylius/Sylius/issues/12875) [Admin] Fix shipping totals in order summary ([@aleho](https://github.com/aleho))
|
||||
- [#12881](https://github.com/Sylius/Sylius/issues/12881) [Documentation] Note about changes related to upgrade to GridBundle 1.10 ([@AdamKasp](https://github.com/AdamKasp), [@GSadee](https://github.com/GSadee))
|
||||
- [#12973](https://github.com/Sylius/Sylius/issues/12973) Fix borders in order - show - addresses ([@pavol-tk](https://github.com/pavol-tk))
|
||||
- [#12975](https://github.com/Sylius/Sylius/issues/12975) [Docs] fix annotations ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12976](https://github.com/Sylius/Sylius/issues/12976) [Documentation] Minor fix in grids docs ([@GSadee](https://github.com/GSadee))
|
||||
- [#12977](https://github.com/Sylius/Sylius/issues/12977) [Docs] add prefix to sylius customer table ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12984](https://github.com/Sylius/Sylius/issues/12984) [Documentation] Move invoice cookbooks to payments section ([@GSadee](https://github.com/GSadee))
|
||||
- [#12993](https://github.com/Sylius/Sylius/issues/12993) [Build] Force symfony flex in github actions ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#13018](https://github.com/Sylius/Sylius/issues/13018) [Bug] Fix default sylius config file path in Sylius 1.8 ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#13019](https://github.com/Sylius/Sylius/issues/13019) [Bug] Fix default sylius config file path in Sylius 1.9 ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#13032](https://github.com/Sylius/Sylius/issues/13032) [Docs] Choosing the right branch - fix ([@CoderMaggie](https://github.com/CoderMaggie))
|
||||
|
||||
## v1.9.6 (2021-07-30)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12751](https://github.com/Sylius/Sylius/issues/12751) [Docs] Describe API customization requirement for SyliusPlus with Sylius 1.9 ([@Zales0123](https://github.com/Zales0123), [@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12763](https://github.com/Sylius/Sylius/issues/12763) [Docs] Remove redundant refund interfaces ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12764](https://github.com/Sylius/Sylius/issues/12764) [Taxon] Wrap resource deletion operation with a transaction to fix a problem with removing used taxon ([@GSadee](https://github.com/GSadee))
|
||||
- [#12767](https://github.com/Sylius/Sylius/issues/12767) [Documentation] Fix warning about version of Sylius in Plus installation guide ([@GSadee](https://github.com/GSadee))
|
||||
- [#12770](https://github.com/Sylius/Sylius/issues/12770) [Documentation] One more fix for warning about version of Sylius in Plus installation guide ([@GSadee](https://github.com/GSadee))
|
||||
- [#12771](https://github.com/Sylius/Sylius/issues/12771) [API] Turn on/off api endpoints with parameter ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12776](https://github.com/Sylius/Sylius/issues/12776) [Docs][Plus] Modify plus installation guide ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12784](https://github.com/Sylius/Sylius/issues/12784) [Documentation][Cookbook] How to add another type of refund? ([@GSadee](https://github.com/GSadee))
|
||||
- [#12789](https://github.com/Sylius/Sylius/issues/12789) [API] Disable API by default ([@GSadee](https://github.com/GSadee))
|
||||
- [#12801](https://github.com/Sylius/Sylius/issues/12801) [Documentation] Update Plus installation guide for Sylius 1.9 ([@GSadee](https://github.com/GSadee))
|
||||
- [#12804](https://github.com/Sylius/Sylius/issues/12804) Enable API by default in dev environment ([@Zales0123](https://github.com/Zales0123))
|
||||
- [#12807](https://github.com/Sylius/Sylius/issues/12807) Optimizing the attribute loading in product edit ([@mamazu](https://github.com/mamazu))
|
||||
- [#12811](https://github.com/Sylius/Sylius/issues/12811) [API] Test not providing required fields during registration ([@Zales0123](https://github.com/Zales0123))
|
||||
- [#12816](https://github.com/Sylius/Sylius/issues/12816) [Maintenance] Fix 1.8 build ([@GSadee](https://github.com/GSadee), [@SirDomin](https://github.com/SirDomin))
|
||||
- [#12817](https://github.com/Sylius/Sylius/issues/12817) [Taxation] Add scenarios for applying proper taxes for shipping ([@GSadee](https://github.com/GSadee))
|
||||
- [#12818](https://github.com/Sylius/Sylius/issues/12818) [Core] Bring back String u function ([@GSadee](https://github.com/GSadee))
|
||||
- [#12819](https://github.com/Sylius/Sylius/issues/12819) [API] 1.8 api as opt ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12823](https://github.com/Sylius/Sylius/issues/12823) [API] Allow creation of commands with no arguments with a default value ([@GSadee](https://github.com/GSadee))
|
||||
- [#12833](https://github.com/Sylius/Sylius/issues/12833) [API] Disable API by default ([@GSadee](https://github.com/GSadee))
|
||||
- [#12837](https://github.com/Sylius/Sylius/issues/12837) [UPGRADE] Split API and non API upgrade files ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#12838](https://github.com/Sylius/Sylius/issues/12838) [UPGRADE] Split API and non API upgrade files ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#12839](https://github.com/Sylius/Sylius/issues/12839) [UI] Add bottom scroll to the order summary table ([@kulczy](https://github.com/kulczy))
|
||||
- [#12843](https://github.com/Sylius/Sylius/issues/12843) [Documentation] Change version of Plus in installation guide ([@GSadee](https://github.com/GSadee))
|
||||
- [#12845](https://github.com/Sylius/Sylius/issues/12845) Quick Typo update :) ([@FaithlessLooting](https://github.com/FaithlessLooting))
|
||||
|
||||
## v1.9.5 (2021-06-28)
|
||||
|
||||
#### TL;DR
|
||||
|
||||
**This is a security release!**
|
||||
|
||||
Fixes the follwing vulnerability:
|
||||
|
||||
- [List of order ids, number, items total and token value exposed for unauthorized uses via new API](https://github.com/Sylius/Sylius/security/advisories/GHSA-rpxh-vg2x-526v)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12596](https://github.com/Sylius/Sylius/issues/12596) Country api resource shouldn't have created/updated at ([@kayue](https://github.com/kayue))
|
||||
- [#12618](https://github.com/Sylius/Sylius/issues/12618) [Docs] Fix cookbook for custom entity ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12682](https://github.com/Sylius/Sylius/issues/12682) Use Symfony 5.2.* instead of ^5.2 for GitHub Actions ([@pamil](https://github.com/pamil))
|
||||
- [#12686](https://github.com/Sylius/Sylius/issues/12686) [DOCS] Cookbook for customizing refund process ([@arti0090](https://github.com/arti0090))
|
||||
- [#12687](https://github.com/Sylius/Sylius/issues/12687) Fix typo and imporve error message ([@dantleech](https://github.com/dantleech))
|
||||
- [#12690](https://github.com/Sylius/Sylius/issues/12690) [Doctrine] Fix problem with explicitly defining entity managers ([@GSadee](https://github.com/GSadee))
|
||||
- [#12698](https://github.com/Sylius/Sylius/issues/12698) Fix the build with Symfony 5.3 ([@pamil](https://github.com/pamil))
|
||||
- [#12699](https://github.com/Sylius/Sylius/issues/12699) [Documentation] Update templates directory in Themes doc ([@CoderMaggie](https://github.com/CoderMaggie))
|
||||
- [#12702](https://github.com/Sylius/Sylius/issues/12702) [Documentation] Fix Refund Process Cookbook ([@GSadee](https://github.com/GSadee))
|
||||
- [#12706](https://github.com/Sylius/Sylius/issues/12706) [Documentation] Tweaks on the refunds process cookbook ([@CoderMaggie](https://github.com/CoderMaggie), [@GSadee](https://github.com/GSadee))
|
||||
- [#12707](https://github.com/Sylius/Sylius/issues/12707) [Documentation] Fix links in the refunds process cookbook ([@GSadee](https://github.com/GSadee))
|
||||
- [#12715](https://github.com/Sylius/Sylius/issues/12715) [Dql] Add parameter instead of hardcoding it in where statement ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12720](https://github.com/Sylius/Sylius/issues/12720) [DQL] Change hardcoded enabled value to parameter in where statements ([@GSadee](https://github.com/GSadee))
|
||||
- [#12726](https://github.com/Sylius/Sylius/issues/12726) [DQL] Change hardcoded tracked value to parameter in where statements ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#12731](https://github.com/Sylius/Sylius/issues/12731) Add cookbook with how to change tax address ([@arti0090](https://github.com/arti0090))
|
||||
- [#12748](https://github.com/Sylius/Sylius/issues/12748) [Documentation][Refund] Add cookbook about refund customization with improvements ([@AdamKasp](https://github.com/AdamKasp), [@GSadee](https://github.com/GSadee))
|
||||
|
||||
## v1.9.4 (2021-05-27)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12557](https://github.com/Sylius/Sylius/issues/12557) update Plus installation guide ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12558](https://github.com/Sylius/Sylius/issues/12558) [Order] Fix race condition problem with multiple order recalculations ([@GSadee](https://github.com/GSadee))
|
||||
- [#12564](https://github.com/Sylius/Sylius/issues/12564) [Docs] add minor improvement to Plus installation guide ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12565](https://github.com/Sylius/Sylius/issues/12565) [API][Order] Fix possibility to limit orders by refactoring from data provider to extension ([@GSadee](https://github.com/GSadee))
|
||||
- [#12569](https://github.com/Sylius/Sylius/issues/12569) Bugfix | Filter out not enabled products in API collection ([@stloyd](https://github.com/stloyd), [@arti0090](https://github.com/arti0090))
|
||||
- [#12604](https://github.com/Sylius/Sylius/issues/12604) [API] Cherry pick commits on 1.9 branch for validating if product is enabled during adding to cart ([@arti0090](https://github.com/arti0090), [@GSadee](https://github.com/GSadee))
|
||||
- [#12609](https://github.com/Sylius/Sylius/issues/12609) Adding product from another channel bugfix ([@arti0090](https://github.com/arti0090))
|
||||
- [#12612](https://github.com/Sylius/Sylius/issues/12612) [Documentation] Update cookbook about Facebook login ([@GSadee](https://github.com/GSadee))
|
||||
- [#12613](https://github.com/Sylius/Sylius/issues/12613) [API] Adding inexistent variant ([@arti0090](https://github.com/arti0090), [@GSadee](https://github.com/GSadee))
|
||||
- [#12619](https://github.com/Sylius/Sylius/issues/12619) [Docs] Add docs for custom entity with access per admin channel ([@Tomanhez](https://github.com/Tomanhez), [@GSadee](https://github.com/GSadee))
|
||||
- [#12628](https://github.com/Sylius/Sylius/issues/12628) [API] Conflict with symfony/property-info due to problem with wrong namespaces of some translation entities ([@GSadee](https://github.com/GSadee))
|
||||
- [#12632](https://github.com/Sylius/Sylius/issues/12632) [Docs] Mention localhost exposure for easier Facebook login ([@Zales0123](https://github.com/Zales0123))
|
||||
- [#12633](https://github.com/Sylius/Sylius/issues/12633) [Bug] [Temporary solution] Comment out 2 behats steps for checking notifications ([@SirDomin](https://github.com/SirDomin))
|
||||
- [#12643](https://github.com/Sylius/Sylius/issues/12643) [README] Fix link to plugin list ([@lchrusciel](https://github.com/lchrusciel))
|
||||
- [#12650](https://github.com/Sylius/Sylius/issues/12650) [API][ProductVariant] Fix product variant response by using proper normalizer ([@GSadee](https://github.com/GSadee))
|
||||
- [#12651](https://github.com/Sylius/Sylius/issues/12651) [API][ProductVariant] Add additional specs for product variant normalizer ([@GSadee](https://github.com/GSadee))
|
||||
- [#12655](https://github.com/Sylius/Sylius/issues/12655) [Documentation][Plus] Minor improvements in cookbook for accessing to entities by channel admins ([@GSadee](https://github.com/GSadee))
|
||||
- [#12667](https://github.com/Sylius/Sylius/issues/12667) [Documentation] Customizing CreditMemo entity by adding a new field ([@GSadee](https://github.com/GSadee))
|
||||
- [#12668](https://github.com/Sylius/Sylius/issues/12668) [API] write order email send test in api bundle ([@pamil](https://github.com/pamil), [@SirDomin](https://github.com/SirDomin))
|
||||
- [#12671](https://github.com/Sylius/Sylius/issues/12671) [Api] Tests adding incorrect county code to address order ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12674](https://github.com/Sylius/Sylius/issues/12674) [Minor] Return shop user after registration command to improve extendibility ([@lchrusciel](https://github.com/lchrusciel))
|
||||
|
||||
## v1.9.3 (2021-04-22)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12458](https://github.com/Sylius/Sylius/issues/12458) [Locale] Current locale set on request ([@lchrusciel](https://github.com/lchrusciel), [@SirDomin](https://github.com/SirDomin))
|
||||
- [#12469](https://github.com/Sylius/Sylius/issues/12469) Extract sylius/admin-api-bundle out of Sylius Core (but keep it installed by default in existing minor releases) ([@pamil](https://github.com/pamil))
|
||||
- [#12475](https://github.com/Sylius/Sylius/issues/12475) [Taxation] Fix applying shipment taxes for multiple shipments ([@GSadee](https://github.com/GSadee))
|
||||
- [#12489](https://github.com/Sylius/Sylius/issues/12489) Build fix Change int to string in GenerateCouponsCommand ([@Tomanhez](https://github.com/Tomanhez))
|
||||
- [#12493](https://github.com/Sylius/Sylius/issues/12493) Update model.rst ([@mariogalan](https://github.com/mariogalan))
|
||||
- [#12494](https://github.com/Sylius/Sylius/issues/12494) [Behat][Customer] Fix assertions ([@GSadee](https://github.com/GSadee))
|
||||
- [#12500](https://github.com/Sylius/Sylius/issues/12500) [Documentation] Customizing credit memo ([@pamil](https://github.com/pamil))
|
||||
- [#12501](https://github.com/Sylius/Sylius/issues/12501) [BUG] Product options null value returns 400 instead of 500 ([@lchrusciel](https://github.com/lchrusciel), [@SirDomin](https://github.com/SirDomin))
|
||||
- [#12504](https://github.com/Sylius/Sylius/issues/12504) Change app.php to index.php ([@stefandoorn](https://github.com/stefandoorn))
|
||||
- [#12508](https://github.com/Sylius/Sylius/issues/12508) Fix the build by solving errors reported by static analysis tools ([@pamil](https://github.com/pamil))
|
||||
- [#12516](https://github.com/Sylius/Sylius/issues/12516) Fix CustomerComponent Typo ([@DennisdeBest](https://github.com/DennisdeBest))
|
||||
- [#12522](https://github.com/Sylius/Sylius/issues/12522) Revert BC break in ProductVariantInterface ([@pamil](https://github.com/pamil))
|
||||
- [#12523](https://github.com/Sylius/Sylius/issues/12523) Remove Admin API Bundle-related tests ([@pamil](https://github.com/pamil))
|
||||
- [#12525](https://github.com/Sylius/Sylius/issues/12525) Move note from UPGRADE-1.8 to UPGRADE-1.9 file ([@GSadee](https://github.com/GSadee))
|
||||
- [#12535](https://github.com/Sylius/Sylius/issues/12535) [API] Add prefix to subresource endpoint of order item's adjustments ([@GSadee](https://github.com/GSadee))
|
||||
- [#12546](https://github.com/Sylius/Sylius/issues/12546) [Minor] Use explicit bus instead of the default one ([@lchrusciel](https://github.com/lchrusciel))
|
||||
|
||||
## v1.9.2 (2021-03-23)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12439](https://github.com/Sylius/Sylius/issues/12439) Don't render _token field if it's already rendered ([@maximehuran](https://github.com/maximehuran))
|
||||
- [#12454](https://github.com/Sylius/Sylius/issues/12454) Don't render _token field if it's already rendered in update template ([@pamil](https://github.com/pamil))
|
||||
- [#12461](https://github.com/Sylius/Sylius/issues/12461) Fix packages builds: ResourceBundle v1.8 does not require StofDoctrineExtensionsBundle anymore ([@pamil](https://github.com/pamil))
|
||||
- [#12468](https://github.com/Sylius/Sylius/issues/12468) Fix the build by conflicting with doctrine/doctrine-bundle 2.3.0 ([@pamil](https://github.com/pamil))
|
||||
- [#12471](https://github.com/Sylius/Sylius/issues/12471) [Maintenance] Conflict with JMSSerializer 3.9.0 due to issues with mapping of persistent collection ([@lchrusciel](https://github.com/lchrusciel))
|
||||
|
||||
## v1.9.1 (2021-03-18)
|
||||
|
||||
#### Details
|
||||
|
||||
- [#12324](https://github.com/Sylius/Sylius/issues/12324) Removing hard timeout on edit while load selected values ([@christopherhero](https://github.com/christopherhero))
|
||||
- [#12376](https://github.com/Sylius/Sylius/issues/12376) Pass path delimiter up to parent taxon ([@Jeroen-G](https://github.com/Jeroen-G), [@Jeroen](https://github.com/Jeroen), [@pamil](https://github.com/pamil))
|
||||
- [#12384](https://github.com/Sylius/Sylius/issues/12384) Doc: Fix Doctrine project url ([@n3wborn](https://github.com/n3wborn))
|
||||
- [#12393](https://github.com/Sylius/Sylius/issues/12393) [ApiBundle] Fixes in test application ([@GSadee](https://github.com/GSadee))
|
||||
- [#12397](https://github.com/Sylius/Sylius/issues/12397) Do not fail when mb_detect_encoding returns false ([@stefandoorn](https://github.com/stefandoorn))
|
||||
- [#12398](https://github.com/Sylius/Sylius/issues/12398) [API] add missing spec ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12401](https://github.com/Sylius/Sylius/issues/12401) Use bold to alert on some changes in the README ([@jacquesbh](https://github.com/jacquesbh))
|
||||
- [#12403](https://github.com/Sylius/Sylius/issues/12403) Minor fixes and CS ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12404](https://github.com/Sylius/Sylius/issues/12404) Fix nested accordion initialisation ([@DjLeChuck](https://github.com/DjLeChuck))
|
||||
- [#12407](https://github.com/Sylius/Sylius/issues/12407) [AttributeBundle] custom locale_code fixed ([@Mateuszry](https://github.com/Mateuszry))
|
||||
- [#12410](https://github.com/Sylius/Sylius/issues/12410) [ApiBundle] Improve tests for custom Sylius resource in test application ([@GSadee](https://github.com/GSadee))
|
||||
- [#12411](https://github.com/Sylius/Sylius/issues/12411) [API] improve tests for overwriting api configs ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12412](https://github.com/Sylius/Sylius/issues/12412) [API][DOCS] custom path ([@AdamKasp](https://github.com/AdamKasp))
|
||||
- [#12416](https://github.com/Sylius/Sylius/issues/12416) [ApiBundle] Improve tests for custom entity in test application ([@GSadee](https://github.com/GSadee))
|
||||
- [#12417](https://github.com/Sylius/Sylius/issues/12417) [API][Documentation] Fix link to jwt documentation ([@GSadee](https://github.com/GSadee))
|
||||
- [#12418](https://github.com/Sylius/Sylius/issues/12418) [API][Documentation] Fix path to security file ([@GSadee](https://github.com/GSadee))
|
||||
- [#12423](https://github.com/Sylius/Sylius/issues/12423) Temporarily conflict to symfony/doctrine-bridge in Core and Api bundles ([@GSadee](https://github.com/GSadee))
|
||||
- [#12427](https://github.com/Sylius/Sylius/issues/12427) [FOSOAuthServerBundle] Remove incompatible version ([@Prometee](https://github.com/Prometee))
|
||||
- [#12447](https://github.com/Sylius/Sylius/issues/12447) Fix build for CoreBundle and ApiBundle packages ([@pamil](https://github.com/pamil))
|
||||
- [#12448](https://github.com/Sylius/Sylius/issues/12448) [ApiBundle] Fix displaying testing section in README file ([@GSadee](https://github.com/GSadee))
|
||||
|
||||
## v1.9.0 (2021-03-01)
|
||||
|
||||
#### TL;DR
|
||||
|
|
|
|||
31
CONFLICTS.md
31
CONFLICTS.md
|
|
@ -3,6 +3,19 @@
|
|||
This document explains why certain conflicts were added to `composer.json` and
|
||||
references related issues.
|
||||
|
||||
- `doctrine/doctrine-bundle:2.3.0`:
|
||||
|
||||
This version makes Gedmo Doctrine Extensions fail (tree and position behaviour mostly).
|
||||
|
||||
References: https://github.com/doctrine/DoctrineBundle/issues/1305
|
||||
|
||||
- `jms/serializer-bundle:3.9`:
|
||||
|
||||
This version automatically registered DocBlockDriver, which is always turned on, while docblocks used in our code are not usable with it. Sample error:
|
||||
`Can't use incorrect type object for collection in Doctrine\ORM\PersistentCollection:owner`
|
||||
|
||||
References: https://github.com/schmittjoh/JMSSerializerBundle/issues/844
|
||||
|
||||
- `symfony/serializer:4.4.19|5.2.2`:
|
||||
|
||||
These versions of Symfony Serializer introduces a bug with trying to access some private properties that don't have getters.
|
||||
|
|
@ -63,3 +76,21 @@ references related issues.
|
|||
```
|
||||
|
||||
References: https://github.com/Sylius/Sylius/issues/13211
|
||||
|
||||
- `symfony/property-info:4.4.22|5.2.7`:
|
||||
|
||||
These versions of Symfony PropertyInfo Component introduce a bug with resolving wrong namespace for some translation entities
|
||||
in Swagger UI docs for API.
|
||||
|
||||
The potential solution would be to explicitly define these translation entities as API resources with proper serialization.
|
||||
|
||||
Probably introduced in: https://github.com/symfony/symfony/pull/40811
|
||||
|
||||
- `doctrine/orm:2.10.0`:
|
||||
|
||||
This version causes a problem with the creation of nested taxons by throwing the exception:
|
||||
|
||||
`Gedmo\Exception\UnexpectedValueException: Root cannot be changed manually, change parent instead in vendor/gedmo/doctrine-extensions/src/Tree/Strategy/ORM/Nested.php:145`
|
||||
|
||||
References: https://github.com/doctrine-extensions/DoctrineExtensions/issues/2155
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<h1 align="center">
|
||||
<a href="https://sylius.com/github-readme/link/" target="_blank">
|
||||
<img src="https://sylius.com/assets/github-readme.png?v19" />
|
||||
<img src="https://sylius.com/assets/github-readme.png?v110" />
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
|
|
|
|||
304
UPGRADE-1.8.md
304
UPGRADE-1.8.md
|
|
@ -1,93 +1,10 @@
|
|||
# UPGRADE FROM `v1.8.X` TO `v1.9.0`
|
||||
|
||||
1. To have better control over the serialization process, we introduced `shop` and `admin` prefixes to names of serialization groups on `src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/*` and `src/Sylius/Bundle/ApiBundle/Resources/config/serialization/*`.
|
||||
Several additional serialization groups have been rephrased, to improve readability and predictability of them.
|
||||
If you are using they on your custom entity `api_resource` configuration or serialization groups, you should check if one of these changes may affect on your app. If yes, change all occurs by this pattern:
|
||||
|
||||
- created serialization groups for `Locale` resource as: `admin:locale:read` and `admin:locale:create`
|
||||
- `adjustment:read` changed to: `admin:adjustment:read` and `shop:adjustment:read`
|
||||
- `admin_user:create` changed to: `admin:admin_user:create`
|
||||
- `admin_user:read` changed to: `admin:admin_user:read`
|
||||
- `admin_user:update` changed to: `admin:admin_user:update`
|
||||
- `avatar_image:read` changed to: `admin:avatar_image:read`
|
||||
- `cart:add_item` changed to: `shop:cart:add_item`
|
||||
- `cart:address` changed to: `shop:cart:address`
|
||||
- `cart:apply_coupon` changed to: `shop:cart:apply_coupon`
|
||||
- `cart:change_quantity` changed to: `shop:cart:change_quantity`
|
||||
- `cart:complete` changed to: `shop:cart:complete`
|
||||
- `cart:remove_item` changed to: `shop:cart:remove_item`
|
||||
- `cart:select_payment_method` changed to: `shop:cart:select_payment_method`
|
||||
- `cart:select_shipping_method` changed to: `shop:cart:select_shipping_method`
|
||||
- `cart:update` changed to: `shop:cart:update`
|
||||
- `channel:create` changed to: `admin:channel:create`
|
||||
- `channel:read` changed to: `admin:channel:read`
|
||||
- `checkout:read` changed to: `shop:cart:read`
|
||||
- `country:read` changed to: `admin:country:read`
|
||||
- `currency:read` changed to: `admin:currency:read`
|
||||
- `customer:password:write` changed to: `shop:customer:password:update`
|
||||
- `customer:read` changed to: `admin:customer:read` and `shop:customer:read`
|
||||
- `customer:update` changed to: `shop:customer:update`
|
||||
- `customer_group:create` changed to: `admin:customer_group:create`
|
||||
- `customer_group:read` changed to: `admin:customer_group:read`
|
||||
- `customer_group:update` changed to: `admin:customer_group:update`
|
||||
- `exchange_rate:create` changed to: `admin:exchange_rate:create`
|
||||
- `exchange_rate:read` changed to: `admin:exchange_rate:read`
|
||||
- `exchange_rate:update` changed to: `admin:exchange_rate:update`
|
||||
- `order:create` changed to: `shop:order:create`
|
||||
- `order:read` changed to: `admin:order:read`
|
||||
- `order:update` changed to: `admin:order:update`
|
||||
- `order_item:read` changed to: `admin:order_item:read` and `shop:order_item:read`
|
||||
- `order_item_unit:read` changed to: `admin:order_item_unit:read` and `shop:order_item_unit:read`
|
||||
- `payment:read` changed to: `admin:payment:read` and `shop:payment:read`
|
||||
- `payment_method:read` changed to: `admin:payment_method:read` and `shop:payment_method:read`
|
||||
- `product:create` changed to: `admin:product:create`
|
||||
- `product:read` changed to: `admin:product:read` and `shop:product:read`
|
||||
- `product:update` changed to: `admin:product:update`
|
||||
- `province:read` changed to: `admin:province:read`
|
||||
- `province:update` changed to: `admin:province:update`
|
||||
- `shipment:read` changed to: `admin:shipment:read` and `shop:shipment:read`
|
||||
- `shipment:update` changed to: `admin:shipment:update`
|
||||
- `shipping_category:create` changed to: `admin:shipping_category:create`
|
||||
- `shipping_category:read` changed to: `admin:shipping_category:read`
|
||||
- `shipping_category:update` changed to: `admin:shipping_category:update`
|
||||
- `shipping_method:create` changed to: `admin:shipping_method:create`
|
||||
- `shipping_method:read` changed to: `admin:shipping_method:read`
|
||||
- `shipping_method:update` changed to: `admin:shipping_method:update`
|
||||
- `shop:currencies:read` changed to: `shop:currency:read`
|
||||
- `shop:customer:write` changed to: `shop:customer:create`
|
||||
- `shop_billing_data:read` changed to: `admin:shop_billing_data:read`
|
||||
- `tax_category:read` changed to: `admin:tax_category:read`
|
||||
- `tax_category:update` changed to: `admin:tax_category:update`
|
||||
- `tax_category:create` changed to: `admin:tax_category:create`
|
||||
- `taxon:read` changed to: `admin:taxon:read` and `shop:taxon:read`
|
||||
- `taxon:update` changed to: `admin:taxon:update`
|
||||
- `taxon:create` changed to: `admin:taxon:create`
|
||||
- `zone:read` changed to: `admin:zone:read`
|
||||
- `zone:update` changed to: `admin:zone:update`
|
||||
- `zone:create` changed to: `admin:zone:create`
|
||||
- `zone_member:read` changed to: `admin:zone_member:read`
|
||||
- removed redundant `zone_member:write`
|
||||
|
||||
# UPGRADE FROM `v1.8.4` TO `v1.8.6`
|
||||
|
||||
1. Change configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
1. API is disabled by default, to enable it you need to set flag to ``true`` in ``config/packages/_sylius.yaml``:
|
||||
|
||||
```diff
|
||||
security:
|
||||
firewalls:
|
||||
new_api_admin_user:
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/admin/authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_admin_route%/authentication-token"
|
||||
new_api_shop_user:
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/shop/authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_shop_route%/authentication-token"
|
||||
access_control:
|
||||
- - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```yaml
|
||||
sylius_api:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.8.3` TO `v1.8.4`
|
||||
|
|
@ -95,204 +12,25 @@ If you are using they on your custom entity `api_resource` configuration or seri
|
|||
1. The `sylius:cancel-unpaid-orders` command now continues to proceed even if an error occurred. The behavior here is now normal but it leads to a few issues for an upgrade:
|
||||
|
||||
- Product variants with `on_hold = on_hand` will become available as soon as the uncancelled orders are now cancelled. This could lead to a lot of products on sale which were not previously on sale. This behavior is normal but the Merchant could be used to the previous behavior and could have acted around it.
|
||||
**Before** you upgrade on production you may want to verify the stocks of these products variants:
|
||||
**Before** you upgrade on production you may want to verify the stocks of these products variants:
|
||||
```sql
|
||||
SELECT code FROM sylius_product_variant WHERE on_hand = on_hold; -- These products will go back on "available" and may be sold
|
||||
```
|
||||
- If the merchant is used to this (now gone) bug, then they should be careful about this situation as well: if they worked with the issue and considered that increasing the `on_hand` value to sale more since some on hand stocks were locked by the `on_hold` items, they may be in the situation of having more items on hand than the reality.
|
||||
|
||||
# UPGRADE FROM `v1.8.0` TO `v1.8.1`
|
||||
|
||||
1. Change configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
|
||||
```diff
|
||||
security:
|
||||
providers:
|
||||
- sylius_api_chain_provider:
|
||||
- chain:
|
||||
- providers: [sylius_api_shop_user_provider, sylius_api_admin_user_provider]
|
||||
|
||||
firewalls:
|
||||
new_api_admin_user:
|
||||
- pattern: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
- provider: sylius_admin_user_provider
|
||||
+ pattern: "%sylius.security.new_api_admin_regex%/.*"
|
||||
+ provider: sylius_api_admin_user_provider
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_route%/admin/authentication-token"
|
||||
|
||||
new_api_shop_user:
|
||||
- pattern: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
- provider: sylius_shop_user_provider
|
||||
+ pattern: "%sylius.security.new_api_shop_regex%/.*"
|
||||
+ provider: sylius_api_shop_user_provider
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_route%/shop/authentication-token"
|
||||
|
||||
- new_api:
|
||||
- pattern: "%sylius.security.new_api_regex%/*"
|
||||
- provider: sylius_api_chain_provider
|
||||
- stateless: true
|
||||
- anonymous: lazy
|
||||
- guard:
|
||||
- authenticators:
|
||||
- - lexik_jwt_authentication.jwt_token_authenticator
|
||||
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.7.X` TO `v1.8.0`
|
||||
|
||||
1. Add new bundles to your list of used bundles in `config/bundles.php` if you are not using it apart from Sylius:
|
||||
|
||||
```diff
|
||||
+ ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||
+ Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
|
||||
+ Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
|
||||
+ SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true],
|
||||
```
|
||||
|
||||
1. Add configuration of new ApiBundle in your `config/packages/_sylius.yaml` file:
|
||||
|
||||
```diff
|
||||
imports:
|
||||
+ - { resource: "@SyliusApiBundle/Resources/config/app/config.yaml" }
|
||||
```
|
||||
|
||||
1. Add configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
|
||||
```diff
|
||||
parameters:
|
||||
- sylius.security.admin_regex: "^/admin"
|
||||
- sylius.security.shop_regex: "^/(?!admin|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.admin_regex: "^/%sylius_admin.path_name%"
|
||||
+ sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|new-api|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.new_api_route: "/new-api"
|
||||
+ sylius.security.new_api_regex: "^%sylius.security.new_api_route%"
|
||||
+ sylius.security.new_api_admin_route: "%sylius.security.new_api_route%/admin"
|
||||
+ sylius.security.new_api_admin_regex: "^%sylius.security.new_api_admin_route%"
|
||||
+ sylius.security.new_api_shop_route: "%sylius.security.new_api_route%/shop"
|
||||
+ sylius.security.new_api_shop_regex: "^%sylius.security.new_api_shop_route%"
|
||||
|
||||
security:
|
||||
providers:
|
||||
+ sylius_api_admin_user_provider:
|
||||
+ id: sylius.admin_user_provider.email_or_name_based
|
||||
+ sylius_api_shop_user_provider:
|
||||
+ id: sylius.shop_user_provider.email_or_name_based
|
||||
+ sylius_api_chain_provider:
|
||||
+ chain:
|
||||
+ providers: [sylius_api_shop_user_provider, sylius_api_admin_user_provider]
|
||||
|
||||
firewalls:
|
||||
admin:
|
||||
remember_me:
|
||||
- path: /admin
|
||||
+ path: "/%sylius_admin.path_name%"
|
||||
+ new_api_admin_user:
|
||||
+ pattern: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ provider: sylius_admin_user_provider
|
||||
+ stateless: true
|
||||
+ anonymous: true
|
||||
+ json_login:
|
||||
+ check_path: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ username_path: email
|
||||
+ password_path: password
|
||||
+ success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||
+ failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
+ new_api_shop_user:
|
||||
+ pattern: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ provider: sylius_shop_user_provider
|
||||
+ stateless: true
|
||||
+ anonymous: true
|
||||
+ json_login:
|
||||
+ check_path: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ username_path: email
|
||||
+ password_path: password
|
||||
+ success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||
+ failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
+ new_api:
|
||||
+ pattern: "%sylius.security.new_api_regex%/*"
|
||||
+ provider: sylius_api_chain_provider
|
||||
+ stateless: true
|
||||
+ anonymous: lazy
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
+ - { path: "%sylius.security.new_api_shop_regex%/.*", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
1. Add `sylius_api.yaml` file to `config/routes/` directory:
|
||||
|
||||
```yaml
|
||||
sylius_api:
|
||||
resource: "@SyliusApiBundle/Resources/config/routing.yml"
|
||||
prefix: "%sylius.security.new_api_route%"
|
||||
```
|
||||
|
||||
1. Add `lexik_jwt_authentication.yaml` file to `config/packages/` directory:
|
||||
|
||||
```yaml
|
||||
lexik_jwt_authentication:
|
||||
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
|
||||
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
|
||||
pass_phrase: '%env(JWT_PASSPHRASE)%'
|
||||
```
|
||||
|
||||
1. Add configuration in your `.env` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
||||
+ JWT_PASSPHRASE=YOUR_SECRET_PASSPHRASE
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Add configuration in your `.env.test` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private-test.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public-test.pem
|
||||
+ JWT_PASSPHRASE=ALL_THAT_IS_GOLD_DOES_NOT_GLITTER_NOT_ALL_THOSE_WHO_WANDER_ARE_LOST
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Add configuration in your `.env.test_cached` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private-test.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public-test.pem
|
||||
+ JWT_PASSPHRASE=ALL_THAT_IS_GOLD_DOES_NOT_GLITTER_NOT_ALL_THOSE_WHO_WANDER_ARE_LOST
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Sample JWT token generation is available [here](https://api-platform.com/docs/core/jwt/)
|
||||
|
||||
1. All consts classes has been changed from final classes to interfaces. As a result initialization of `\Sylius\Bundle\UserBundle\UserEvents` is not longer possible. The whole list of changed classes can be found [here](https://github.com/Sylius/Sylius/pull/11347).
|
||||
|
||||
1. Service alias `Sylius\Component\Channel\Context\ChannelContextInterface` was changed from `sylius.context.channel.composite` to `sylius.context.channel`.
|
||||
The later is being decorated by `sylius.context.channel.cached` which caches the channel per request and reduces the amount of database queries.
|
||||
The later is being decorated by `sylius.context.channel.cached` which caches the channel per request and reduces the amount of database queries.
|
||||
|
||||
1. A serialization group has been added to the route `sylius_admin_ajax_product_index` to avoid an infinite loop, or a
|
||||
time out during this ajax request (previously no serialization group was defined on this route).
|
||||
time out during this ajax request (previously no serialization group was defined on this route).
|
||||
|
||||
1. We now use the parameter `sylius_admin.path_name` to retrieve the admin routes prefix. If you used the `/admin` prefix
|
||||
in some admin URLs you can now replace `/admin` by `/%sylius_admin.path_name%`.
|
||||
Also the route is now dynamic. You can change the `SYLIUS_ADMIN_ROUTING_PATH_NAME` environment variable to custom the admin's URL.
|
||||
in some admin URLs you can now replace `/admin` by `/%sylius_admin.path_name%`.
|
||||
Also the route is now dynamic. You can change the `SYLIUS_ADMIN_ROUTING_PATH_NAME` environment variable to custom the admin's URL.
|
||||
|
||||
## Special attention
|
||||
|
||||
|
|
@ -323,26 +61,26 @@ As we switched to the `3.0` version of Doctrine Migrations, there are some thing
|
|||
```
|
||||
|
||||
1. Mark all migrations from **@SyliusCoreBundle** and **@SyliusAdminApiBundle** as executed
|
||||
(they're the same as legacy ones, just not recognized by the doctrine _yet_)
|
||||
(they're the same as legacy ones, just not recognized by the doctrine _yet_)
|
||||
|
||||
```bash
|
||||
bin/console doctrine:migrations:version "Sylius\Bundle\CoreBundle\Migrations\Version20161202011555" --add --no-interaction
|
||||
#...
|
||||
```
|
||||
|
||||
> BEWARE!
|
||||
> BEWARE!
|
||||
|
||||
If you're using some Sylius plugins you'll probably need to handle their migrations as well.
|
||||
You can either leave them in your `src/Migrations/` catalog and treat as _your own_ or use the migrations from the vendors.
|
||||
However, it assumes that plugin provides a proper integration with Doctrine Migrations 3.0 - as, for example,
|
||||
[Invoicing Plugin](https://github.com/Sylius/InvoicingPlugin/blob/master/src/DependencyInjection/SyliusInvoicingExtension.php#L33).
|
||||
If you're using some Sylius plugins you'll probably need to handle their migrations as well.
|
||||
You can either leave them in your `src/Migrations/` catalog and treat as _your own_ or use the migrations from the vendors.
|
||||
However, it assumes that plugin provides a proper integration with Doctrine Migrations 3.0 - as, for example,
|
||||
[Invoicing Plugin](https://github.com/Sylius/InvoicingPlugin/blob/master/src/DependencyInjection/SyliusInvoicingExtension.php#L33).
|
||||
|
||||
> TIP
|
||||
> TIP
|
||||
|
||||
Take a look at [etc/migrations-1.8.sh](etc/migrations-1.8.sh) script - it would execute points 2) and 3) automatically.
|
||||
Take a look at [etc/migrations-1.8.sh](etc/migrations-1.8.sh) script - it would execute points 2) and 3) automatically.
|
||||
|
||||
1. Do the same for your own migrations. Assuming your migrations namespace is `DoctrineMigrations` and
|
||||
migrations catalog is `src/Migrations`, you can run such a script:
|
||||
migrations catalog is `src/Migrations`, you can run such a script:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
|
@ -352,7 +90,7 @@ migrations catalog is `src/Migrations`, you can run such a script:
|
|||
bin/console doctrine:migrations:version "DoctrineMigrations\\${file}" --add --no-interaction
|
||||
done
|
||||
```
|
||||
|
||||
|
||||
1. Run `bin/console doctrine:migrations:migrate` to apply migrations added in Sylius 1.8
|
||||
|
||||
#### Re-enable product variants and taxons
|
||||
|
|
@ -380,3 +118,7 @@ Some translations have changed, you may want to search for them in your project:
|
|||
- `sylius.email.shipment_confirmation.tracking_code` has been removed.
|
||||
- `sylius.email.shipment_confirmation.you_can_check_its_location` has been removed.
|
||||
- `sylius.email.shipment_confirmation.you_can_check_its_location_with_the_tracking_code` has been added instead of the two above.
|
||||
|
||||
### API v2
|
||||
|
||||
For changes according to the API v2, please visit [API v2 upgrade file](UPGRADE-API-1.8.md).
|
||||
|
|
|
|||
149
UPGRADE-1.9.md
149
UPGRADE-1.9.md
|
|
@ -1,3 +1,12 @@
|
|||
# UPGRADE FROM `v1.9.5` TO `v1.9.6`
|
||||
|
||||
1. API is disabled by default, to enable it you need to set flag to ``true`` in ``config/packages/_sylius.yaml``:
|
||||
|
||||
```yaml
|
||||
sylius_api:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.8.X` TO `v1.9.0`
|
||||
|
||||
### Package upgrades
|
||||
|
|
@ -9,31 +18,28 @@
|
|||
```
|
||||
|
||||
1. We've upgraded Sylius' ResourceBundle and GridBundle packages which forced us to upgrade major versions of our dependencies.
|
||||
|
||||
Please follow [ResourceBundle's upgrade instructions](https://github.com/Sylius/SyliusResourceBundle/blob/master/UPGRADE.md#from-16x-to-17x).
|
||||
|
||||
Apart from that, JMS Serializer major version upgrade requires to replace `array` type to `iterable` when serializing Doctrine Collections.
|
||||
|
||||
Due to FOS Rest Bundle major version upgrade, the JSON error responses might have changed. If your tests stop passing,
|
||||
you can bring back old behaviour by overriding `error.json.twig` and `exception.json.twig` templates. You can check
|
||||
how we've done that in Sylius by looking into vendor code in `templates/bundles/TwigBundle/Exception/` directory.
|
||||
Please follow [ResourceBundle's upgrade instructions](https://github.com/Sylius/SyliusResourceBundle/blob/master/UPGRADE.md#from-16x-to-17x).
|
||||
|
||||
Apart from that, JMS Serializer major version upgrade requires to replace `array` type to `iterable` when serializing Doctrine Collections.
|
||||
|
||||
Due to FOS Rest Bundle major version upgrade, the JSON error responses might have changed. If your tests stop passing,
|
||||
you can bring back old behaviour by overriding `error.json.twig` and `exception.json.twig` templates. You can check
|
||||
how we've done that in Sylius by looking into vendor code in `templates/bundles/TwigBundle/Exception/` directory.
|
||||
|
||||
1. We've replaced deprecated Doctrine Persistence API with the new one.
|
||||
|
||||
Replace `Doctrine\Common\Persistence` namespace in your codebase to `Doctrine\Persistence`.
|
||||
|
||||
1. **We've removed DoctrineCacheBundle from our required packages while upgrading to the next major version of DoctrineBundle (v2).**
|
||||
|
||||
1. **We've upgraded SyliusThemeBundle to the next major version (v2.1).**
|
||||
|
||||
Please follow [SyliusThemeBundle's upgrade instructions](https://github.com/Sylius/SyliusThemeBundle/blob/master/UPGRADE.md).
|
||||
|
||||
1. We've replaced deprecated Symfony Translator API with the new one.
|
||||
|
||||
Replace `Symfony\Component\Translation\TranslatorInterface` with `Symfony\Contracts\Translation\TranslatorInterface` in your codebase.
|
||||
|
||||
1. `/new-api` prefix has been changed to `/api/v2`. Please adjust your routes accordingly.
|
||||
Admin API is hardcoded to `/api/v1` instead of `/api/v{version}`.
|
||||
Replace `Doctrine\Common\Persistence` namespace in your codebase to `Doctrine\Persistence`.
|
||||
|
||||
1. **We've removed DoctrineCacheBundle from our required packages while upgrading to the next major version of DoctrineBundle (v2).**
|
||||
|
||||
1. **We've upgraded SyliusThemeBundle to the next major version (v2.1).**
|
||||
|
||||
Please follow [SyliusThemeBundle's upgrade instructions](https://github.com/Sylius/SyliusThemeBundle/blob/master/UPGRADE.md).
|
||||
|
||||
1. We've replaced deprecated Symfony Translator API with the new one.
|
||||
|
||||
Replace `Symfony\Component\Translation\TranslatorInterface` with `Symfony\Contracts\Translation\TranslatorInterface` in your codebase.
|
||||
|
||||
1. Add proper redirect to changing password page in your `config/routes/sylius_shop.yaml` file:
|
||||
|
||||
|
|
@ -70,10 +76,10 @@
|
|||
composer update
|
||||
```
|
||||
|
||||
1. We've removed the support for Symfony's Templating component (which is removed in Symfony 5).
|
||||
1. We've removed the support for Symfony's Templating component (which is removed in Symfony 5).
|
||||
|
||||
* Remove `templating` from framework's configuration:
|
||||
|
||||
|
||||
```diff
|
||||
# config/packages/framework.yaml
|
||||
|
||||
|
|
@ -81,12 +87,12 @@
|
|||
# ...
|
||||
- templating: { engines: ["twig"] }
|
||||
```
|
||||
|
||||
|
||||
* Replace any usages of `Symfony\Bundle\FrameworkBundle\Templating\EngineInterface` with `Twig\Environment`.
|
||||
|
||||
Inject `twig` service into your controllers instead of `templating` or `templating.engine.twig`.
|
||||
|
||||
`$templating->renderResponse(...)` might be replaced with `new Response($twig->render(...))`.
|
||||
|
||||
Inject `twig` service into your controllers instead of `templating` or `templating.engine.twig`.
|
||||
|
||||
`$templating->renderResponse(...)` might be replaced with `new Response($twig->render(...))`.
|
||||
|
||||
1. Remove Twig route configuration from your `config/routes/dev/twig.yaml`:
|
||||
|
||||
|
|
@ -96,59 +102,6 @@
|
|||
- prefix: /_error
|
||||
```
|
||||
|
||||
### New API
|
||||
|
||||
1. Adjust your `config/packages/security.yaml`.
|
||||
|
||||
* Parameters from `config/packages/security.yaml` has been moved to separated bundles.
|
||||
You may delete them if you are using the default values:
|
||||
|
||||
```diff
|
||||
- parameters:
|
||||
- sylius.security.admin_regex: "^/%sylius_admin.path_name%"
|
||||
- sylius.security.api_regex: "^/api/v1"
|
||||
- sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|api/.*|api$|media/.*)[^/]++"
|
||||
- sylius.security.new_api_route: "/api/v2"
|
||||
- sylius.security.new_api_regex: "^%sylius.security.new_api_route%"
|
||||
- sylius.security.new_api_admin_route: "%sylius.security.new_api_route%/admin"
|
||||
- sylius.security.new_api_admin_regex: "^%sylius.security.new_api_admin_route%"
|
||||
- sylius.security.new_api_shop_route: "%sylius.security.new_api_route%/shop"
|
||||
- sylius.security.new_api_shop_regex: "^%sylius.security.new_api_shop_route%"
|
||||
```
|
||||
|
||||
* If you are not using the default values, you may need to add and change parameters:
|
||||
|
||||
```diff
|
||||
parameters:
|
||||
- sylius.security.api_regex: "^/api"
|
||||
- sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|new-api|api/.*|api$|media/.*)[^/]++"
|
||||
- sylius.security.new_api_route: "/new-api"
|
||||
+ sylius.security.api_regex: "^/api/v1"
|
||||
+ sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.new_api_route: "/api/v2"
|
||||
+ sylius.security.new_api_user_account_route: "%sylius.security.new_api_shop_route%/account"
|
||||
+ sylius.security.new_api_user_account_regex: "^%sylius.security.new_api_user_account_route%"
|
||||
```
|
||||
|
||||
* Add new access control configuration and reorder it:
|
||||
|
||||
```diff
|
||||
security:
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
- - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_user_account_regex%/.*", role: ROLE_USER }
|
||||
- - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
- { path: "%sylius.security.new_api_shop_regex%/.*", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
|
||||
1. Unified API registration path in shop has been changed from `/new-api/shop/register` to `/new-api/shop/customers/`.
|
||||
|
||||
1. Identifier needed to retrieve a product in shop API endpoint (`/new-api/shop/products/{id}`) has been changed from `slug` to `code`.
|
||||
|
||||
1. Replace and add new keys in `config/packages/dev/jms_serializer.yaml`:
|
||||
|
||||
```diff
|
||||
|
|
@ -182,9 +135,9 @@
|
|||
+ - JSON_UNESCAPED_SLASHES
|
||||
+ - JSON_PRESERVE_ZERO_FRACTION
|
||||
```
|
||||
|
||||
|
||||
1. Replace key in `config/packages/jms_serializer.yaml`:
|
||||
|
||||
|
||||
```diff
|
||||
jms_serializer:
|
||||
visitors:
|
||||
|
|
@ -202,30 +155,34 @@
|
|||
|
||||
### Data migrations
|
||||
|
||||
1. The `CoreBundle/Migrations/Version20201208105207.php` migration was added which extends existing adjustments with additional details (context).
|
||||
|
||||
Depending on the type of adjustment, additionally defined information are:
|
||||
|
||||
1. The `CoreBundle/Migrations/Version20201208105207.php` migration was added which extends existing adjustments with additional details (context).
|
||||
|
||||
Depending on the type of adjustment, additionally defined information are:
|
||||
|
||||
* Taxation details (percentage and relation to tax rate)
|
||||
* Shipping details (shipping relation)
|
||||
* Taxation for shipping (combined details of percentage and shipping relation)
|
||||
|
||||
This data is fetched based on two assumptions:
|
||||
|
||||
|
||||
This data is fetched based on two assumptions:
|
||||
|
||||
* Order level taxes relates to shipping only (default Sylius behaviour)
|
||||
* Tax rate name has not changed since the time, the first order has been placed
|
||||
|
||||
If these are not true, please adjust migration accordingly to your need. To exclude following migration from execution run following code:
|
||||
|
||||
|
||||
If these are not true, please adjust migration accordingly to your need. To exclude following migration from execution run following code:
|
||||
|
||||
```
|
||||
bin/console doctrine:migrations:version 'Sylius\Bundle\CoreBundle\Migrations\Version20201208105207' --add
|
||||
```
|
||||
|
||||
1. The base of the `Adjustment` class has changed. If you extend your adjustments already (or have them overridden
|
||||
by default, because of Sylius-Standard usage), you should base your Adjustment class
|
||||
on `Sylius\Component\Core\Model\Adjustment` instead of `Sylius\Component\Order\Model\Adjustment`.
|
||||
1. The base of the `Adjustment` class has changed. If you extend your adjustments already (or have them overridden
|
||||
by default, because of Sylius-Standard usage), you should base your Adjustment class
|
||||
on `Sylius\Component\Core\Model\Adjustment` instead of `Sylius\Component\Order\Model\Adjustment`.
|
||||
|
||||
```diff
|
||||
- use Sylius\Component\Order\Model\Adjustment as BaseAdjustment;
|
||||
+ use Sylius\Component\Core\Model\Adjustment as BaseAdjustment;
|
||||
```
|
||||
|
||||
### API v2
|
||||
|
||||
For changes according to the API v2, please visit [API v2 upgrade file](UPGRADE-API-1.9.md).
|
||||
|
|
|
|||
204
UPGRADE-API-1.8.md
Normal file
204
UPGRADE-API-1.8.md
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
# UPGRADE FROM `v1.8.4` TO `v1.8.6`
|
||||
|
||||
1. Api is disabled by default, to enable it you need to set flag ``sylius_api.enabled`` to ``true`` in ``config/packages/_sylius.yaml``.
|
||||
|
||||
1. Change configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
|
||||
```diff
|
||||
security:
|
||||
firewalls:
|
||||
new_api_admin_user:
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/admin/authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_admin_route%/authentication-token"
|
||||
new_api_shop_user:
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/shop/authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_shop_route%/authentication-token"
|
||||
access_control:
|
||||
- - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.8.0` TO `v1.8.1`
|
||||
|
||||
1. Change configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
|
||||
```diff
|
||||
security:
|
||||
providers:
|
||||
- sylius_api_chain_provider:
|
||||
- chain:
|
||||
- providers: [sylius_api_shop_user_provider, sylius_api_admin_user_provider]
|
||||
|
||||
firewalls:
|
||||
new_api_admin_user:
|
||||
- pattern: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
- provider: sylius_admin_user_provider
|
||||
+ pattern: "%sylius.security.new_api_admin_regex%/.*"
|
||||
+ provider: sylius_api_admin_user_provider
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_route%/admin/authentication-token"
|
||||
|
||||
new_api_shop_user:
|
||||
- pattern: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
- provider: sylius_shop_user_provider
|
||||
+ pattern: "%sylius.security.new_api_shop_regex%/.*"
|
||||
+ provider: sylius_api_shop_user_provider
|
||||
json_login:
|
||||
- check_path: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ check_path: "%sylius.security.new_api_route%/shop/authentication-token"
|
||||
|
||||
- new_api:
|
||||
- pattern: "%sylius.security.new_api_regex%/*"
|
||||
- provider: sylius_api_chain_provider
|
||||
- stateless: true
|
||||
- anonymous: lazy
|
||||
- guard:
|
||||
- authenticators:
|
||||
- - lexik_jwt_authentication.jwt_token_authenticator
|
||||
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.7.X` TO `v1.8.0`
|
||||
|
||||
1. Add new bundles to your list of used bundles in `config/bundles.php` if you are not using it apart from Sylius:
|
||||
|
||||
```diff
|
||||
+ ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
|
||||
+ Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
|
||||
+ Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
|
||||
+ SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true],
|
||||
```
|
||||
|
||||
1. Add configuration of new ApiBundle in your `config/packages/_sylius.yaml` file:
|
||||
|
||||
```diff
|
||||
imports:
|
||||
+ - { resource: "@SyliusApiBundle/Resources/config/app/config.yaml" }
|
||||
```
|
||||
|
||||
1. Add configuration of new ApiBundle in your `config/packages/security.yaml` file:
|
||||
|
||||
```diff
|
||||
parameters:
|
||||
- sylius.security.admin_regex: "^/admin"
|
||||
- sylius.security.shop_regex: "^/(?!admin|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.admin_regex: "^/%sylius_admin.path_name%"
|
||||
+ sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|new-api|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.new_api_route: "/new-api"
|
||||
+ sylius.security.new_api_regex: "^%sylius.security.new_api_route%"
|
||||
+ sylius.security.new_api_admin_route: "%sylius.security.new_api_route%/admin"
|
||||
+ sylius.security.new_api_admin_regex: "^%sylius.security.new_api_admin_route%"
|
||||
+ sylius.security.new_api_shop_route: "%sylius.security.new_api_route%/shop"
|
||||
+ sylius.security.new_api_shop_regex: "^%sylius.security.new_api_shop_route%"
|
||||
|
||||
security:
|
||||
providers:
|
||||
+ sylius_api_admin_user_provider:
|
||||
+ id: sylius.admin_user_provider.email_or_name_based
|
||||
+ sylius_api_shop_user_provider:
|
||||
+ id: sylius.shop_user_provider.email_or_name_based
|
||||
+ sylius_api_chain_provider:
|
||||
+ chain:
|
||||
+ providers: [sylius_api_shop_user_provider, sylius_api_admin_user_provider]
|
||||
|
||||
firewalls:
|
||||
admin:
|
||||
remember_me:
|
||||
- path: /admin
|
||||
+ path: "/%sylius_admin.path_name%"
|
||||
+ new_api_admin_user:
|
||||
+ pattern: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ provider: sylius_admin_user_provider
|
||||
+ stateless: true
|
||||
+ anonymous: true
|
||||
+ json_login:
|
||||
+ check_path: "%sylius.security.new_api_route%/admin-user-authentication-token"
|
||||
+ username_path: email
|
||||
+ password_path: password
|
||||
+ success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||
+ failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
+ new_api_shop_user:
|
||||
+ pattern: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ provider: sylius_shop_user_provider
|
||||
+ stateless: true
|
||||
+ anonymous: true
|
||||
+ json_login:
|
||||
+ check_path: "%sylius.security.new_api_route%/shop-user-authentication-token"
|
||||
+ username_path: email
|
||||
+ password_path: password
|
||||
+ success_handler: lexik_jwt_authentication.handler.authentication_success
|
||||
+ failure_handler: lexik_jwt_authentication.handler.authentication_failure
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
+ new_api:
|
||||
+ pattern: "%sylius.security.new_api_regex%/*"
|
||||
+ provider: sylius_api_chain_provider
|
||||
+ stateless: true
|
||||
+ anonymous: lazy
|
||||
+ guard:
|
||||
+ authenticators:
|
||||
+ - lexik_jwt_authentication.jwt_token_authenticator
|
||||
+
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
+ - { path: "%sylius.security.new_api_shop_regex%/.*", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
1. Add `sylius_api.yaml` file to `config/routes/` directory:
|
||||
|
||||
```yaml
|
||||
sylius_api:
|
||||
resource: "@SyliusApiBundle/Resources/config/routing.yml"
|
||||
prefix: "%sylius.security.new_api_route%"
|
||||
```
|
||||
|
||||
1. Add `lexik_jwt_authentication.yaml` file to `config/packages/` directory:
|
||||
|
||||
```yaml
|
||||
lexik_jwt_authentication:
|
||||
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
|
||||
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
|
||||
pass_phrase: '%env(JWT_PASSPHRASE)%'
|
||||
```
|
||||
|
||||
1. Add configuration in your `.env` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
||||
+ JWT_PASSPHRASE=YOUR_SECRET_PASSPHRASE
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Add configuration in your `.env.test` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private-test.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public-test.pem
|
||||
+ JWT_PASSPHRASE=ALL_THAT_IS_GOLD_DOES_NOT_GLITTER_NOT_ALL_THOSE_WHO_WANDER_ARE_LOST
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Add configuration in your `.env.test_cached` file:
|
||||
|
||||
```diff
|
||||
+ ###> lexik/jwt-authentication-bundle ###
|
||||
+ JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private-test.pem
|
||||
+ JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public-test.pem
|
||||
+ JWT_PASSPHRASE=ALL_THAT_IS_GOLD_DOES_NOT_GLITTER_NOT_ALL_THOSE_WHO_WANDER_ARE_LOST
|
||||
+ ###< lexik/jwt-authentication-bundle ###
|
||||
|
||||
1. Sample JWT token generation is available [here](https://api-platform.com/docs/core/jwt/)
|
||||
156
UPGRADE-API-1.9.md
Normal file
156
UPGRADE-API-1.9.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# UPGRADE FROM `v1.9.5` TO `v1.9.6`
|
||||
|
||||
1. API is disabled by default, to enable it you need to set flag to ``true`` in ``config/packages/_sylius.yaml``:
|
||||
|
||||
```yaml
|
||||
sylius_api:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
# UPGRADE FROM `v1.9.3` TO `v1.9.4`
|
||||
|
||||
1. `Sylius\Bundle\ApiBundle\DataProvider\OrderCollectionDataProvider` has been removed and the same logic
|
||||
is now implemented in `Sylius\Bundle\ApiBundle\Doctrine\QueryCollectionExtension\OrdersByLoggedInUserExtension`
|
||||
|
||||
1. The service `Sylius\Bundle\ApiBundle\Serializer\ProductVariantSerializer` has been changed to `Sylius\Bundle\ApiBundle\Serializer\ProductVariantNormalizer`
|
||||
and its first argument `NormalizerInterface $objectNormalizer` has been removed from constructor.
|
||||
|
||||
# UPGRADE FROM `v1.9.2` TO `v1.9.3`
|
||||
|
||||
1. The endpoint `GET api/v2/order-items/{id}/adjustments` has been changed to `GET api/v2/admin/order-items/{id}/adjustments`
|
||||
|
||||
# UPGRADE FROM `v1.8.X` TO `v1.9.0`
|
||||
|
||||
1. `/new-api` prefix has been changed to `/api/v2`. Please adjust your routes accordingly.
|
||||
Admin API is hardcoded to `/api/v1` instead of `/api/v{version}`.
|
||||
|
||||
### New API
|
||||
|
||||
1. Adjust your `config/packages/security.yaml`.
|
||||
|
||||
* Parameters from `config/packages/security.yaml` has been moved to separated bundles.
|
||||
You may delete them if you are using the default values:
|
||||
|
||||
```diff
|
||||
- parameters:
|
||||
- sylius.security.admin_regex: "^/%sylius_admin.path_name%"
|
||||
- sylius.security.api_regex: "^/api/v1"
|
||||
- sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|api/.*|api$|media/.*)[^/]++"
|
||||
- sylius.security.new_api_route: "/api/v2"
|
||||
- sylius.security.new_api_regex: "^%sylius.security.new_api_route%"
|
||||
- sylius.security.new_api_admin_route: "%sylius.security.new_api_route%/admin"
|
||||
- sylius.security.new_api_admin_regex: "^%sylius.security.new_api_admin_route%"
|
||||
- sylius.security.new_api_shop_route: "%sylius.security.new_api_route%/shop"
|
||||
- sylius.security.new_api_shop_regex: "^%sylius.security.new_api_shop_route%"
|
||||
```
|
||||
|
||||
* If you are not using the default values, you may need to add and change parameters:
|
||||
|
||||
```diff
|
||||
parameters:
|
||||
- sylius.security.api_regex: "^/api"
|
||||
- sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|new-api|api/.*|api$|media/.*)[^/]++"
|
||||
- sylius.security.new_api_route: "/new-api"
|
||||
+ sylius.security.api_regex: "^/api/v1"
|
||||
+ sylius.security.shop_regex: "^/(?!%sylius_admin.path_name%|api/.*|api$|media/.*)[^/]++"
|
||||
+ sylius.security.new_api_route: "/api/v2"
|
||||
+ sylius.security.new_api_user_account_route: "%sylius.security.new_api_shop_route%/account"
|
||||
+ sylius.security.new_api_user_account_regex: "^%sylius.security.new_api_user_account_route%"
|
||||
```
|
||||
|
||||
* Add new access control configuration and reorder it:
|
||||
|
||||
```diff
|
||||
security:
|
||||
access_control:
|
||||
+ - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
- - { path: "%sylius.security.new_api_route%/admin/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_admin_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_user_account_regex%/.*", role: ROLE_USER }
|
||||
- - { path: "%sylius.security.new_api_route%/shop/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
+ - { path: "%sylius.security.new_api_shop_route%/authentication-token", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- - { path: "%sylius.security.new_api_admin_regex%/.*", role: ROLE_API_ACCESS }
|
||||
- { path: "%sylius.security.new_api_shop_regex%/.*", role: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
```
|
||||
|
||||
1. Unified API registration path in shop has been changed from `/new-api/shop/register` to `/new-api/shop/customers/`.
|
||||
|
||||
1. Identifier needed to retrieve a product in shop API endpoint (`/new-api/shop/products/{id}`) has been changed from `slug` to `code`.
|
||||
|
||||
1. `config/packages/fos_rest.yaml` rules have been changed to:
|
||||
|
||||
```diff
|
||||
rules:
|
||||
- - { path: '^/api/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
|
||||
+ - { path: '^/api/v1/.*', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: true }
|
||||
```
|
||||
|
||||
1. To have better control over the serialization process, we introduced `shop` and `admin` prefixes
|
||||
to names of serialization groups on `src/Sylius/Bundle/ApiBundle/Resources/config/api_resources/*` and `src/Sylius/Bundle/ApiBundle/Resources/config/serialization/*`.
|
||||
Several additional serialization groups have been rephrased, to improve readability and predictability of them.
|
||||
If you are using they on your custom entity `api_resource` configuration or serialization groups, you should check
|
||||
if one of these changes may affect on your app. If yes, change all occurs by this pattern:
|
||||
|
||||
- created serialization groups for `Locale` resource as: `admin:locale:read` and `admin:locale:create`
|
||||
- `adjustment:read` changed to: `admin:adjustment:read` and `shop:adjustment:read`
|
||||
- `admin_user:create` changed to: `admin:admin_user:create`
|
||||
- `admin_user:read` changed to: `admin:admin_user:read`
|
||||
- `admin_user:update` changed to: `admin:admin_user:update`
|
||||
- `avatar_image:read` changed to: `admin:avatar_image:read`
|
||||
- `cart:add_item` changed to: `shop:cart:add_item`
|
||||
- `cart:address` changed to: `shop:cart:address`
|
||||
- `cart:apply_coupon` changed to: `shop:cart:apply_coupon`
|
||||
- `cart:change_quantity` changed to: `shop:cart:change_quantity`
|
||||
- `cart:complete` changed to: `shop:cart:complete`
|
||||
- `cart:remove_item` changed to: `shop:cart:remove_item`
|
||||
- `cart:select_payment_method` changed to: `shop:cart:select_payment_method`
|
||||
- `cart:select_shipping_method` changed to: `shop:cart:select_shipping_method`
|
||||
- `cart:update` changed to: `shop:cart:update`
|
||||
- `channel:create` changed to: `admin:channel:create`
|
||||
- `channel:read` changed to: `admin:channel:read`
|
||||
- `checkout:read` changed to: `shop:cart:read`
|
||||
- `country:read` changed to: `admin:country:read`
|
||||
- `currency:read` changed to: `admin:currency:read`
|
||||
- `customer:password:write` changed to: `shop:customer:password:update`
|
||||
- `customer:read` changed to: `admin:customer:read` and `shop:customer:read`
|
||||
- `customer:update` changed to: `shop:customer:update`
|
||||
- `customer_group:create` changed to: `admin:customer_group:create`
|
||||
- `customer_group:read` changed to: `admin:customer_group:read`
|
||||
- `customer_group:update` changed to: `admin:customer_group:update`
|
||||
- `exchange_rate:create` changed to: `admin:exchange_rate:create`
|
||||
- `exchange_rate:read` changed to: `admin:exchange_rate:read`
|
||||
- `exchange_rate:update` changed to: `admin:exchange_rate:update`
|
||||
- `order:create` changed to: `shop:order:create`
|
||||
- `order:read` changed to: `admin:order:read`
|
||||
- `order:update` changed to: `admin:order:update`
|
||||
- `order_item:read` changed to: `admin:order_item:read` and `shop:order_item:read`
|
||||
- `order_item_unit:read` changed to: `admin:order_item_unit:read` and `shop:order_item_unit:read`
|
||||
- `payment:read` changed to: `admin:payment:read` and `shop:payment:read`
|
||||
- `payment_method:read` changed to: `admin:payment_method:read` and `shop:payment_method:read`
|
||||
- `product:create` changed to: `admin:product:create`
|
||||
- `product:read` changed to: `admin:product:read` and `shop:product:read`
|
||||
- `product:update` changed to: `admin:product:update`
|
||||
- `province:read` changed to: `admin:province:read`
|
||||
- `province:update` changed to: `admin:province:update`
|
||||
- `shipment:read` changed to: `admin:shipment:read` and `shop:shipment:read`
|
||||
- `shipment:update` changed to: `admin:shipment:update`
|
||||
- `shipping_category:create` changed to: `admin:shipping_category:create`
|
||||
- `shipping_category:read` changed to: `admin:shipping_category:read`
|
||||
- `shipping_category:update` changed to: `admin:shipping_category:update`
|
||||
- `shipping_method:create` changed to: `admin:shipping_method:create`
|
||||
- `shipping_method:read` changed to: `admin:shipping_method:read`
|
||||
- `shipping_method:update` changed to: `admin:shipping_method:update`
|
||||
- `shop:currencies:read` changed to: `shop:currency:read`
|
||||
- `shop:customer:write` changed to: `shop:customer:create`
|
||||
- `shop_billing_data:read` changed to: `admin:shop_billing_data:read`
|
||||
- `tax_category:read` changed to: `admin:tax_category:read`
|
||||
- `tax_category:update` changed to: `admin:tax_category:update`
|
||||
- `tax_category:create` changed to: `admin:tax_category:create`
|
||||
- `taxon:read` changed to: `admin:taxon:read` and `shop:taxon:read`
|
||||
- `taxon:update` changed to: `admin:taxon:update`
|
||||
- `taxon:create` changed to: `admin:taxon:create`
|
||||
- `zone:read` changed to: `admin:zone:read`
|
||||
- `zone:update` changed to: `admin:zone:update`
|
||||
- `zone:create` changed to: `admin:zone:create`
|
||||
- `zone_member:read` changed to: `admin:zone_member:read`
|
||||
- removed redundant `zone_member:write`
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "sylius/sylius",
|
||||
"type": "library",
|
||||
"version": "v1.9.9-dev",
|
||||
"description": "E-Commerce platform for PHP, based on Symfony framework.",
|
||||
"homepage": "https://sylius.com",
|
||||
"license": "MIT",
|
||||
|
|
@ -35,7 +36,7 @@
|
|||
"egulias/email-validator": "^2.1",
|
||||
"fakerphp/faker": "^1.9",
|
||||
"friendsofphp/proxy-manager-lts": "^1.0",
|
||||
"friendsofsymfony/oauth-server-bundle": "^1.6 || >2.0.0-alpha.0 ^2.0@dev",
|
||||
"friendsofsymfony/oauth-server-bundle": ">2.0.0-alpha.0 ^2.0@dev",
|
||||
"friendsofsymfony/rest-bundle": "^3.0",
|
||||
"gedmo/doctrine-extensions": "^2.4.12 || ^3.0",
|
||||
"jms/serializer-bundle": "^3.5",
|
||||
|
|
@ -58,6 +59,7 @@
|
|||
"sylius-labs/polyfill-symfony-event-dispatcher": "^1.0.1",
|
||||
"sylius-labs/polyfill-symfony-framework-bundle": "^1.0",
|
||||
"sylius-labs/polyfill-symfony-security": "^1.0",
|
||||
"sylius/admin-api-bundle": "~1.9.3",
|
||||
"sylius/fixtures-bundle": "^1.6.1",
|
||||
"sylius/grid": "^1.8",
|
||||
"sylius/grid-bundle": "^1.8",
|
||||
|
|
@ -160,9 +162,13 @@
|
|||
"conflict": {
|
||||
"api-platform/core": "^2.6",
|
||||
"doctrine/dbal": "^3",
|
||||
"doctrine/doctrine-bundle": "2.3.0",
|
||||
"doctrine/orm": "^2.10.0",
|
||||
"jms/serializer-bundle": "3.9.0",
|
||||
"laminas/laminas-code": "^4.0.0",
|
||||
"symfony/doctrine-bridge": "4.4.16",
|
||||
"symfony/polyfill-mbstring": "^1.22.0",
|
||||
"symfony/property-info": "4.4.22 || 5.2.7",
|
||||
"symfony/serializer": "4.4.19 || 5.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -199,7 +205,7 @@
|
|||
"symfony/flex": "^1.7",
|
||||
"symfony/web-profiler-bundle": "^4.4 || ^5.2",
|
||||
"symplify/package-builder": "^8.0 <8.3",
|
||||
"vimeo/psalm": "4.4.1"
|
||||
"vimeo/psalm": "4.7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "For better performance than using Symfony Polyfill Component",
|
||||
|
|
@ -252,7 +258,6 @@
|
|||
"spec\\Sylius\\Component\\Taxonomy\\": "src/Sylius/Component/Taxonomy/spec/",
|
||||
"spec\\Sylius\\Component\\User\\": "src/Sylius/Component/User/spec/",
|
||||
"spec\\Sylius\\Bundle\\AddressingBundle\\": "src/Sylius/Bundle/AddressingBundle/spec/",
|
||||
"spec\\Sylius\\Bundle\\AdminApiBundle\\": "src/Sylius/Bundle/AdminApiBundle/spec/",
|
||||
"spec\\Sylius\\Bundle\\AdminBundle\\": "src/Sylius/Bundle/AdminBundle/spec/",
|
||||
"spec\\Sylius\\Bundle\\ApiBundle\\": "src/Sylius/Bundle/ApiBundle/spec/",
|
||||
"spec\\Sylius\\Bundle\\AttributeBundle\\": "src/Sylius/Bundle/AttributeBundle/spec/",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ imports:
|
|||
parameters:
|
||||
sylius_core.public_dir: '%kernel.project_dir%/public'
|
||||
|
||||
sylius_api:
|
||||
enabled: false
|
||||
|
||||
sylius_shop:
|
||||
product_grid:
|
||||
include_all_descendants: true
|
||||
|
|
|
|||
2
config/packages/dev/_sylius.yaml
Normal file
2
config/packages/dev/_sylius.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
sylius_api:
|
||||
enabled: true
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
doctrine:
|
||||
orm:
|
||||
metadata_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
query_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
result_cache_driver:
|
||||
type: service
|
||||
id: doctrine.result_cache_provider
|
||||
entity_managers:
|
||||
default:
|
||||
metadata_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
query_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
result_cache_driver:
|
||||
type: service
|
||||
id: doctrine.result_cache_provider
|
||||
|
||||
services:
|
||||
doctrine.result_cache_provider:
|
||||
|
|
|
|||
2
config/packages/test/_sylius.yaml
Normal file
2
config/packages/test/_sylius.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
sylius_api:
|
||||
enabled: true
|
||||
2
config/packages/test_cached/_sylius.yaml
Normal file
2
config/packages/test_cached/_sylius.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
sylius_api:
|
||||
enabled: true
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
doctrine:
|
||||
orm:
|
||||
metadata_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
query_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
result_cache_driver:
|
||||
type: service
|
||||
id: doctrine.result_cache_provider
|
||||
entity_managers:
|
||||
default:
|
||||
metadata_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
query_cache_driver:
|
||||
type: service
|
||||
id: doctrine.system_cache_provider
|
||||
result_cache_driver:
|
||||
type: service
|
||||
id: doctrine.result_cache_provider
|
||||
|
||||
services:
|
||||
doctrine.result_cache_provider:
|
||||
|
|
|
|||
BIN
docs/_images/cookbook/custom-invoice/pdf_after.png
Normal file
BIN
docs/_images/cookbook/custom-invoice/pdf_after.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
docs/_images/cookbook/custom-invoice/pdf_before.png
Normal file
BIN
docs/_images/cookbook/custom-invoice/pdf_before.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
BIN
docs/_images/cookbook/custom-invoice/pdf_phone.png
Normal file
BIN
docs/_images/cookbook/custom-invoice/pdf_phone.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/_images/cookbook/custom-invoice/pdf_total.png
Normal file
BIN
docs/_images/cookbook/custom-invoice/pdf_total.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -5,6 +5,7 @@ Introduction
|
|||
|
||||
The new, unified Sylius API is still under development, that's why the whole ``ApiBundle`` is tagged with ``@experimental``.
|
||||
This means that all code from ``ApiBundle`` is excluded from :doc:`Backward Compatibility Promise </book/organization/backward-compatibility-promise>`.
|
||||
You can enable entire API by changing the flag ``sylius_api.enabled`` to ``true`` in ``config/packages/_sylius.yaml``.
|
||||
|
||||
We have decided that we should rebuild our API and use API Platform to build a truly mature, multi-purpose API
|
||||
which can define a new standard for headless e-commerce backends.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Every time a customer registers via the registration form, a user registration e
|
|||
|
||||
**Code**: ``user_registration``
|
||||
|
||||
**The default template**: ``@SyliusShopBundle/Email/userRegistration.html.twig``
|
||||
**The default template**: ``@SyliusShop/Email/userRegistration.html.twig``
|
||||
|
||||
You also have the following parameters available:
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ When a customer registers via the registration form, besides the User Confirmati
|
|||
|
||||
**Code**: ``verification_token``
|
||||
|
||||
**The default template**: ``@SyliusShopBundle/Email/verification.html.twig``
|
||||
**The default template**: ``@SyliusShop/Email/verification.html.twig``
|
||||
|
||||
You also have the following parameters available:
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ This e-mail is used when the user requests to reset their password in the login
|
|||
|
||||
**Code**: ``reset_password_token``
|
||||
|
||||
**The default template**: ``@SyliusShopBundle/Email/passwordReset.html.twig``
|
||||
**The default template**: ``@SyliusShop/Email/passwordReset.html.twig``
|
||||
|
||||
You also have the following parameters available:
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ This e-mail is sent when order is placed.
|
|||
|
||||
**Code**: ``order_confirmation``
|
||||
|
||||
**The default template**: ``@SyliusShopBundle/Email/orderConfirmation.html.twig``
|
||||
**The default template**: ``@SyliusShop/Email/orderConfirmation.html.twig``
|
||||
|
||||
You also have the following parameters available:
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ This e-mail is sent when the order's shipping process has started.
|
|||
|
||||
**Code**: ``shipment_confirmation``
|
||||
|
||||
**The default template**: ``@SyliusAdminBundle/Email/shipmentConfirmation.html.twig``
|
||||
**The default template**: ``@SyliusAdmin/Email/shipmentConfirmation.html.twig``
|
||||
|
||||
You have the following parameters available:
|
||||
|
||||
|
|
@ -84,6 +84,21 @@ You have the following parameters available:
|
|||
* ``channel``: Channel in which an order was placed
|
||||
* ``localeCode``: Locale code in which an order was placed
|
||||
|
||||
Contact Request
|
||||
---------------
|
||||
|
||||
This e-mail is sent when a customer validades contact form.
|
||||
|
||||
**Code**: ``contact_request``
|
||||
|
||||
**The default template**: ``@SyliusShop/Email/contactRequest.html.twig``
|
||||
|
||||
You have the following parameters available:
|
||||
|
||||
* ``data``: An array of submitted data from form
|
||||
* ``channel``: Channel in which an order was placed
|
||||
* ``localeCode``: Locale code in which an order was placed
|
||||
|
||||
.. rst-class:: plus-doc
|
||||
|
||||
Return Requests Emails
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ Choose the right Base Branch
|
|||
|
||||
Before starting to work on a patch, you must determine on which branch you need to work. It will be:
|
||||
|
||||
* ``1.7``, if you are fixing or adding docs for features that exist in one of those versions,
|
||||
* ``master``, if you are documenting a new feature, that was not in ``1.7``
|
||||
* ``1.x``, if you are fixing or adding docs for features that exist in one of those versions,
|
||||
* ``master``, if you are documenting a new feature, that was not in ``1.x``
|
||||
|
||||
.. note::
|
||||
|
||||
All bug fixes merged into the ``1.7`` maintenance branches are also merged into ``master`` on a regular basis.
|
||||
All bug fixes merged into the ``1.x`` maintenance branches are also merged into ``master`` on a regular basis.
|
||||
|
||||
Create a dedicated branch for your changes (for organization):
|
||||
|
||||
|
|
@ -67,6 +67,10 @@ To test the documentation before a commit you need to install Sphinx and needed
|
|||
|
||||
Official Sphinx installation guide : `www.sphinx-doc.org <https://www.sphinx-doc.org/en/master/usage/installation.html>`_
|
||||
|
||||
.. note::
|
||||
|
||||
If you are using docker - you can try building your documentation with: `Sylius Documentation Builder <https://github.com/arti0090/SyliusDocumentationBuilder>`_
|
||||
|
||||
Our recommendation is to install ``Sphinx`` via `Pip`_.
|
||||
|
||||
We suggest to install & use ``Sphinx v1.8.5``
|
||||
|
|
|
|||
|
|
@ -15,17 +15,19 @@ Installing Sylius Plus as a plugin to a Sylius application
|
|||
+---------------+-----------------------+
|
||||
| PHP | ^7.3 |
|
||||
+---------------+-----------------------+
|
||||
| sylius/sylius | ^1.7 |
|
||||
| sylius/sylius | ^1.9 |
|
||||
+---------------+-----------------------+
|
||||
| Symfony | ^5.2 |
|
||||
+---------------+-----------------------+
|
||||
|
||||
**0.** Prepare project:
|
||||
|
||||
.. tip::
|
||||
|
||||
If it is a new project you are initiating, then first install Sylius-Standard in **version ^1.6** according to
|
||||
If it is a new project you are initiating, then first install Sylius-Standard in **version ^1.9** according to
|
||||
:doc:`these instructions </book/installation/installation>`.
|
||||
|
||||
If you're installing Plus package to an existing project, then make sure you're upgraded to ``sylius/sylius ^1.7``.
|
||||
If you're installing Plus package to an existing project, then make sure you're upgraded to ``sylius/sylius ^1.9``.
|
||||
|
||||
**1.** Configure access to the private Packagist package in composer by using the Access Token you have been given with your license.
|
||||
|
||||
|
|
@ -38,8 +40,7 @@ Installing Sylius Plus as a plugin to a Sylius application
|
|||
.. code-block:: bash
|
||||
|
||||
composer config repositories.plus composer https://sylius.repo.packagist.com/ShortNameOfYourOrganization/
|
||||
composer require sylius/plus --no-update
|
||||
composer config minimum-stability rc #due to the usage of some pre-stable packages (like SyliusRefundPlugin)
|
||||
composer require "sylius/plus:^1.0.0-ALPHA.1" --no-update
|
||||
composer update --no-scripts
|
||||
composer sync-recipes
|
||||
|
||||
|
|
@ -58,23 +59,27 @@ Installing Sylius Plus as a plugin to a Sylius application
|
|||
|
||||
.. code-block:: yaml
|
||||
|
||||
// config/packages/_sylius.yaml
|
||||
# config/packages/_sylius.yaml
|
||||
imports:
|
||||
...
|
||||
- { resource: "@SyliusPlusPlugin/Resources/config/config.yaml" }
|
||||
|
||||
.. code-block:: yaml
|
||||
.. warning::
|
||||
|
||||
// config/packages/messenger.yaml
|
||||
framework:
|
||||
messenger:
|
||||
default_bus: sylius_invoicing_plugin.command_bus
|
||||
Recommended Sylius version to use with Sylius Plus is 1.10. If, for any reason, you need to use Sylius 1.9, it's required
|
||||
to customise some API configurations. Run the following commands, to do it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
rm vendor/sylius/plus/src/Resources/config/api_resources/Shipment.xml
|
||||
mkdir config/api_platform/
|
||||
cp -R vendor/sylius/plus/etc/sylius-1.9/Resources/config/api_resources/* config/api_platform/
|
||||
|
||||
**5.** Configure Shop, Admin and Admin API routing:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
// config/routes/sylius_shop.yaml
|
||||
# config/routes/sylius_shop.yaml
|
||||
...
|
||||
|
||||
sylius_plus_shop:
|
||||
|
|
@ -85,21 +90,24 @@ Installing Sylius Plus as a plugin to a Sylius application
|
|||
|
||||
.. code-block:: yaml
|
||||
|
||||
// config/routes/sylius_admin.yaml:
|
||||
#...
|
||||
# config/routes/sylius_admin.yaml:
|
||||
...
|
||||
|
||||
sylius_plus_admin:
|
||||
resource: "@SyliusPlusPlugin/Resources/config/admin_routing.yaml"
|
||||
prefix: /admin
|
||||
.. warning::
|
||||
|
||||
.. code-block:: yaml
|
||||
Not needed for Sylius Plus >= `1.0.0-ALPHA.1`
|
||||
|
||||
// config/routes/sylius_admin_api.yaml:
|
||||
#...
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_plus_admin_api:
|
||||
resource: "@SyliusPlusPlugin/Resources/config/api_routing.yaml"
|
||||
prefix: /api/v1
|
||||
# config/routes/sylius_admin_api.yaml:
|
||||
...
|
||||
|
||||
sylius_plus_admin_api:
|
||||
resource: "@SyliusPlusPlugin/Resources/config/api_routing.yaml"
|
||||
prefix: /api/v1
|
||||
|
||||
**6.** Add traits that enhance Sylius models:
|
||||
|
||||
|
|
@ -287,16 +295,18 @@ Installing Sylius Plus as a plugin to a Sylius application
|
|||
use ShipmentTrait;
|
||||
}
|
||||
|
||||
**7.** Copy and apply migrations:
|
||||
**7.** Add wkhtmltopdf binary for Invoicing purposes.
|
||||
|
||||
Copy Sylius Plus migrations from ``vendor/sylius/plus/migrations/`` to your migrations directory (e.g. ``src/Migrations``)
|
||||
and apply them to your database:
|
||||
If you do not have the ``wkhtmltopdf`` binary, download it `here <https://wkhtmltopdf.org/downloads.html>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
In case wkhtmltopdf is not located in ``/usr/local/bin/wkhtmltopdf``, add the following snippet at the end of
|
||||
your application's ``.env`` file:
|
||||
|
||||
bin/console doctrine:database:create --if-not-exists
|
||||
cp -f vendor/sylius/plus/migrations/* src/Migrations
|
||||
bin/console doctrine:migrations:migrate -n
|
||||
.. code-block:: yaml
|
||||
|
||||
###> knplabs/knp-snappy-bundle ###
|
||||
WKHTMLTOPDF_PATH=/your-path
|
||||
###< knplabs/knp-snappy-bundle ###
|
||||
|
||||
**8.** Install Sylius with Sylius Plus fixtures:
|
||||
|
||||
|
|
@ -312,26 +322,13 @@ and apply them to your database:
|
|||
|
||||
bin/console sylius:install --fixture-suite plus -n
|
||||
|
||||
**9.** Add wkhtmltopdf binary for Invoicing purposes.
|
||||
|
||||
If you do not have the ``wkhtmltopdf`` binary, download it `here <https://wkhtmltopdf.org/downloads.html>`_.
|
||||
|
||||
In case wkhtmltopdf is not located in ``/usr/local/bin/wkhtmltopdf``, add the following snippet at the end of
|
||||
your application's ``.env`` file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
###> knplabs/knp-snappy-bundle ###
|
||||
WKHTMLTOPDF_PATH=/your-path
|
||||
###< knplabs/knp-snappy-bundle ###
|
||||
|
||||
**10.** Copy templates that are overridden by Sylius Plus into ``templates/bundles``:
|
||||
**9.** Copy templates that are overridden by Sylius Plus into ``templates/bundles``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cp -fr vendor/sylius/plus/src/Resources/templates/bundles/* templates/bundles
|
||||
|
||||
**11.** Install JS libraries using Yarn:
|
||||
**10.** Install JS libraries using Yarn:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
|
@ -339,7 +336,14 @@ your application's ``.env`` file:
|
|||
yarn build
|
||||
bin/console assets:install --ansi
|
||||
|
||||
**12.** Additionally check the installation guides for all plugins installed as dependencies with Sylius Plus.
|
||||
**11.** Rebuild cache for proper display of all translations:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
bin/console cache:clear
|
||||
bin/console cache:warmup
|
||||
|
||||
**12.** For more details check the installation guides for all plugins installed as dependencies with Sylius Plus.
|
||||
|
||||
* `Sylius/InvoicingPlugin <https://github.com/Sylius/InvoicingPlugin/blob/master/README.md#installation>`_
|
||||
* `Sylius/RefundPlugin <https://github.com/Sylius/RefundPlugin/blob/master/README.md#installation>`_
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ from the repository to assign it to your order's payment created defaultly in th
|
|||
// Let's assume that you have a method with code 'paypal' configured
|
||||
$paymentMethod = $this->container->get('sylius.repository.payment_method')->findOneByCode('paypal');
|
||||
|
||||
// Payments are a Collection, so even though you hve one Payment by default you have to iterate over them
|
||||
// Payments are a Collection, so even though you have one Payment by default you have to iterate over them
|
||||
foreach ($order->getPayments() as $payment) {
|
||||
$payment->setMethod($paymentMethod);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ That's it! All other files are just a boilerplate to show you what can be done i
|
|||
|
||||
* All files from ``tests/Behat/Page/Shop/`` (with corresponding services)
|
||||
|
||||
* ``tests/Context/Ui/Shop/WelcomeContext.php`` (with corresponding service)
|
||||
* ``tests/Behat/Context/Ui/Shop/WelcomeContext.php`` (with corresponding service)
|
||||
|
||||
You should also delete Behat suite named ``greeting_customer`` from ``tests/Behat/Resources/suites.yml``.
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Exemplary features may be: Social media buttons, newsletter, wishlists, payment
|
|||
|
||||
.. tip::
|
||||
|
||||
**The list of all Sylius Plugins (official and approved) is available on the Sylius website** `here <https://sylius.com/developers/store/plugins>`_.
|
||||
**The list of all Sylius Plugins (official and approved) is available on the Sylius website** `here <https://plugins.sylius.com/plugins/>`_.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ To do that find a desired taxon by code and get all its products. Perfect access
|
|||
/** @var TaxonInterface $taxon */
|
||||
$taxon = $this->container->get('sylius.repository.taxon')->findOneBy(['code' => 'sd-cards']);
|
||||
|
||||
$associatedProducts = $taxon->getProducts();
|
||||
$associatedProducts = $this->container->get('sylius.repository.product')->findByTaxon($taxon);
|
||||
|
||||
Having a collection of products from the SD cards taxon iterate over them and add them one by one to the association.
|
||||
|
||||
|
|
@ -86,6 +86,26 @@ And to save everything in the database you need to add the created association t
|
|||
|
||||
$this->container->get('sylius.repository.product_association')->add($association);
|
||||
|
||||
In the previous example we used a custom query in the product repository, here is the implementation:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Sylius\Bundle\CoreBundle\Doctrine\ORM\ProductRepository as BaseProductRepository;
|
||||
|
||||
class ProductRepository extends BaseProductRepository
|
||||
{
|
||||
public function findByTaxon(Taxon $taxon): array
|
||||
{
|
||||
return $this->createQueryBuilder('p')
|
||||
->join('p.productTaxons', 'pt')
|
||||
->where('pt.taxon = :taxon')
|
||||
->setParameter('taxon', $taxon)
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
Learn more:
|
||||
-----------
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ When you create a new asset or delete an existing one, it is required to rerun t
|
|||
4. Customize a template:
|
||||
|
||||
In order to customize the login view you should take the content of ``@SyliusShopBundle/views/login.html.twig`` file
|
||||
and paste it to your theme directory: ``themes/CrimsonTheme/SyliusShopBundle/views/login.html.twig``
|
||||
and paste it to your theme directory: ``themes/CrimsonTheme/templates/bundles/SyliusShopBundle/login.html.twig``
|
||||
|
||||
Let's remove the registration column in this example:
|
||||
|
||||
|
|
|
|||
13
docs/cookbook/configuration/admin-prefix.rst
Normal file
13
docs/cookbook/configuration/admin-prefix.rst
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
How to customize Admin routes prefix?
|
||||
=====================================
|
||||
|
||||
By default, Sylius administration routes are prefixed with ``/admin``.
|
||||
|
||||
You can use the parameter ``sylius_admin.path_name`` to retrieve the admin routes prefix.
|
||||
|
||||
In order to change to administration panel route prefix you need to modify the ``SYLIUS_ADMIN_ROUTING_PATH_NAME`` environment variable.
|
||||
|
||||
.. warning::
|
||||
|
||||
If you used the ``/admin`` prefix in some admin URLs in your custom code you need to replace the ``/admin``
|
||||
by ``/%sylius_admin.path_prefix%``.
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
* :doc:`/cookbook/configuration/installation-commands`
|
||||
* :doc:`/cookbook/configuration/disabling-shop-admin-api`
|
||||
* :doc:`/cookbook/configuration/disabling-admin-notifications`
|
||||
* :doc:`/cookbook/configuration/admin-prefix`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,279 @@
|
|||
.. rst-class:: plus-doc
|
||||
|
||||
How to add a custom model accessible for respective channel administrators?
|
||||
===========================================================================
|
||||
|
||||
Given that you are using Sylius Plus, the licensed edition of Sylius, you may have
|
||||
the Administrators per Channel defined in your application. Thus when you add a new,
|
||||
channel-based entity to it, you will need to enable this entity to be viewed only by the relevant channel admins.
|
||||
|
||||
1. Define your custom model, our example will be the **Supplier entity**
|
||||
------------------------------------------------------------------------
|
||||
|
||||
In order to prepare a simple Entity follow :doc:`this guide </cookbook/entities/custom-model>`.
|
||||
|
||||
Remember to then add your entity to the admin menu. Adding a new entity to the admin menu
|
||||
is described in the section ``How to customize Admin Menu`` of :doc:`this guide </customization/menu>`.
|
||||
|
||||
* Having your Supplier entity created, add a channel field with relation to the ``Channel`` entity:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
/**
|
||||
* @var ChannelInterface
|
||||
* @ORM\ManyToOne(targetEntity="Sylius\Plus\Entity\ChannelInterface")
|
||||
* @ORM\JoinColumn(name="channel_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $channel;
|
||||
|
||||
public function getChannel(): ?ChannelInterface
|
||||
{
|
||||
return $this->channel;
|
||||
}
|
||||
|
||||
public function setChannel(?ChannelInterface $channel): void
|
||||
{
|
||||
$this->channel = $channel;
|
||||
}
|
||||
|
||||
* Assuming that your database was up-to-date before these changes, create a proper migration and use it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php bin/console doctrine:migrations:diff
|
||||
php bin/console doctrine:migrations:migrate
|
||||
|
||||
* Next, create a form type for your entity:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use Sylius\Bundle\ChannelBundle\Form\Type\ChannelChoiceType;
|
||||
use Sylius\Bundle\ResourceBundle\Form\Type\AbstractResourceType;
|
||||
use Sylius\Plus\ChannelAdmin\Application\Provider\AvailableChannelsForAdminProviderInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
final class SupplierType extends AbstractResourceType
|
||||
{
|
||||
/** @var AvailableChannelsForAdminProviderInterface */
|
||||
private $availableChannelsForAdminProvider;
|
||||
|
||||
public function __construct(
|
||||
string $dataClass,
|
||||
array $validationGroups,
|
||||
AvailableChannelsForAdminProviderInterface $availableChannelsForAdminProvider
|
||||
) {
|
||||
parent::__construct($dataClass, $validationGroups);
|
||||
|
||||
$this->availableChannelsForAdminProvider = $availableChannelsForAdminProvider;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('name', TextType::class, [
|
||||
'label' => 'Name'
|
||||
])
|
||||
->add('channel', ChannelChoiceType::class, [
|
||||
'choices' => $this->availableChannelsForAdminProvider->getChannels(),
|
||||
'label' => 'sylius.ui.channel',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function getBlockPrefix(): string
|
||||
{
|
||||
return 'supplier';
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
App\Form\Type\SupplierType:
|
||||
arguments: ['App\Entity\Supplier', ['sylius'], '@Sylius\Plus\ChannelAdmin\Application\Provider\AvailableChannelsForAdminProviderInterface']
|
||||
tags: ['form.type']
|
||||
|
||||
The ``Sylius\Plus\ChannelAdmin\Application\Provider\AvailableChannelsForAdminProviderInterface`` service allows getting
|
||||
a list of proper channels for the currently logged in admin user.
|
||||
|
||||
Remember to register ``App\Form\SupplierType`` for resource:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_resource:
|
||||
resources:
|
||||
app.supplier:
|
||||
driver: doctrine/orm
|
||||
classes:
|
||||
model: App\Entity\Supplier
|
||||
+ form: App\Form\Type\SupplierType
|
||||
|
||||
1. Restrict access to the entity for the respective channel administrator:
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
More information about using administrator roles (ACL/RBAC) can be found :doc:`here </book/customers/admin_user>`.
|
||||
|
||||
* Create ``App\Checker\ResourceChannelEnabilibityChecker`` and decorate ``Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelEnabilibityCheckerInterface``.
|
||||
|
||||
* Then add ``Supplier`` as checking resource:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Checker;
|
||||
|
||||
use Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelEnabilibityCheckerInterface;
|
||||
|
||||
final class ResourceChannelEnabilibityChecker implements ResourceChannelEnabilibityCheckerInterface
|
||||
{
|
||||
/** @var ResourceChannelEnabilibityCheckerInterface */
|
||||
private $decoratedResourceChannelEnabilibityChecker;
|
||||
|
||||
public function __construct(ResourceChannelEnabilibityCheckerInterface $decoratedResourceChannelEnabilibityChecker)
|
||||
{
|
||||
$this->decoratedResourceChannelEnabilibityChecker = $decoratedResourceChannelEnabilibityChecker;
|
||||
}
|
||||
|
||||
public function forResourceName(string $resourceName): bool
|
||||
{
|
||||
if ($this->decoratedResourceChannelEnabilibityChecker->forResourceName($resourceName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $resourceName === 'supplier';
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
App\Checker\ResourceChannelEnabilibityChecker:
|
||||
decorates: Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelEnabilibityCheckerInterface
|
||||
arguments: ['@.inner']
|
||||
|
||||
* Create ``App\Checker\ResourceChannelChecker`` and decorate ``Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelCheckerInterface`` next add condition for checking ``Supplier``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Checker;
|
||||
|
||||
use App\Entity\Supplier;
|
||||
use Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelCheckerInterface;
|
||||
use Sylius\Plus\Entity\ChannelInterface;
|
||||
|
||||
final class ResourceChannelChecker implements ResourceChannelCheckerInterface
|
||||
{
|
||||
/** @var ResourceChannelCheckerInterface */
|
||||
private $decoratedResourceChannelChecker;
|
||||
|
||||
public function __construct(ResourceChannelCheckerInterface $decoratedResourceChannelChecker)
|
||||
{
|
||||
$this->decoratedResourceChannelChecker = $decoratedResourceChannelChecker;
|
||||
}
|
||||
|
||||
public function isFromChannel(object $resource, ChannelInterface $channel): bool
|
||||
{
|
||||
if ($resource instanceof Supplier && in_array($resource->getChannel(), [$channel, null], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->decoratedResourceChannelChecker->isFromChannel($resource, $channel);
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
App\Checker\ResourceChannelChecker:
|
||||
decorates: Sylius\Plus\ChannelAdmin\Application\Checker\ResourceChannelCheckerInterface
|
||||
arguments: ['@.inner']
|
||||
|
||||
After that, access to the resource should work properly with all restrictions.
|
||||
|
||||
* Next add ``RestrictingSupplierListQueryBuilder``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Doctrine\ORM;
|
||||
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Sylius\Plus\ChannelAdmin\Application\Provider\AdminChannelProviderInterface;
|
||||
|
||||
final class RestrictingSupplierListQueryBuilder
|
||||
{
|
||||
/** @var AdminChannelProviderInterface */
|
||||
private $adminChannelProvider;
|
||||
|
||||
/** @var EntityRepository */
|
||||
private $supplierRepository;
|
||||
|
||||
public function __construct(
|
||||
AdminChannelProviderInterface $adminChannelProvider,
|
||||
EntityRepository $supplierRepository
|
||||
) {
|
||||
$this->adminChannelProvider = $adminChannelProvider;
|
||||
$this->supplierRepository = $supplierRepository;
|
||||
}
|
||||
|
||||
public function create(): QueryBuilder
|
||||
{
|
||||
$listQueryBuilder = $this->supplierRepository->createQueryBuilder('o');
|
||||
|
||||
/** @var ChannelInterface|null $channel */
|
||||
$channel = $this->adminChannelProvider->getChannel();
|
||||
if ($channel === null) {
|
||||
return $listQueryBuilder;
|
||||
}
|
||||
|
||||
return $listQueryBuilder
|
||||
->andWhere('o.channel = :channel')
|
||||
->setParameter('channel', $channel)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
App\Doctrine\ORM\RestrictingSupplierListQueryBuilder:
|
||||
public: true
|
||||
class: App\Doctrine\ORM\RestrictingSupplierListQueryBuilder
|
||||
arguments: ['@Sylius\Plus\ChannelAdmin\Application\Provider\AdminChannelProviderInterface', '@app.repository.supplier']
|
||||
|
||||
* Add method to the Suppliers grid:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_grid:
|
||||
grids:
|
||||
app_admin_supplier:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
class: App\Entity\Supplier
|
||||
+ repository:
|
||||
+ method: [expr:service('App\\Doctrine\\ORM\\RestrictingSupplierListQueryBuilder'), create]
|
||||
|
||||
Well done! That's it, now you have a Supplier entity, that is accessible within the Sylius Plus Administrators per Channel feature!
|
||||
|
|
@ -180,7 +180,6 @@ Having a grid prepared we can configure routing for the entity administration:
|
|||
resource: |
|
||||
alias: app.supplier
|
||||
section: admin
|
||||
path: admin
|
||||
templates: "@SyliusAdmin\\Crud"
|
||||
redirect: update
|
||||
grid: app_admin_supplier
|
||||
|
|
@ -190,28 +189,8 @@ Having a grid prepared we can configure routing for the entity administration:
|
|||
index:
|
||||
icon: 'file image outline'
|
||||
type: sylius.resource
|
||||
prefix: /admin
|
||||
|
||||
.. note::
|
||||
|
||||
You can replace ``path: admin`` with ``prefix: /admin``
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/routes.yaml
|
||||
app_admin_supplier:
|
||||
resource: |
|
||||
alias: app.supplier
|
||||
section: admin
|
||||
templates: "@SyliusAdmin\\Crud"
|
||||
redirect: update
|
||||
grid: app_admin_supplier
|
||||
vars:
|
||||
all:
|
||||
subheader: app.ui.supplier
|
||||
index:
|
||||
icon: 'file image outline'
|
||||
type: sylius.resource
|
||||
prefix: /admin
|
||||
|
||||
10. Add entity administration to the admin menu
|
||||
-----------------------------------------------
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
* :doc:`/cookbook/entities/custom-model`
|
||||
* :doc:`/cookbook/entities/custom-model-accessible-for-channel-admin`
|
||||
* :doc:`/cookbook/entities/custom-translatable-model`
|
||||
|
|
|
|||
|
|
@ -41,12 +41,19 @@ This is a simple guide on how to start using webpack in Sylius apps. Webpack fin
|
|||
// templates/bundles/SyliusAdminBundle/_styles.html.twig
|
||||
{{ encore_entry_link_tags('admin-entry', null, 'admin') }}
|
||||
|
||||
// templates/bundles/SyliusAdminBundle/_logo.html.twig
|
||||
// templates/bundles/SyliusAdminBundle/Layout/_logo.html.twig
|
||||
<a class="item" href="{{ path('sylius_admin_dashboard') }}" style="padding: 13px 0;">
|
||||
<div style="max-width: 90px; margin: 0 auto;">
|
||||
<img src="{{ asset('build/admin/images/admin-logo.svg', 'admin') }}" class="ui fluid image">
|
||||
</div>
|
||||
</a>
|
||||
// templates/bundles/SyliusAdminBundle/Security/_content.html.twig
|
||||
{% include '@SyliusUi/Security/_login.html.twig'
|
||||
with {
|
||||
'action': path('sylius_admin_login_check'),
|
||||
'paths': {'logo': asset('build/admin/images/logo.png', 'admin')}
|
||||
}
|
||||
%}
|
||||
|
||||
// templates/bundles/SyliusShopBundle/_scripts.html.twig
|
||||
{{ encore_entry_script_tags('shop-entry', null, 'shop') }}
|
||||
|
|
@ -54,14 +61,13 @@ This is a simple guide on how to start using webpack in Sylius apps. Webpack fin
|
|||
// templates/bundles/SyliusShopBundle/_styles.html.twig
|
||||
{{ encore_entry_link_tags('shop-entry', null, 'shop') }}
|
||||
|
||||
// templates/bundles/SyliusShopBundle/Layout/Header/_header.html.twig
|
||||
// templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig
|
||||
<div class="column">
|
||||
<a href="{{ path('sylius_shop_homepage') }}">
|
||||
<img src="{{ asset('assets/shop/img/logo.png') }}" alt="Sylius logo" class="ui small image" />
|
||||
<img src="{{ asset('build/shop/images/logo.png', 'shop') }}" alt="Sylius logo" class="ui small image" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
The paths should be changed for each asset you use.
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Entities
|
|||
:hidden:
|
||||
|
||||
entities/custom-model
|
||||
entities/custom-model-accessible-for-channel-admin
|
||||
entities/custom-translatable-model
|
||||
|
||||
.. include:: /cookbook/entities/map.rst.inc
|
||||
|
|
@ -52,6 +53,12 @@ Payments
|
|||
payments/encrypting-gateway-config
|
||||
payments/authorize
|
||||
payments/custom-payment-gateway
|
||||
payments/customizing-credit-memo
|
||||
payments/refund-process
|
||||
payments/custom-field-on-refund-payment
|
||||
payments/custom-type-of-refund
|
||||
payments/custom-invoice
|
||||
payments/generating-invoice-after-payment
|
||||
|
||||
.. include:: /cookbook/payments/map.rst.inc
|
||||
|
||||
|
|
@ -133,6 +140,7 @@ Configuration
|
|||
configuration/disabling-shop-admin-api
|
||||
configuration/installation-commands
|
||||
configuration/disabling-admin-notifications
|
||||
configuration/admin-prefix
|
||||
|
||||
.. include:: /cookbook/configuration/map.rst.inc
|
||||
|
||||
|
|
@ -147,3 +155,13 @@ Frontend
|
|||
frontend/webpack.rst
|
||||
|
||||
.. include:: /cookbook/frontend/map.rst.inc
|
||||
|
||||
Taxation
|
||||
--------
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
taxation/customize-tax-by-address
|
||||
|
||||
.. include:: /cookbook/taxation/map.rst.inc
|
||||
|
|
|
|||
526
docs/cookbook/payments/custom-field-on-refund-payment.rst
Normal file
526
docs/cookbook/payments/custom-field-on-refund-payment.rst
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
How to customize the refund form?
|
||||
=================================
|
||||
|
||||
.. note::
|
||||
|
||||
This cookbook describes customization of a feature available only with `Sylius/RefundPlugin <https://github.com/Sylius/RefundPlugin/>`_ installed.
|
||||
|
||||
A refund form is the form in which, as an Administrator, you can specify the exact amounts of money that will be refunded to a Customer.
|
||||
|
||||
Why would you customize the refund form?
|
||||
----------------------------------------
|
||||
|
||||
Refund Plugin provides a generic solution for refunding orders, it is enough for a basic refund but many shops need more custom functionalities.
|
||||
For example, one may need to add refund payments scheduling, as they may be paid once a month.
|
||||
|
||||
How to add a field to the refund form?
|
||||
--------------------------------------
|
||||
|
||||
The refund form is a form used to create the Refund Payment, thus in order to add a field to this form,
|
||||
you need to first add it to the Refund Payment's model.
|
||||
|
||||
Refunds are processed with such a flow: ``command -> handler -> event -> listener``, and this flow we will also need to customize in order to process the data from the new field.
|
||||
|
||||
In this customization, we will be extending the refund form with a ``scheduledAt`` field,
|
||||
which might be used then for scheduling the payments in the payment gateway.
|
||||
|
||||
**1. Add the custom field to the Refund Payment:**
|
||||
|
||||
Extended refund payment should look like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Refund;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Sylius\RefundPlugin\Entity\RefundPayment as BaseRefundPayment;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="sylius_refund_refund_payment")
|
||||
*/
|
||||
class RefundPayment extends BaseRefundPayment implements RefundPaymentInterface
|
||||
{
|
||||
/**
|
||||
* @var \DateTimeInterface|null
|
||||
*
|
||||
* @ORM\Column(type="datetime", nullable="true", name="scheduled_at")
|
||||
*/
|
||||
protected $scheduledAt;
|
||||
|
||||
public function getScheduledAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->scheduledAt;
|
||||
}
|
||||
|
||||
public function setScheduledAt(\DateTimeInterface $scheduledAt): void
|
||||
{
|
||||
$this->scheduledAt = $scheduledAt;
|
||||
}
|
||||
}
|
||||
|
||||
It should implement a new interface:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Refund;
|
||||
|
||||
use Sylius\RefundPlugin\Entity\RefundPaymentInterface as BaseRefundPaymentInterface;
|
||||
|
||||
interface RefundPaymentInterface extends BaseRefundPaymentInterface
|
||||
{
|
||||
public function getScheduledAt(): ?\DateTimeInterface;
|
||||
|
||||
public function setScheduledAt(\DateTimeInterface $date): void;
|
||||
}
|
||||
|
||||
Remember to update resource configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/sylius_refund.yaml
|
||||
sylius_resource:
|
||||
resources:
|
||||
sylius_refund.refund_payment:
|
||||
classes:
|
||||
model: App\Entity\Refund\RefundPayment
|
||||
interface: App\Entity\Refund\RefundPaymentInterface
|
||||
|
||||
And update the database:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php bin/console doctrine:migrations:diff
|
||||
php bin/console doctrine:migrations:migrate
|
||||
|
||||
**2. Modify the refund form:**
|
||||
|
||||
Once we have the new field on the Refund Payment, we will need to display its input on the refund form.
|
||||
We need to overwrite the template ``orderRefunds.html.twig`` from Refund Plugin.
|
||||
To achieve that copy the entire ``orderRefunds.html.twig`` to ``templates/bundles/SyliusRefundPlugin/orderRefunds.html.twig``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir templates/bundles/SyliusRefundPlugin
|
||||
cp vendor/sylius/refund-plugin/src/Resources/views/orderRefunds.html.twig templates/bundles/SyliusRefundPlugin
|
||||
|
||||
Then add:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
<div class="field">
|
||||
<label for="scheduled-at">Scheduled at</label>
|
||||
<input type="date" name="sylius_scheduled_at" id="scheduled-at" />
|
||||
</div>
|
||||
|
||||
**3. Adjust the ``RefundUnits`` command:**
|
||||
|
||||
We want the refund payments to be created with our extra ``scheduledAt`` date, therefore we need to provide this data in command,
|
||||
We will extend the ``RefundUnits`` command from Refund Plugin and add the new value:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Sylius\RefundPlugin\Command\RefundUnits as BaseRefundUnits;
|
||||
|
||||
final class RefundUnits extends BaseRefundUnits
|
||||
{
|
||||
/** @var \DateTimeInterface|null */
|
||||
private $scheduledAt;
|
||||
|
||||
public function __construct(
|
||||
string $orderNumber,
|
||||
array $units,
|
||||
array $shipments,
|
||||
int $paymentMethodId,
|
||||
string $comment,
|
||||
?\DateTimeInterface $scheduledAt
|
||||
) {
|
||||
parent::__construct($orderNumber, $units, $shipments, $paymentMethodId, $comment);
|
||||
|
||||
$this->scheduledAt = $scheduledAt;
|
||||
}
|
||||
|
||||
public function getScheduledAt(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->scheduledAt;
|
||||
}
|
||||
|
||||
public function setScheduledAt(?\DateTimeInterface $scheduledAt): void
|
||||
{
|
||||
$this->scheduledAt = $scheduledAt;
|
||||
}
|
||||
}
|
||||
|
||||
**4. Update the ``RefundUnitsCommandCreator``:**
|
||||
|
||||
The controller related to the refund form dispatches the ``RefundUnits`` command, and there is a service that creates a command from request,
|
||||
so we need to overwrite the ``Sylius\RefundPlugin\Creator\RefundUnitsCommandCreator``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Creator;
|
||||
|
||||
use App\Command\RefundUnits;
|
||||
use Sylius\RefundPlugin\Command\RefundUnits as BaseRefundUnits;
|
||||
use Sylius\RefundPlugin\Converter\RefundUnitsConverterInterface;
|
||||
use Sylius\RefundPlugin\Creator\RefundUnitsCommandCreatorInterface;
|
||||
use Sylius\RefundPlugin\Exception\InvalidRefundAmount;
|
||||
use Sylius\RefundPlugin\Model\OrderItemUnitRefund;
|
||||
use Sylius\RefundPlugin\Model\RefundType;
|
||||
use Sylius\RefundPlugin\Model\ShipmentRefund;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class RefundUnitsCommandCreator implements RefundUnitsCommandCreatorInterface
|
||||
{
|
||||
/** @var RefundUnitsConverterInterface */
|
||||
private $refundUnitsConverter;
|
||||
|
||||
public function __construct(RefundUnitsConverterInterface $refundUnitsConverter)
|
||||
{
|
||||
$this->refundUnitsConverter = $refundUnitsConverter;
|
||||
}
|
||||
|
||||
public function fromRequest(Request $request): BaseRefundUnits
|
||||
{
|
||||
Assert::true($request->attributes->has('orderNumber'), 'Refunded order number not provided');
|
||||
|
||||
$units = $this->refundUnitsConverter->convert(
|
||||
$request->request->has('sylius_refund_units') ? $request->request->all()['sylius_refund_units'] : [],
|
||||
RefundType::orderItemUnit(),
|
||||
OrderItemUnitRefund::class
|
||||
);
|
||||
|
||||
$shipments = $this->refundUnitsConverter->convert(
|
||||
$request->request->has('sylius_refund_shipments') ? $request->request->all()['sylius_refund_shipments'] : [],
|
||||
RefundType::shipment(),
|
||||
ShipmentRefund::class
|
||||
);
|
||||
|
||||
if (count($units) === 0 && count($shipments) === 0) {
|
||||
throw InvalidRefundAmount::withValidationConstraint('sylius_refund.at_least_one_unit_should_be_selected_to_refund');
|
||||
}
|
||||
|
||||
/** @var string $comment */
|
||||
$comment = $request->request->get('sylius_refund_comment', '');
|
||||
|
||||
// here we need to return the new RefundUnits command, with new data
|
||||
return new RefundUnits(
|
||||
$request->attributes->get('orderNumber'),
|
||||
$units,
|
||||
$shipments,
|
||||
(int) $request->request->get('sylius_refund_payment_method'),
|
||||
$comment,
|
||||
new \DateTime($request->request->get('sylius_scheduled_at'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
And register the new service:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
Sylius\RefundPlugin\Creator\RefundUnitsCommandCreatorInterface:
|
||||
class: App\Creator\RefundUnitsCommandCreator
|
||||
arguments:
|
||||
- '@Sylius\RefundPlugin\Converter\RefundUnitsConverterInterface'
|
||||
|
||||
**5. Modify the ``RefundUnitsHandler``:**
|
||||
|
||||
Now, when we have a new command, we also need to overwrite the related command handler:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\CommandHandler;
|
||||
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
|
||||
use App\Command\RefundUnits;
|
||||
use App\Event\UnitsRefunded;
|
||||
use Sylius\RefundPlugin\Refunder\RefunderInterface;
|
||||
use Sylius\RefundPlugin\Validator\RefundUnitsCommandValidatorInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class RefundUnitsHandler
|
||||
{
|
||||
/** @var RefunderInterface */
|
||||
private $orderUnitsRefunder;
|
||||
|
||||
/** @var RefunderInterface */
|
||||
private $orderShipmentsRefunder;
|
||||
|
||||
/** @var MessageBusInterface */
|
||||
private $eventBus;
|
||||
|
||||
/** @var OrderRepositoryInterface */
|
||||
private $orderRepository;
|
||||
|
||||
/** @var RefundUnitsCommandValidatorInterface */
|
||||
private $refundUnitsCommandValidator;
|
||||
|
||||
public function __construct(
|
||||
RefunderInterface $orderUnitsRefunder,
|
||||
RefunderInterface $orderShipmentsRefunder,
|
||||
MessageBusInterface $eventBus,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
RefundUnitsCommandValidatorInterface $refundUnitsCommandValidator
|
||||
) {
|
||||
$this->orderUnitsRefunder = $orderUnitsRefunder;
|
||||
$this->orderShipmentsRefunder = $orderShipmentsRefunder;
|
||||
$this->eventBus = $eventBus;
|
||||
$this->orderRepository = $orderRepository;
|
||||
$this->refundUnitsCommandValidator = $refundUnitsCommandValidator;
|
||||
}
|
||||
|
||||
public function __invoke(RefundUnits $command): void
|
||||
{
|
||||
$this->refundUnitsCommandValidator->validate($command);
|
||||
|
||||
$orderNumber = $command->orderNumber();
|
||||
|
||||
/** @var OrderInterface $order */
|
||||
$order = $this->orderRepository->findOneByNumber($orderNumber);
|
||||
|
||||
$refundedTotal = 0;
|
||||
$refundedTotal += $this->orderUnitsRefunder->refundFromOrder($command->units(), $orderNumber);
|
||||
$refundedTotal += $this->orderShipmentsRefunder->refundFromOrder($command->shipments(), $orderNumber);
|
||||
|
||||
/** @var string|null $currencyCode */
|
||||
$currencyCode = $order->getCurrencyCode();
|
||||
Assert::notNull($currencyCode);
|
||||
|
||||
$this->eventBus->dispatch(new UnitsRefunded(
|
||||
$orderNumber,
|
||||
$command->units(),
|
||||
$command->shipments(),
|
||||
$command->paymentMethodId(),
|
||||
$refundedTotal,
|
||||
$currencyCode,
|
||||
$command->comment(),
|
||||
$command->getScheduledAt()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
And register it:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
Sylius\RefundPlugin\CommandHandler\RefundUnitsHandler:
|
||||
class: App\CommandHandler\RefundUnitsHandler
|
||||
arguments:
|
||||
- '@Sylius\RefundPlugin\Refunder\OrderItemUnitsRefunder'
|
||||
- '@Sylius\RefundPlugin\Refunder\OrderShipmentsRefunder'
|
||||
- '@sylius.event_bus'
|
||||
- '@sylius.repository.order'
|
||||
- '@Sylius\RefundPlugin\Validator\RefundUnitsCommandValidatorInterface'
|
||||
tags:
|
||||
- { name: messenger.message_handler, bus: sylius.command_bus }
|
||||
|
||||
**6. Modify the ``UnitsReturned`` event:**
|
||||
|
||||
In previous command handler we are dispatching a new event so now we need to create this event and related event handler:
|
||||
|
||||
event:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Event;
|
||||
|
||||
use Sylius\RefundPlugin\Event\UnitsRefunded as BaseUnitsRefunded;
|
||||
|
||||
final class UnitsRefunded extends BaseUnitsRefunded
|
||||
{
|
||||
/** @var \DateTimeInterface */
|
||||
protected $scheduledAt;
|
||||
|
||||
public function __construct(
|
||||
string $orderNumber,
|
||||
array $units,
|
||||
array $shipments,
|
||||
int $paymentMethodId,
|
||||
int $amount,
|
||||
string $currencyCode,
|
||||
string $comment,
|
||||
\DateTime $scheduledAt
|
||||
) {
|
||||
parent::__construct($orderNumber, $units, $shipments, $paymentMethodId, $amount, $currencyCode, $comment);
|
||||
|
||||
$this->scheduledAt = $scheduledAt;
|
||||
}
|
||||
|
||||
public function getScheduledAt(): \DateTimeInterface
|
||||
{
|
||||
return $this->scheduledAt;
|
||||
}
|
||||
}
|
||||
|
||||
And process manager to handle the new event:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\ProcessManager;
|
||||
|
||||
use App\Entity\Refund\RefundPaymentInterface as AppRefundPaymentInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\PaymentMethodInterface;
|
||||
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
|
||||
use Sylius\Component\Core\Repository\PaymentMethodRepositoryInterface;
|
||||
use Sylius\RefundPlugin\Entity\RefundPaymentInterface;
|
||||
use Sylius\RefundPlugin\Event\RefundPaymentGenerated;
|
||||
use Sylius\RefundPlugin\Event\UnitsRefunded;
|
||||
use Sylius\RefundPlugin\Factory\RefundPaymentFactoryInterface;
|
||||
use Sylius\RefundPlugin\ProcessManager\UnitsRefundedProcessStepInterface;
|
||||
use Sylius\RefundPlugin\Provider\RelatedPaymentIdProviderInterface;
|
||||
use Sylius\RefundPlugin\StateResolver\OrderFullyRefundedStateResolverInterface;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class RefundPaymentProcessManager implements UnitsRefundedProcessStepInterface
|
||||
{
|
||||
/** @var OrderFullyRefundedStateResolverInterface */
|
||||
private $orderFullyRefundedStateResolver;
|
||||
|
||||
/** @var RelatedPaymentIdProviderInterface */
|
||||
private $relatedPaymentIdProvider;
|
||||
|
||||
/** @var RefundPaymentFactoryInterface */
|
||||
private $refundPaymentFactory;
|
||||
|
||||
/** @var OrderRepositoryInterface */
|
||||
private $orderRepository;
|
||||
|
||||
/** @var PaymentMethodRepositoryInterface */
|
||||
private $paymentMethodRepository;
|
||||
|
||||
/** @var EntityManagerInterface */
|
||||
private $entityManager;
|
||||
|
||||
/** @var MessageBusInterface */
|
||||
private $eventBus;
|
||||
|
||||
public function __construct(
|
||||
OrderFullyRefundedStateResolverInterface $orderFullyRefundedStateResolver,
|
||||
RelatedPaymentIdProviderInterface $relatedPaymentIdProvider,
|
||||
RefundPaymentFactoryInterface $refundPaymentFactory,
|
||||
OrderRepositoryInterface $orderRepository,
|
||||
PaymentMethodRepositoryInterface $paymentMethodRepository,
|
||||
EntityManagerInterface $entityManager,
|
||||
MessageBusInterface $eventBus
|
||||
) {
|
||||
$this->orderFullyRefundedStateResolver = $orderFullyRefundedStateResolver;
|
||||
$this->relatedPaymentIdProvider = $relatedPaymentIdProvider;
|
||||
$this->refundPaymentFactory = $refundPaymentFactory;
|
||||
$this->orderRepository = $orderRepository;
|
||||
$this->paymentMethodRepository = $paymentMethodRepository;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->eventBus = $eventBus;
|
||||
}
|
||||
|
||||
public function next(UnitsRefunded $unitsRefunded): void
|
||||
{
|
||||
/** @var OrderInterface|null $order */
|
||||
$order = $this->orderRepository->findOneByNumber($unitsRefunded->orderNumber());
|
||||
Assert::notNull($order);
|
||||
|
||||
/** @var PaymentMethodInterface|null $paymentMethod */
|
||||
$paymentMethod = $this->paymentMethodRepository->find($unitsRefunded->paymentMethodId());
|
||||
Assert::notNull($paymentMethod);
|
||||
|
||||
/** @var AppRefundPaymentInterface $refundPayment */
|
||||
$refundPayment = $this->refundPaymentFactory->createWithData(
|
||||
$order,
|
||||
$unitsRefunded->amount(),
|
||||
$unitsRefunded->currencyCode(),
|
||||
RefundPaymentInterface::STATE_NEW,
|
||||
$paymentMethod
|
||||
);
|
||||
$refundPayment->setScheduledAt($unitsRefunded->getScheduledAt());
|
||||
|
||||
$this->entityManager->persist($refundPayment);
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->eventBus->dispatch(new RefundPaymentGenerated(
|
||||
$refundPayment->getId(),
|
||||
$unitsRefunded->orderNumber(),
|
||||
$unitsRefunded->amount(),
|
||||
$unitsRefunded->currencyCode(),
|
||||
$unitsRefunded->paymentMethodId(),
|
||||
$this->relatedPaymentIdProvider->getForRefundPayment($refundPayment)
|
||||
));
|
||||
|
||||
$this->orderFullyRefundedStateResolver->resolve($unitsRefunded->orderNumber());
|
||||
}
|
||||
}
|
||||
|
||||
And register it:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
Sylius\RefundPlugin\ProcessManager\RefundPaymentProcessManager:
|
||||
class: App\ProcessManager\RefundPaymentProcessManager
|
||||
arguments:
|
||||
- '@Sylius\RefundPlugin\StateResolver\OrderFullyRefundedStateResolverInterface'
|
||||
- '@Sylius\RefundPlugin\Provider\RelatedPaymentIdProviderInterface'
|
||||
- '@sylius_refund.factory.refund_payment'
|
||||
- '@sylius.repository.order'
|
||||
- '@sylius.repository.payment_method'
|
||||
- '@doctrine.orm.default_entity_manager'
|
||||
- '@sylius.event_bus'
|
||||
tags:
|
||||
- {name: sylius_refund.units_refunded.process_step, priority: 50}
|
||||
|
||||
**7. Display the new field on the refund payment:**
|
||||
|
||||
And as the last step, we need to overwrite the template ``_refundPayments.html.twig`` from Refund Plugin.
|
||||
Copy the entire ``_refundPayments.html.twig`` to ``templates/bundles/SyliusRefundPlugin/Order/Admin/_refundPayments.html.twig``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir -p templates/bundles/SyliusRefundPlugin/Order/Admin
|
||||
cp vendor/sylius/refund-plugin/src/Resources/views/Order/Admin/_refundPayments.html.twig templates/bundles/SyliusRefundPlugin/Order/Admin/
|
||||
|
||||
And replace ``header`` with:
|
||||
|
||||
.. code-block:: twig
|
||||
|
||||
<div class="header">
|
||||
{{ refund_payment.paymentMethod }} {% if refund_payment.scheduledAt is not null %} (Payment should be made in {{ refund_payment.scheduledAt|date('Y-M-d') }}) {% endif %}
|
||||
</div>
|
||||
|
||||
And that's it, we have a new field on Refund Payment with a "scheduled at" date (when admin/payment gateway
|
||||
should make the payment), in your application, you probably will add crone to automatize it.
|
||||
205
docs/cookbook/payments/custom-invoice.rst
Normal file
205
docs/cookbook/payments/custom-invoice.rst
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
How to customize the order invoice?
|
||||
===================================
|
||||
|
||||
.. note::
|
||||
|
||||
This cookbook describes customization of a feature available only with `Sylius/InvoicingPlugin <https://github.com/Sylius/InvoicingPlugin/>`_ installed.
|
||||
|
||||
The invoicing plugin lets you generate invoice on admin panel and download PDF with it. This plugin also sends an email with this invoice
|
||||
as well as let the administrator to delegate an email resend.
|
||||
|
||||
Why would you customize the invoice?
|
||||
------------------------------------
|
||||
|
||||
Invoicing Plugin provides a generic solution for generating invoices for orders, it is enough for a basic invoicing functionality
|
||||
but many shops need this feature customized for its needs.
|
||||
For example, one may need to change the look of it, or add some more data.
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
Before you start make sure that you have:
|
||||
|
||||
#. `Sylius/InvoicingPlugin <https://github.com/Sylius/InvoicingPlugin/>`_ installed.
|
||||
#. `Wkhtmltopdf <https://wkhtmltopdf.org/>`_ package installed, because most of pdf generation is done with it.
|
||||
|
||||
How to customize the invoice appearance?
|
||||
----------------------------------------
|
||||
|
||||
There might be need to change how the invoices look like, f.e. shop is using its own logo, there might be some colours changed
|
||||
on the tables, or maybe the order of fields might be changed.
|
||||
|
||||
First let's prepare the HTML's so we can modify them. This command will copy only the PDF template:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir templates/bundles/SyliusInvoicingPlugin/Invoice/Download
|
||||
cp vendor/sylius/invoicing-plugin/src/Resources/views/Invoice/Download/pdf.html.twig templates/bundles/SyliusInvoicingPlugin/Download
|
||||
|
||||
But you can also copy all of the templates with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir templates/bundles/SyliusInvoicingPlugin
|
||||
cp -r vendor/sylius/invoicing-plugin/src/Resources/views/Invoice templates/bundles/SyliusInvoicingPlugin/
|
||||
|
||||
In directory ``templates/bundles/SyliusInvoicingPlugin/Invoice`` you can find now few files.
|
||||
|
||||
Let's modify the generated PDF. In this case we will modify the file from ``Download/pdf.html.twig``.
|
||||
This is how the default PDF looks like (don't worry this is not a real address of Myrna, or is it?):
|
||||
|
||||
.. image:: ../../_images/cookbook/custom-invoice/pdf_before.png
|
||||
|
||||
Now with some magic of HTML and CSS we can modify this template, as an example we can change the color of background to ``red`` by changing
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<!--...-->
|
||||
<div class="invoice-box" style="background-color: red">
|
||||
<!--...-->
|
||||
|
||||
and after this change we are graced with this masterpiece:
|
||||
|
||||
.. image:: ../../_images/cookbook/custom-invoice/pdf_after.png
|
||||
|
||||
.. warning::
|
||||
|
||||
Every PDF that you generate is stored and then extracted so it won't be created again. If you want to see the changes
|
||||
go to ``private/invoices`` and remove the generated PDF. You should see the changes of your file when you generate it again.
|
||||
|
||||
.. note::
|
||||
|
||||
You can also modify the view on administrator page by changing code inside ``show.html.twig`` and related templates
|
||||
|
||||
.. note::
|
||||
|
||||
You can learn more about customizing templates at :doc:`Customization Guide </customization/index>`
|
||||
|
||||
How to add additional fields to invoice?
|
||||
----------------------------------------
|
||||
|
||||
Let's say that you need (or not) some more fields. In this example we will add the customer phone number.
|
||||
Because we are basing upon the existing field, there should be no problem adding it to document - just place a line into
|
||||
``Download/pdf.html.twig`` file. The ``Phone Number`` field is quite nested so you need to add ``invoice.order.customer.phoneNumber``
|
||||
to retrieve it:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<!--...-->
|
||||
{{ invoice.billingData.city }}<br/>
|
||||
{{ invoice.order.customer.phoneNumber }}<br/>
|
||||
{{ invoice.billingData.countryCode}}
|
||||
<!--...-->
|
||||
|
||||
And as a result we can see that phone number has been added just after the city:
|
||||
|
||||
.. image:: ../../_images/cookbook/custom-invoice/pdf_phone.png
|
||||
|
||||
.. note::
|
||||
|
||||
You can also create some validation (for example if customer has no phone number) so the field won't be shown.
|
||||
If you want to learn more about twig - visit `twig <https://twig.symfony.com/>`_.
|
||||
|
||||
How to change the appearance of invoice tables?
|
||||
-----------------------------------------------
|
||||
|
||||
By default on lower right corner of invoice we are displaying ``total`` of ordered items and shipment.
|
||||
Lets create now a new row where we will show ``Products total`` where only price for products will be shown.
|
||||
|
||||
First let's add the new table row between other ``totals`` in ``pdf.html.twig``
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<!--...-->
|
||||
<tr class="totals">
|
||||
<!--tr body-->
|
||||
</tr>
|
||||
|
||||
<tr class="totals">
|
||||
<td colspan="5"></td>
|
||||
<td colspan="2" >{{ 'sylius_invoicing_plugin.ui.products_total'|trans([], 'messages', invoice.localeCode) }}:</td>
|
||||
<td>{{ '%0.2f'|format(invoice.order.itemsTotal/100) }}</td>
|
||||
<td>{{ invoice.currencyCode }}</td>
|
||||
</tr>
|
||||
|
||||
<tr class="totals bold">
|
||||
<!--...-->
|
||||
|
||||
And now add the translation by creating file ``translations/messages.en.yaml`` and adding:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_invoicing_plugin:
|
||||
ui:
|
||||
products_total: 'Products total'
|
||||
|
||||
after this changes your PDF's total table should look like this:
|
||||
|
||||
.. image:: ../../_images/cookbook/custom-invoice/pdf_total.png
|
||||
|
||||
How to extend Invoice with custom logic?
|
||||
----------------------------------------
|
||||
|
||||
With default behavior and some simple customization it should be quite simple to achieve the Invoice you are looking for.
|
||||
But life is not so straightforward as we all would like, and you are in need to create some custom logic for your needs.
|
||||
Scary process isn't it? Well not exactly, let's create some custom logic for your invoice in this step.
|
||||
|
||||
First we need a class with our logic that will extend current Invoice:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Invoice;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Sylius\InvoicingPlugin\Entity\Invoice as BaseInvoice;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="sylius_invoicing_plugin_invoice")
|
||||
*/
|
||||
class Invoice extends BaseInvoice implements InvoiceInterface
|
||||
{
|
||||
public function customFunction(): mixed
|
||||
{
|
||||
/** your custom logic */
|
||||
}
|
||||
}
|
||||
|
||||
And if there is a need you can also create an interface that will extend the base one:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Invoice;
|
||||
|
||||
use Sylius\InvoicingPlugin\Entity\InvoiceInterface as BaseInvoiceInterface;
|
||||
|
||||
interface InvoiceInterface extends BaseInvoiceInterface
|
||||
{
|
||||
public function customFunction(): mixed;
|
||||
}
|
||||
|
||||
Now let's add those classes to the configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/_sylius.yaml
|
||||
sylius_invoicing:
|
||||
resources:
|
||||
invoice:
|
||||
classes:
|
||||
model: App\Entity\Invoice\Invoice
|
||||
interface: App\Entity\Invoice\InvoiceInterface
|
||||
|
||||
.. note::
|
||||
|
||||
Don't forget to update your database if you are changing/adding fields.
|
||||
|
||||
Now you can show a new invoice table on PDF with some changes just like in chapters before.
|
||||
|
|
@ -41,7 +41,7 @@ In the following example, a new gateway will be configured, which will send paym
|
|||
}
|
||||
}
|
||||
|
||||
And at the end of ``src/Resources/config/services.xml`` add such a configuration for your gateway:
|
||||
And at the end of ``src/Resources/config/services.xml`` or ``src/Resources/config/services.yaml`` add such a configuration for your gateway:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
|
|
@ -52,6 +52,17 @@ In the following example, a new gateway will be configured, which will send paym
|
|||
<tag name="payum.gateway_factory_builder" factory="sylius_payment" />
|
||||
</service>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# src/Resources/config/services.yaml
|
||||
|
||||
app.sylius_payment:
|
||||
class: Payum\Core\Bridge\Symfony\Builder\GatewayFactoryBuilder
|
||||
arguments: [ Acme\SyliusExamplePlugin\Payum\SyliusPaymentGatewayFactory ]
|
||||
tags:
|
||||
- { name: payum.gateway_factory_builder, factory: sylius_payment }
|
||||
|
||||
|
||||
**3.** Next, one should create a configuration form, where authorization
|
||||
(or some additional information, like sandbox mode) can be specified.
|
||||
|
||||
|
|
@ -79,7 +90,7 @@ In the following example, a new gateway will be configured, which will send paym
|
|||
}
|
||||
}
|
||||
|
||||
And add its configuration to `src/Resources/config/services.xml`:
|
||||
And add its configuration to `src/Resources/config/services.xml` or ``src/Resources/config/services.yaml``:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
|
|
@ -89,6 +100,15 @@ In the following example, a new gateway will be configured, which will send paym
|
|||
<tag name="sylius.gateway_configuration_type" type="sylius_payment" label="Sylius Payment" />
|
||||
<tag name="form.type" />
|
||||
</service>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# src/Resources/config/services.yaml
|
||||
|
||||
Acme\SyliusExamplePlugin\Form\Type\SyliusGatewayConfigurationType:
|
||||
tags:
|
||||
- { name: sylius.gateway_configuration_type, type: sylius_payment, label: 'Sylius Payment' }
|
||||
- { name: form.type }
|
||||
|
||||
**4.** To introduce support for new configuration fields, we need to create a value object which will be passed to action,
|
||||
so we can use an API Key provided in form.
|
||||
|
|
@ -347,7 +367,7 @@ so we can use an API Key provided in form.
|
|||
}
|
||||
}
|
||||
|
||||
And at the end of ``src/Resources/config/services.xml`` add such a configuration for your capture action:
|
||||
And at the end of ``src/Resources/config/services.xml`` or `src/Resources/config/services.yaml`` add such a configuration for your capture action:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
|
|
@ -357,6 +377,16 @@ so we can use an API Key provided in form.
|
|||
<argument type="service" id="sylius.http_client" />
|
||||
<tag name="payum.action" factory="sylius_payment" alias="payum.action.capture" />
|
||||
</service>
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# src/Resources/config/services.yaml
|
||||
|
||||
Acme\SyliusExamplePlugin\Payum\Action\CaptureAction:
|
||||
arguments:
|
||||
- '@sylius.http_client'
|
||||
tags:
|
||||
- { name: payum.action, factory: sylius_payment, alias: payum.action.capture }
|
||||
|
||||
Your shop is ready to handle the first checkout with your newly created gateway!
|
||||
|
||||
|
|
|
|||
108
docs/cookbook/payments/custom-type-of-refund.rst
Normal file
108
docs/cookbook/payments/custom-type-of-refund.rst
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
How to add another type of refund?
|
||||
==================================
|
||||
|
||||
.. note::
|
||||
|
||||
This cookbook describes customization of a feature available only with `Sylius/RefundPlugin <https://github.com/Sylius/RefundPlugin/>`_ installed.
|
||||
|
||||
Why would you add type of refund?
|
||||
---------------------------------
|
||||
|
||||
Refund Plugin provides a generic solution for refunding orders, it is enough for a basic refund but many shops need more custom functionalities.
|
||||
For example, one may need to add loyalty points as a different refund type than order item unit and shipment.
|
||||
|
||||
How to implement a new type of refund?
|
||||
--------------------------------------
|
||||
|
||||
In the current implementation, there are 2 basic types that are defined in RefundPlugin:
|
||||
|
||||
* order item unit
|
||||
* shipment
|
||||
|
||||
If you would like to add another one, e.g. ``loyalty``, which might be used then to refund the loyalty points.
|
||||
You need to first add it to the RefundType enum.
|
||||
|
||||
**1. Add the new type to the RefundType and RefundTypeInterface:**
|
||||
|
||||
Extended RefundTypeInterface should look like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model\Refund;
|
||||
|
||||
interface RefundTypeInterface
|
||||
{
|
||||
public const LOYALTY = 'loyalty';
|
||||
|
||||
public static function loyalty(): self;
|
||||
}
|
||||
|
||||
And extended RefundType should look like:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Model\Refund;
|
||||
|
||||
use Sylius\RefundPlugin\Model\RefundType as BaseRefundType;
|
||||
|
||||
final class RefundType extends BaseRefundType implements RefundTypeInterface
|
||||
{
|
||||
public static function loyalty(): self
|
||||
{
|
||||
return new self(self::LOYALTY);
|
||||
}
|
||||
}
|
||||
|
||||
You need also to set the parameter with new RefundType in your configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/sylius_refund.yaml
|
||||
parameters:
|
||||
sylius_refund.refund_type: App\Model\Refund\RefundType
|
||||
|
||||
**2. Overwrite RefundEnumType to use your extended RefundType:**
|
||||
|
||||
Extended RefundEnumType should look like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Refund\Type;
|
||||
|
||||
use App\Model\Refund\RefundType;
|
||||
use Sylius\RefundPlugin\Entity\Type\RefundEnumType as BaseRefundEnumType;
|
||||
use Sylius\RefundPlugin\Model\RefundTypeInterface;
|
||||
|
||||
final class RefundEnumType extends BaseRefundEnumType
|
||||
{
|
||||
protected function createType($value): RefundTypeInterface
|
||||
{
|
||||
return new RefundType($value);
|
||||
}
|
||||
}
|
||||
|
||||
And set the parameter with new RefundEnumType in your configuration file:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/sylius_refund.yaml
|
||||
parameters:
|
||||
sylius_refund.refund_enum_type: App\Entity\Refund\Type\RefundEnumType
|
||||
|
||||
**3. Modify the refund flow:**
|
||||
|
||||
Once we have the new type of refund added, we will need to use it and display its input on the refund form.
|
||||
You can achieve this by using :doc:`Cookbook - How to customize the refund form? </cookbook/payments/custom-field-on-refund-payment>`
|
||||
and add in handler your custom logic for refunding e.g. loyalty points.
|
||||
260
docs/cookbook/payments/customizing-credit-memo.rst
Normal file
260
docs/cookbook/payments/customizing-credit-memo.rst
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
How to customize a Credit Memo?
|
||||
===============================
|
||||
|
||||
Customizing a downloadable credit memo is a really common task, which leverages the extendability of traditional Symfony applications.
|
||||
This cookbook includes four exemplary customizations with a varying degree of difficulty and impact.
|
||||
|
||||
Customizing Credit Memo's template
|
||||
----------------------------------
|
||||
|
||||
The first exemplary customization is to change background color of the heading of line items table.
|
||||
|
||||
**1.** Copy ``vendor/sylius/refund-plugin/src/Resources/views/Download/creditMemo.html.twig`` into ``templates/bundles/SyliusRefundPlugin/Download/creditMemo.html.twig``.
|
||||
|
||||
**2.** Change CSS styling included in the template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<style>
|
||||
/* ... */
|
||||
.credit-memo table tr.heading td { background: #0d71bb; border-bottom: 1px solid #ddd; font-weight: bold; }
|
||||
/* ... */
|
||||
</style>
|
||||
|
||||
Displaying additional Customer's data on Credit Memo
|
||||
----------------------------------------------------
|
||||
|
||||
There might be some cases in which you want to get access to order or customer data.
|
||||
You can access these through ``creditMemo.order`` or ``creditMemo.order.customer`` respectively.
|
||||
|
||||
**1.** Copy ``vendor/sylius/refund-plugin/src/Resources/views/Download/creditMemo.html.twig`` into ``templates/bundles/SyliusRefundPlugin/Download/creditMemo.html.twig``.
|
||||
|
||||
**2.** Customize buyer's data included in the template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<td>
|
||||
{{ 'sylius_refund.ui.buyer'|trans([], 'messages', creditMemo.localeCode) }}<br/>
|
||||
<strong>{{ from.fullName }} </strong><br/>
|
||||
<!-- ... -->
|
||||
{{ creditMemo.order.customer.phoneNumber }}<br/>
|
||||
<!-- ... -->
|
||||
</td>
|
||||
|
||||
Displaying additional line item data (such as gross unit price) on Credit Memo
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
By default, a credit memo does not include unit gross price in the line items table - however, it is provided within
|
||||
line items data included with credit memo.
|
||||
|
||||
**1.** Copy ``vendor/sylius/refund-plugin/src/Resources/views/Download/creditMemo.html.twig`` into ``templates/bundles/SyliusRefundPlugin/Download/creditMemo.html.twig``.
|
||||
|
||||
**2.** Customize products table data by adding one column in the template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<tr class="heading">
|
||||
<!-- ... -->
|
||||
<td>{{ 'sylius_refund.ui.unit_net_price'|trans([], 'messages', creditMemo.localeCode) }}</td>
|
||||
<td>{{ 'app.ui.unit_gross_price'|trans([], 'messages', creditMemo.localeCode) }}</td>
|
||||
<td>{{ 'sylius_refund.ui.net_value'|trans([], 'messages', creditMemo.localeCode) }}</td>
|
||||
<!-- ... -->
|
||||
</tr>
|
||||
|
||||
{% for item in creditMemo.lineItems %}
|
||||
<tr class="item">
|
||||
<!-- ... -->
|
||||
<td>{{ '%0.2f'|format(item.unitNetPrice/100) }}</td>
|
||||
<td>{{ '%0.2f'|format(item.unitGrossPrice/100) }}</td>
|
||||
<td>{{ '%0.2f'|format(item.netValue/100) }}</td>
|
||||
<!-- ... -->
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
**3.** Add missing translations for newly added string in ``translations/messages.en.yml``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
app:
|
||||
ui:
|
||||
unit_gross_price: Unit gross price
|
||||
|
||||
Displaying additional elements on Credit Memo
|
||||
---------------------------------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
This section applies only for RefundPlugin in version v1.0.0-RC.10 or above.
|
||||
|
||||
There might be a case when you want to extend the credit memo with additional field.
|
||||
|
||||
**1.** Copy ``vendor/sylius/refund-plugin/src/Resources/views/Download/creditMemo.html.twig`` into ``templates/bundles/SyliusRefundPlugin/Download/creditMemo.html.twig``.
|
||||
|
||||
**2.** Customize credit memo template to include the reason:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<div class="credit-memo">
|
||||
Reason: {{ creditMemo.reason }}
|
||||
|
||||
<!-- ... -->
|
||||
</div>
|
||||
|
||||
**3.** Override the default credit memo model in ``src/Entity/Refund/CreditMemo.php``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Refund;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Sylius\RefundPlugin\Entity\CreditMemo as BaseCreditMemo;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="sylius_refund_credit_memo")
|
||||
*/
|
||||
class CreditMemo extends BaseCreditMemo
|
||||
{
|
||||
/**
|
||||
* @ORM\Column
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $reason;
|
||||
|
||||
public function getReason(): ?string
|
||||
{
|
||||
return $this->reason;
|
||||
}
|
||||
|
||||
public function setReason(?string $reason): void
|
||||
{
|
||||
$this->reason = $reason;
|
||||
}
|
||||
}
|
||||
|
||||
**4.** Configure ResourceBundle to use overridden model in ``config/packages/sylius_refund.yaml``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
sylius_resource:
|
||||
resources:
|
||||
sylius_refund.credit_memo:
|
||||
classes:
|
||||
model: App\Entity\Refund\CreditMemo
|
||||
|
||||
**5.** Assuming that your database was up-to-date before these changes, create a proper migration and use it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php bin/console doctrine:migrations:diff
|
||||
php bin/console doctrine:migrations:migrate
|
||||
|
||||
**6.** Decorate credit memo generator to set the reason while generating the invoice. Create a class in ``src/Refund/CreditMemoGenerator.php``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Refund;
|
||||
|
||||
use App\Entity\Refund\CreditMemo;
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\RefundPlugin\Entity\CreditMemoInterface;
|
||||
use Sylius\RefundPlugin\Generator\CreditMemoGeneratorInterface;
|
||||
|
||||
final class CreditMemoGenerator implements CreditMemoGeneratorInterface
|
||||
{
|
||||
/** @var CreditMemoGeneratorInterface */
|
||||
private $creditMemoGenerator;
|
||||
|
||||
public function __construct(CreditMemoGeneratorInterface $creditMemoGenerator)
|
||||
{
|
||||
$this->creditMemoGenerator = $creditMemoGenerator;
|
||||
}
|
||||
|
||||
public function generate(OrderInterface $order, int $total, array $units, array $shipments, string $comment): CreditMemoInterface
|
||||
{
|
||||
/** @var CreditMemo $creditMemo */
|
||||
$creditMemo = $this->creditMemoGenerator->generate($order, $total, $units, $shipments, $comment);
|
||||
$creditMemo->setReason('Charged too much');
|
||||
|
||||
return $creditMemo;
|
||||
}
|
||||
}
|
||||
|
||||
**7.** And then configure Symfony's dependency injection to use that class in ``config/services.yaml``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
services:
|
||||
# ...
|
||||
|
||||
App\Refund\CreditMemoGenerator:
|
||||
decorates: 'Sylius\RefundPlugin\Generator\CreditMemoGenerator'
|
||||
arguments:
|
||||
- '@App\Refund\CreditMemoGenerator.inner'
|
||||
|
||||
Displaying additional elements on Credit Memo by embedding a controller
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
There might be times when you want to calculate some extra data on-the-fly or get some which are not connected on
|
||||
entity level with credit memo.
|
||||
|
||||
**1.** Copy ``vendor/sylius/refund-plugin/src/Resources/views/Download/creditMemo.html.twig`` into ``templates/bundles/SyliusRefundPlugin/Download/creditMemo.html.twig``.
|
||||
|
||||
**2.** Embed a controller in the credit memo template:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<div class="credit-memo">
|
||||
Some unique data: {{ render(controller('App\\Controller\\FooController::extraData', { 'creditMemo': creditMemo })) }}
|
||||
|
||||
<!-- ... -->
|
||||
</div>
|
||||
|
||||
**3.** Create the referenced controller in a file called ``src/Controller/FooController.php``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Sylius\RefundPlugin\Entity\CreditMemoInterface;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Twig\Environment;
|
||||
|
||||
final class FooController
|
||||
{
|
||||
/** @var Environment */
|
||||
private $twig;
|
||||
|
||||
public function __construct(Environment $twig)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
public function extraData(CreditMemoInterface $creditMemo): Response
|
||||
{
|
||||
return new Response($this->twig->render('CreditMemo/extraData.html.twig', [
|
||||
'creditMemo' => $creditMemo,
|
||||
// Customise it to your needs, this one makes no sense
|
||||
'extraData' => $creditMemo->getNetValueTotal() * random_int(0, 42),
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
**4.** Created the template referenced in the controller in a file called ``templates/CreditMemo/extraData.html.twig``:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<strong>{{ extraData }}</strong>
|
||||
170
docs/cookbook/payments/generating-invoice-after-payment.rst
Normal file
170
docs/cookbook/payments/generating-invoice-after-payment.rst
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
How to have the Invoice generated after the payment is paid?
|
||||
============================================================
|
||||
|
||||
.. note::
|
||||
|
||||
This cookbook describes customization of a feature available only with `Sylius/InvoicingPlugin <https://github.com/Sylius/InvoicingPlugin/>`_ installed.
|
||||
|
||||
The invoicing plugin lets you generate and download PDF invoices regarding orders. In its default behavior the invoice
|
||||
is generated right after the customer creates and places the order.
|
||||
In this cookbook, we will describe how to change this behavior, so the invoice will be created right after the order would be paid.
|
||||
|
||||
Why would you customize the invoice generation?
|
||||
-----------------------------------------------
|
||||
|
||||
In the default case the order items should not be changed after completing order. But let's say that your shop is customized with some logic
|
||||
which is not out of the box. Maybe one of these changes will let you change the order after it is placed?
|
||||
In this case, it would be better to have an invoice generated after a particular step (in the case of this cookbook - after the order is paid).
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
Before you start, make sure that you have:
|
||||
|
||||
#. `Sylius/InvoicingPlugin <https://github.com/Sylius/InvoicingPlugin/>`_ installed.
|
||||
#. `Wkhtmltopdf <https://wkhtmltopdf.org/>`_ package installed, because most of pdf generation is done with it.
|
||||
|
||||
How to customize the invoice generation?
|
||||
----------------------------------------
|
||||
|
||||
The concept is quite straightforward and it is based on Symfony events and event listeners.
|
||||
We need to create 3 classes and declare them in config files.
|
||||
Let's start first with EventListeners that will override the default ones:
|
||||
|
||||
**1.** The ``OrderPaymentPaidListener`` will create an invoice and check if it does not exist:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\EventListener;
|
||||
|
||||
use Sylius\InvoicingPlugin\Command\SendInvoiceEmail;
|
||||
use Sylius\InvoicingPlugin\Creator\InvoiceCreatorInterface;
|
||||
use Sylius\InvoicingPlugin\Event\OrderPaymentPaid;
|
||||
use Sylius\InvoicingPlugin\Exception\InvoiceAlreadyGenerated;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
final class OrderPaymentPaidListener
|
||||
{
|
||||
/** @var InvoiceCreatorInterface */
|
||||
private $invoiceCreator;
|
||||
|
||||
/** @var MessageBusInterface */
|
||||
private $commandBus;
|
||||
|
||||
public function __construct(InvoiceCreatorInterface $invoiceCreator, MessageBusInterface $commandBus)
|
||||
{
|
||||
$this->invoiceCreator = $invoiceCreator;
|
||||
$this->commandBus = $commandBus;
|
||||
}
|
||||
|
||||
public function __invoke(OrderPaymentPaid $event): void
|
||||
{
|
||||
try {
|
||||
$this->invoiceCreator->__invoke($event->orderNumber(), $event->date());
|
||||
} catch (InvoiceAlreadyGenerated $exception) {
|
||||
}
|
||||
|
||||
$this->commandBus->dispatch(new SendInvoiceEmail($event->orderNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
**2.** The ``NoInvoiceOnOrderPlacedListener`` will not do anything (what a lazy boy), but as we are changing the behavior, it still has very important role:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\EventListener;
|
||||
|
||||
use Sylius\InvoicingPlugin\Event\OrderPlaced;
|
||||
|
||||
final class NoInvoiceOnOrderPlacedListener
|
||||
{
|
||||
public function __invoke(OrderPlaced $event): void
|
||||
{
|
||||
// intentionally left blank
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
**3.** Last but not least ``OrderPaymentPaidProducer`` which will dispatch an event at a correct moment:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Producer;
|
||||
|
||||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\PaymentInterface;
|
||||
use Sylius\InvoicingPlugin\DateTimeProvider;
|
||||
use Sylius\InvoicingPlugin\Event\OrderPaymentPaid;
|
||||
use Symfony\Component\Messenger\MessageBusInterface;
|
||||
|
||||
final class OrderPaymentPaidProducer
|
||||
{
|
||||
/** @var MessageBusInterface */
|
||||
private $eventBus;
|
||||
|
||||
/** @var DateTimeProvider */
|
||||
private $dateTimeProvider;
|
||||
|
||||
public function __construct(
|
||||
MessageBusInterface $eventBus,
|
||||
DateTimeProvider $dateTimeProvider
|
||||
) {
|
||||
$this->eventBus = $eventBus;
|
||||
$this->dateTimeProvider = $dateTimeProvider;
|
||||
}
|
||||
|
||||
public function __invoke(PaymentInterface $payment): void
|
||||
{
|
||||
/** @var OrderInterface|null $order */
|
||||
$order = $payment->getOrder();
|
||||
if ($order === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var string $number */
|
||||
$number = $order->getNumber();
|
||||
$this->eventBus->dispatch(new OrderPaymentPaid($number, $this->dateTimeProvider->__invoke()));
|
||||
}
|
||||
}
|
||||
|
||||
**4.** Last thing that we need to do is to register new services in a container:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
services:
|
||||
sylius_invoicing_plugin.listener.order_payment_paid:
|
||||
class: App\EventListener\OrderPaymentPaidListener
|
||||
arguments:
|
||||
- '@sylius_invoicing_plugin.creator.invoice'
|
||||
- '@sylius.command_bus'
|
||||
tags:
|
||||
- { name: messenger.message_handler }
|
||||
|
||||
sylius_invoicing_plugin.event_listener.order_placed:
|
||||
class: App\EventListener\NoInvoiceOnOrderPlacedListener
|
||||
tags:
|
||||
- { name: messenger.message_handler }
|
||||
|
||||
sylius_invoicing_plugin.event_producer.order_payment_paid:
|
||||
class: App\Producer\OrderPaymentPaidProducer
|
||||
arguments:
|
||||
- '@sylius.event_bus'
|
||||
- '@sylius_invoicing_plugin.date_time_provider'
|
||||
public: true
|
||||
|
||||
After these changes, the invoice will be generated after the order is paid, not just after it is placed.
|
||||
|
||||
.. image:: ../../_images/cookbook/generating-invoice-after-payment/before_payment.png
|
||||
|
|
@ -3,3 +3,9 @@
|
|||
* :doc:`/cookbook/payments/encrypting-gateway-config`
|
||||
* :doc:`/cookbook/payments/authorize`
|
||||
* :doc:`/cookbook/payments/custom-payment-gateway`
|
||||
* :doc:`/cookbook/payments/customizing-credit-memo`
|
||||
* :doc:`/cookbook/payments/refund-process`
|
||||
* :doc:`/cookbook/payments/custom-field-on-refund-payment`
|
||||
* :doc:`/cookbook/payments/custom-type-of-refund`
|
||||
* :doc:`/cookbook/payments/custom-invoice`
|
||||
* :doc:`/cookbook/payments/generating-invoice-after-payment`
|
||||
|
|
|
|||
64
docs/cookbook/payments/refund-process.rst
Normal file
64
docs/cookbook/payments/refund-process.rst
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
How to have the Credit Memos created after the Refund Payments?
|
||||
===============================================================
|
||||
|
||||
.. note::
|
||||
|
||||
This cookbook requires having the `Refund Plugin <https://github.com/Sylius/RefundPlugin>`_ installed in your application.
|
||||
|
||||
.. tip::
|
||||
|
||||
Read about the features of Refund Plugin in the documentation :doc:`here </book/orders/refunds>`.
|
||||
|
||||
|
||||
By default the refund payments are created right after the credit memos have been created.
|
||||
Although one may need to change it due to business requirements.
|
||||
|
||||
Let's see how to achieve this!
|
||||
|
||||
Credit Memos created after the Refund Payments
|
||||
----------------------------------------------
|
||||
|
||||
All you need to do is to override the priority in service declaration in the config file.
|
||||
Give the `CreditMemoProcessManager`, which is responsible for the Credit Memo generation, the lowest possible priority (``0``).
|
||||
The priorites of services are interpreted in the descending order, thus this change will make it run after the service responsible for
|
||||
Refund Payments.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
services:
|
||||
Sylius\RefundPlugin\ProcessManager\CreditMemoProcessManager:
|
||||
arguments: ['@sylius.command_bus']
|
||||
tags:
|
||||
- { name: sylius_refund.units_refunded.process_step, priority: 0 }
|
||||
|
||||
You can also achieve it the other way round, by giving the service responsible for Payments
|
||||
- ``RefundPaymentProcessManager`` - the highest priority, let it be ``200``.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/services.yaml
|
||||
services:
|
||||
Sylius\RefundPlugin\ProcessManager\RefundPaymentProcessManager:
|
||||
arguments:
|
||||
- '@Sylius\RefundPlugin\StateResolver\OrderFullyRefundedStateResolverInterface'
|
||||
- '@Sylius\RefundPlugin\Provider\RelatedPaymentIdProviderInterface'
|
||||
- '@Sylius\RefundPlugin\Factory\RefundPaymentFactoryInterface'
|
||||
- '@doctrine.orm.default_entity_manager'
|
||||
- '@sylius.event_bus'
|
||||
tags:
|
||||
- { name: sylius_refund.units_refunded.process_step, priority: 200 }
|
||||
|
||||
The process managers will work according to the new priorities (descending), and as a result, all Refund Payments will be created before their Credit Memos.
|
||||
|
||||
.. tip::
|
||||
|
||||
You can find the default config of all the services run in the the refund process in
|
||||
``%kernel.project_dir%/vendor/sylius/refund-plugin/src/Resources/config/services/event_bus.xml``
|
||||
tagged as ``sylius_refund.units_refunded.process_step``
|
||||
|
||||
|
||||
Learn more
|
||||
----------
|
||||
|
||||
* `The refund process - details <https://github.com/Sylius/RefundPlugin#post-refunding-process>`_
|
||||
|
|
@ -41,29 +41,7 @@ With:
|
|||
sylius_shop_payum:
|
||||
resource: "@SyliusShopBundle/Resources/config/routing/payum.yml"
|
||||
|
||||
**2.** Customise the security settings in the ``config/packages/security.yaml``.
|
||||
|
||||
Replace:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/security.yaml
|
||||
|
||||
parameters:
|
||||
# ...
|
||||
sylius.security.shop_regex: "^/(?!admin|api/.*|api$|media/.*)[^/]++"
|
||||
|
||||
With:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/security.yaml
|
||||
|
||||
parameters:
|
||||
# ...
|
||||
sylius.security.shop_regex: "^"
|
||||
|
||||
**3.** Customise SyliusShopBundle to use storage-based locale switching in the ``config/packages/_sylius.yaml``.
|
||||
**2.** Customise SyliusShopBundle to use storage-based locale switching in the ``config/packages/_sylius.yaml``.
|
||||
|
||||
Replace :
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Your extending repository class should look like that:
|
|||
{
|
||||
return $this->createQueryBuilder('o')
|
||||
->innerJoin('o.channels', 'channel')
|
||||
->andWhere('o.enabled = true')
|
||||
->andWhere('o.enabled = :enabled')
|
||||
->andWhere('channel = :channel')
|
||||
->innerJoin('o.productTaxons', 'productTaxons')
|
||||
->addOrderBy('productTaxons.position', 'asc')
|
||||
|
|
@ -43,6 +43,7 @@ Your extending repository class should look like that:
|
|||
->andWhere('taxon.code = :code')
|
||||
->setParameter('code', $code)
|
||||
->setParameter('channel', $channel)
|
||||
->setParameter('enabled', true)
|
||||
->setMaxResults($count)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ Set up the HWIOAuthBundle
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
composer require hwi/oauth-bundle
|
||||
composer require hwi/oauth-bundle php-http/httplug-bundle
|
||||
|
||||
`php-http/httplug-bundle` is optional, require this dependency if you don't want to provide your own services.
|
||||
For more information, please visit `Setting up HWIOAuthBundle <https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/1-setting_up_the_bundle.md#a-add-hwioauthbundle-to-your-project>`_.
|
||||
|
||||
* Enable the bundle:
|
||||
|
||||
|
|
@ -21,7 +24,8 @@ Set up the HWIOAuthBundle
|
|||
|
||||
return [
|
||||
// ...
|
||||
new HWI\Bundle\OAuthBundle\HWIOAuthBundle(),
|
||||
Http\HttplugBundle\HttplugBundle::class => ['all' => true], // If you require the php-http/httplug-bundle package.
|
||||
HWI\Bundle\OAuthBundle\HWIOAuthBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
* Import the routing:
|
||||
|
|
@ -76,6 +80,12 @@ Sylius uses email as the username, that's why we choose emails as ``scope`` for
|
|||
* Click ``+Add Platform`` and choose "Website" type.
|
||||
* Provide the **Site URL** of the platform - your local server on which you run Sylius: ``http://localhost:8000``
|
||||
|
||||
Alternatively, you could temporarily expose your localhost to be publicly accessible, using a tool like `ngrok <https://ngrok.com/>`_.
|
||||
Facebook app configuration would be similar to:
|
||||
|
||||
* **App Domain**: ``abcde12345.ngrok.io``
|
||||
* **Site URL** ``http://abcde12345.ngrok.io``
|
||||
|
||||
Configure the security layer
|
||||
----------------------------
|
||||
|
||||
|
|
|
|||
49
docs/cookbook/taxation/customize-tax-by-address.rst
Normal file
49
docs/cookbook/taxation/customize-tax-by-address.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
How to configure tax rates to be based on shipping address?
|
||||
===========================================================
|
||||
|
||||
The default configuration of Sylius tax calculation is based on billing address but there are situations where we would
|
||||
like to use a shipping address to be used in this process. This may be useful to anyone who uses Sylius in European Union
|
||||
as from 1st July 2021 the new taxation rules will be applied.
|
||||
|
||||
.. note::
|
||||
|
||||
You can learn more about new EU taxation rules `here <https://ec.europa.eu/taxation_customs/business/vat/modernising-vat-cross-border-ecommerce_en>`_.
|
||||
|
||||
To change the way how the taxes are calculated; by billing or by shipping address, you need to override the service called
|
||||
``OrderTaxesProcessor.php`` from ``Sylius/Component/Core/OrderProcessing``.
|
||||
|
||||
First let's copy code from original Processor to our service
|
||||
from ``%kernel.project_dir%/vendor/sylius/sylius/src/Sylius/Component/Core/OrderProcessing/OrderTaxesProcessor.php`` to ``src/OrderProcessing/OrderTaxesProcessor.php``
|
||||
|
||||
Then register our new service:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# app/config/services.yaml
|
||||
App\OrderProcessing\OrderTaxesProcessor:
|
||||
arguments:
|
||||
- '@sylius.provider.channel_based_default_zone_provider'
|
||||
- '@sylius.zone_matcher'
|
||||
- '@sylius.registry.tax_calculation_strategy'
|
||||
tags:
|
||||
- { name: sylius.order_processor, priority: 10 }
|
||||
|
||||
Now we need to change the method ``getTaxZone`` to be using the shipping address:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
//...
|
||||
private function getTaxZone(OrderInterface $order): ?ZoneInterface
|
||||
{
|
||||
$shippingAddress = $order->getShippingAddress();
|
||||
$zone = null;
|
||||
|
||||
if (null !== $shippingAddress) {
|
||||
$zone = $this->zoneMatcher->match($shippingAddress, Scope::TAX);
|
||||
}
|
||||
|
||||
return $zone ?: $this->defaultTaxZoneProvider->getZone($order);
|
||||
}
|
||||
//...
|
||||
|
||||
And with this change, the way how taxes are calculated will be based on shipping address.
|
||||
1
docs/cookbook/taxation/map.rst.inc
Normal file
1
docs/cookbook/taxation/map.rst.inc
Normal file
|
|
@ -0,0 +1 @@
|
|||
* :doc:`/cookbook/taxation/customize-tax-by-address`
|
||||
|
|
@ -228,6 +228,237 @@ After these two steps your admin product grid should not have the image field.
|
|||
|
||||
.. include:: /customization/plugins.rst.inc
|
||||
|
||||
Changes related to upgrade to GridBundle 1.10
|
||||
---------------------------------------------
|
||||
|
||||
Since the SyliusGridBundle v1.10, all grids has options `fetch_join_collection` and `use_output_walkers` enabled by default.
|
||||
According to our research it may fix a lot of pagination issues and improve big-database performance (1M+ rows) up to 70%,
|
||||
but with the price of more queries required to be performed. If this trade-off is not worth it for you,
|
||||
you may disable it by using the following configuration snippet:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
# config/packages/_sylius.yaml
|
||||
sylius_grid:
|
||||
grids:
|
||||
sylius_admin_address_log_entry:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_admin_user:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_channel:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_country:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_currency:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_customer:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_customer_group:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_customer_order:
|
||||
extends: sylius_admin_order
|
||||
driver:
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_exchange_rate:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_inventory:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_locale:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_order:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_payment:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_payment_method:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product_association_type:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product_attribute:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product_option:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product_review:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_product_variant:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_promotion:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_promotion_coupon:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_shipment:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_shipping_category:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_shipping_method:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_tax_category:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_tax_rate:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_taxon:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_admin_zone:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_shop_account_order:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
sylius_shop_product:
|
||||
driver:
|
||||
name: doctrine/orm
|
||||
options:
|
||||
pagination:
|
||||
fetch_join_collection: false
|
||||
use_output_walkers: false
|
||||
|
||||
Learn more
|
||||
----------
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ If all is well the output should look like:
|
|||
---------------------------- -------------------------------------------
|
||||
Parameter Value
|
||||
---------------------------- -------------------------------------------
|
||||
sylius.model.country.class App\Entity\Country
|
||||
sylius.model.country.class App\Entity\Addressing\Country
|
||||
---------------------------- -------------------------------------------
|
||||
|
||||
.. tip::
|
||||
|
|
|
|||
|
|
@ -24,11 +24,14 @@ Default logo in shop panel:
|
|||
The first step is to detect which template is responsible for displaying the logo and therefore which should be overridden
|
||||
to customize a logo image.
|
||||
|
||||
It's placed in **SyliusShopBundle**, at ``Resources/views/_header.html.twig.path``, so to override it,
|
||||
you should create the ``templates/bundles/SyliusShopBundle/_header.html.twig`` file and copy the original file content.
|
||||
It's placed in **SyliusShopBundle**, at ``Resources/views/Layout/Header/_logo.html.twig`` path, so to override it,
|
||||
you should create the ``templates/bundles/SyliusShopBundle/Layout/Header/_logo.html.twig`` file and copy the original file content.
|
||||
Next, replace the ``img`` element source with a link to the logo or properly imported asset image (take a look at
|
||||
`Symfony assets documentation <https://symfony.com/doc/current/best_practices/web-assets.html>`_ for more info).
|
||||
|
||||
The other way to achieve this is to modify the configuration of the ``sylius.shop.layout.header.grid`` template event.
|
||||
Learn more about it in :doc:`this doc</customization/template>`.
|
||||
|
||||
.. hint::
|
||||
|
||||
*Psst!* To speed up your learning path you can just put a logo file into the ``public/assets/`` directory. Just remember,
|
||||
|
|
@ -38,18 +41,8 @@ At the end of customization, the overridden file would look similar to this:
|
|||
|
||||
.. code-block:: twig
|
||||
|
||||
<div class="ui basic segment">
|
||||
<div class="ui three column stackable grid">
|
||||
<div class="column">
|
||||
<a href="{{ path('sylius_shop_homepage') }}"><img src="{{ asset('assets/logo.png') }}" alt="Logo" class="ui small image" /></a>
|
||||
</div>
|
||||
<div class="column">
|
||||
{{ sonata_block_render_event('sylius.shop.layout.header') }}
|
||||
</div>
|
||||
<div class="right aligned column">
|
||||
{{ render(url('sylius_shop_partial_cart_summary', {'template': '@SyliusShop/Cart/_widget.html.twig'})) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<a href="{{ path('sylius_shop_homepage') }}"><img src="{{ asset('assets/logo.png') }}" alt="Logo" class="ui small image" /></a>
|
||||
</div>
|
||||
|
||||
A custom logo should now be displayed on the Shop panel header:
|
||||
|
|
|
|||
|
|
@ -107,6 +107,18 @@ Components & Bundles
|
|||
|
||||
.. include:: /components_and_bundles/map.rst.inc
|
||||
|
||||
The Performance Guide
|
||||
---------------------
|
||||
|
||||
With :doc:`The Performance Guide </performance/index>` you can decrease page loading times.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
performance/index
|
||||
|
||||
.. include:: /performance/map.rst.inc
|
||||
|
||||
.. _Sylius: https://sylius.com
|
||||
.. _`Symfony Framework`: https://symfony.com
|
||||
.. _`Quick Tour`: https://symfony.com/doc/current/quick_tour
|
||||
|
|
|
|||
46
docs/performance/database-indexes.rst
Normal file
46
docs/performance/database-indexes.rst
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Database indexes
|
||||
================
|
||||
|
||||
Indexing tables allow you to decrease fetching time from the database.
|
||||
|
||||
As an example, let's take a look at the customers' list.
|
||||
|
||||
The default index page is sorted by registration date, to create a table index all you need to do is modify `App\Entity\Customer\Customer` entity and add the index using annotations.
|
||||
|
||||
In this file, add indexes attribute into the table configuration:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
`@ORM\Table(name="sylius_customer", indexes={@ORM\Index(name="created_at_index", columns={"created_at"})})`.
|
||||
|
||||
Your class should now look like this:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Customer;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Sylius\Component\Core\Model\Customer as BaseCustomer;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="sylius_customer",indexes={@ORM\Index(name="created_at_index", columns={"created_at"})})
|
||||
*/
|
||||
class Customer extends BaseCustomer
|
||||
{
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
You can learn more here about `ORM annotations <https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref_haslifecyclecallbacks>`_
|
||||
|
||||
This should be considered for the most common sorting in your application.
|
||||
|
||||
.. note::
|
||||
|
||||
Using this solution you can increase speed of customer listing by around 10%.
|
||||
Indexes should be used when working with huge tables, otherwise it doesnt really affect loading times.
|
||||
12
docs/performance/index.rst
Normal file
12
docs/performance/index.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
The Performance Guide
|
||||
=====================
|
||||
|
||||
With huge databases some of you may experience performance issues, with this guide you can learn how to handle even millions of records.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
database-indexes
|
||||
query-optimization
|
||||
|
||||
.. include:: /performance/map.rst.inc
|
||||
2
docs/performance/map.rst.inc
Normal file
2
docs/performance/map.rst.inc
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
* :doc:`/performance/database-indexes`
|
||||
* :doc:`/performance/query-optimization`
|
||||
26
docs/performance/query-optimization.rst
Normal file
26
docs/performance/query-optimization.rst
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Query optimization
|
||||
==================
|
||||
|
||||
A huge performance boost is achieved by optimizing queries.
|
||||
For example, let's take a look at the customers' list.
|
||||
|
||||
By default, we don't really need to fetch every single field from a customer entity to create a list of 10 customers.
|
||||
All we need, is to load the `id` and the field we are sorting by (for pagination purposes).
|
||||
|
||||
Once these 10 customers are fetched, we can create 10 queries to fetch data for them.
|
||||
As it can slow down small databases (a lot of unnecessary queries), this allows tables with millions of records to be loaded in less than a second.
|
||||
|
||||
It seems to be a bit complicated, but `Pagerfanta\Adapter\DoctrineORMAdapter` allow us to achieve it easily.
|
||||
|
||||
The second argument of `Pagerfanta\Adapter\DoctrineORMAdapter` is `fetchJoinCollection`, which is set to `false` by default.
|
||||
Changing it to `true`, forces the database to fetch additional data once we get sorted results.
|
||||
|
||||
With 3 000 000 customers this method allows you to load page up to 70% faster.
|
||||
|
||||
.. warning::
|
||||
|
||||
This solution may slow down loading page with small tables as it will create additional database queries.
|
||||
|
||||
This solution will be turned on by default on `SyliusGridBundle` since version 1.10.
|
||||
For the earlier versions, the `Pagerfanta\Adapter\DoctrineORMAdapter` has to be adjusted manually,
|
||||
by overriding the `Sylius\Bundle\GridBundle\Doctrine\ORM\DataSource` class.
|
||||
|
|
@ -23,8 +23,8 @@ Feature: Editing a customer profile
|
|||
When I want to modify my profile
|
||||
And I specify the customer email as "frank@underwood.com"
|
||||
And I save my changes
|
||||
Then I should be notified that it has been successfully edited
|
||||
And I should be notified that the verification email has been sent
|
||||
# Then I should be notified that it has been successfully edited
|
||||
# And I should be notified that the verification email has been sent
|
||||
And it should be sent to "frank@underwood.com"
|
||||
And I should not be logged in
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ Feature: Seeing customer's orders placed as guest
|
|||
@ui @api
|
||||
Scenario: Not being able to hijack another customer's orders
|
||||
Given I registered with previously used "ned@stark.com" email and "lannistersAreDumb" password
|
||||
And I log in as "ned@stark.com" with "lannistersAreDumb" password
|
||||
When I log in as "ned@stark.com" with "lannistersAreDumb" password
|
||||
And I browse my orders
|
||||
Then I should see a single order in the list
|
||||
|
|
|
|||
|
|
@ -9,17 +9,23 @@ Feature: Viewing orders on my account page
|
|||
And the store has "Angel T-Shirt" and "Green Arrow" products
|
||||
And the store ships everywhere for free
|
||||
And the store allows paying with "Cash on Delivery"
|
||||
And I am a logged in customer
|
||||
And there is another customer "oliver@teamarrow.com" that placed an order "#00000999"
|
||||
And the customer bought a single "Green Arrow"
|
||||
And the customer "Oliver Queen" addressed it to "Seaside Fwy", "90802" "Los Angeles" in the "United States" with identical billing address
|
||||
And the customer chose "Free" shipping method with "Cash on Delivery" payment
|
||||
|
||||
@ui @api
|
||||
Scenario: Viewing orders
|
||||
Given I am a logged in customer
|
||||
And I placed an order "#00000666"
|
||||
And I bought a single "Angel T-Shirt"
|
||||
And I addressed it to "Lucifer Morningstar", "Seaside Fwy", "90802" "Los Angeles" in the "United States" with identical billing address
|
||||
And I chose "Free" shipping method with "Cash on Delivery" payment
|
||||
And there is another customer "oliver@teamarrow.com" that placed an order "#00000999"
|
||||
And the customer bought a single "Green Arrow"
|
||||
And the customer "Oliver Queen" addressed it to "Seaside Fwy", "90802" "Los Angeles" in the "United States" with identical billing address
|
||||
|
||||
@ui @api
|
||||
Scenario: Viewing orders
|
||||
When I browse my orders
|
||||
Then I should see a single order in the list
|
||||
And this order should have "#00000666" number
|
||||
|
||||
@api
|
||||
Scenario: Viewing orders
|
||||
When I browse my orders
|
||||
Then I should be denied an access to order list
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ Feature: Account registration
|
|||
Scenario: Trying to register a new account with email that has been already used
|
||||
Given there is a user "goodman@gmail.com" identified by "heisenberg"
|
||||
When I want to register a new account
|
||||
And I specify the first name as "Saul"
|
||||
And I specify the last name as "Goodman"
|
||||
And I specify the email as "goodman@gmail.com"
|
||||
And I try to register this account
|
||||
Then I should be notified that the email is already used
|
||||
|
|
@ -71,3 +73,12 @@ Feature: Account registration
|
|||
And I try to register this account
|
||||
Then I should be notified that the email is required
|
||||
And I should not be logged in
|
||||
|
||||
@api
|
||||
Scenario: Trying to register a new account without providing required fields
|
||||
When I want to register a new account
|
||||
And I specify the email as "goodman@gmail.com"
|
||||
And I specify the password as "heisenberg"
|
||||
And I try to register this account
|
||||
Then I should be notified that the "first name" and "last name" have to be provided
|
||||
And I should not be logged in
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
@admin_locale
|
||||
Feature: Browsing administration panel in a proper locale
|
||||
In order to see panel in correct language
|
||||
As an Admin
|
||||
I want to browse admin panel in my locale
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel
|
||||
And that channel allows to shop using "English (United States)" and "Polish (Poland)" locales
|
||||
And it uses the "Polish (Poland)" locale by default
|
||||
And I am logged in as an administrator
|
||||
And I am using "Polish (Poland)" locale for my panel
|
||||
|
||||
@ui
|
||||
Scenario: Getting errors in my language
|
||||
Given I am editing my details
|
||||
When I change its email to "wrong-email"
|
||||
And I save my changes
|
||||
Then I should be notified that this email is not valid in "Polish (Poland)" locale
|
||||
|
||||
@ui
|
||||
Scenario: Seeing menu in my language
|
||||
When I open administration dashboard
|
||||
Then I should see sidebar catalog section configuration in "Polish (Poland)" locale
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@checkout
|
||||
Feature: Order address validation
|
||||
In order to avoid making mistakes when addressing order
|
||||
As Visitor
|
||||
I want to be prevented from adding incorrect order address
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store has a product "Stark T-shirt" priced at "$12.00"
|
||||
And the store allows paying offline
|
||||
And the store has "UPS" shipping method with "$20.00" fee
|
||||
|
||||
@api
|
||||
Scenario: Trying to add address with incorrect country to the cart by the visitor
|
||||
Given the visitor has product "Stark T-Shirt" in the cart
|
||||
When the visitor specify the email as "jon.snow@example.com"
|
||||
And the visitor try to specify the incorrect billing address as "Ankh Morpork", "Frost Alley", "90210", "United Russia" for "Jon Snow"
|
||||
And the visitor complete the addressing step
|
||||
Then they should be notified that "United Russia" country does not exist
|
||||
|
||||
@api
|
||||
Scenario: Trying to add address without country to the cart by the visitor
|
||||
Given the visitor has product "Stark T-Shirt" in the cart
|
||||
When the visitor specify the email as "jon.snow@example.com"
|
||||
And the visitor try to specify the billing address without country as "Ankh Morpork", "Frost Alley", "90210" for "Jon Snow"
|
||||
And the visitor complete the addressing step
|
||||
Then they should be notified that address without country cannot exist
|
||||
|
||||
@api
|
||||
Scenario: Trying to add address without any products in cart
|
||||
Given the visitor picks up the cart
|
||||
When the visitor specify the email as "jon.snow@example.com"
|
||||
And the visitor specify the billing address as "Ankh Morpork", "Frost Alley", "90210", "United States" for "Jon Snow"
|
||||
And the visitor complete the addressing step
|
||||
Then they should be notified that they cannot address an empty cart
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
@checkout
|
||||
Feature: Preventing adding to cart disabled products
|
||||
In order to have correct products in cart when adding them
|
||||
As a Customer
|
||||
I want to have the added products validated
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store has a product "PHP T-Shirt" priced at "$19.99"
|
||||
And the store has a "Super Cool T-Shirt" configurable product
|
||||
And this product has "Small", "Medium" and "Large" variants
|
||||
And I am a logged in customer
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding disabled product
|
||||
Given the product "PHP T-Shirt" has been disabled
|
||||
When I pick up my cart
|
||||
And I try to add product "PHP T-Shirt" to the cart
|
||||
Then I should be informed that product "PHP T-Shirt" does not exist
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding disabled variant
|
||||
Given the "Large" product variant is disabled
|
||||
When I pick up my cart
|
||||
And I try to add "Large" product variant
|
||||
Then I should be informed that "Large" product variant does not exist
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
@checkout
|
||||
Feature: Preventing adding to cart inexistent product variant
|
||||
In order to have correct products in cart when adding them
|
||||
As a Customer
|
||||
I want to have the added product variants validated
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store has a "Super Cool T-Shirt" configurable product
|
||||
And this product has "Small", "Medium" and "Large" variants
|
||||
And I am a logged in customer
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding inexistent variant
|
||||
Given the "Large" product variant is disabled
|
||||
When I pick up my cart
|
||||
And I try to add product "Super Cool T-Shirt" with variant code "Magic"
|
||||
Then I should be informed that product variant with code "Magic" does not exist
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
@checkout
|
||||
Feature: Preventing adding to cart product or variant from another channel
|
||||
In order to have correct products in cart when adding them
|
||||
As a Customer
|
||||
I want to have the added products validated
|
||||
|
||||
Background:
|
||||
Given the store operates on a channel named "France" with hostname "france"
|
||||
And the store has a "Baquette" configurable product
|
||||
And this product has "Small", "Medium" and "Large" variants
|
||||
And the store has a "Pain" product
|
||||
And the store operates on a channel named "Poland" with hostname "poland"
|
||||
And I am a logged in customer
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding simple product from another channel
|
||||
Given I am browsing channel "Poland"
|
||||
When I pick up my cart
|
||||
And I try to add product "Pain" to the cart
|
||||
Then I should be informed that product "Pain" does not exist
|
||||
|
||||
@api
|
||||
Scenario: Preventing customer from adding product with variant from another channel
|
||||
Given I am browsing channel "Poland"
|
||||
When I pick up my cart
|
||||
And I try to add "Large" variant of product "Baquette"
|
||||
Then I should be informed that product "Baquette" does not exist
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
@managing_orders
|
||||
Feature: Limiting the number of orders
|
||||
In order to display a specific number of orders
|
||||
As an Administrator
|
||||
I want to be able to limit the number of orders on the list
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And the store has a product "Blue ElePHPant"
|
||||
And the store ships everywhere for free
|
||||
And the store allows paying offline
|
||||
And there is a customer "john@doe.com" that placed an order "#00000022"
|
||||
And the customer bought a single "Blue ElePHPant"
|
||||
And the customer chose "Free" shipping method to "United States" with "Offline" payment
|
||||
And this customer placed another order "#00000023"
|
||||
And the customer bought a single "Blue ElePHPant"
|
||||
And the customer chose "Free" shipping method to "United States" with "Offline" payment
|
||||
And I am logged in as an administrator
|
||||
|
||||
@api
|
||||
Scenario: Limiting the number of orders
|
||||
When I browse orders
|
||||
And I limit number of items to 1
|
||||
Then I should see a single order in the list
|
||||
|
|
@ -26,7 +26,7 @@ Feature: Viewing diagonal variants options
|
|||
@ui @javascript
|
||||
Scenario: Viewing an "Unavailable" message when selecting an unavailable combination
|
||||
When I view product "Extra Cool T-Shirt"
|
||||
And I set its color to "Blue"
|
||||
And I set its size to "Small"
|
||||
And I select its color as "Blue"
|
||||
And I select its size as "Small"
|
||||
Then I should see that the combination is "Unavailable"
|
||||
And I should be unable to add it to the cart
|
||||
|
|
|
|||
|
|
@ -19,5 +19,5 @@ Feature: Viewing different price for different product variants selected with op
|
|||
@ui @javascript
|
||||
Scenario: Viewing a detailed page with product's price for different option
|
||||
When I view product "Wyborowa Vodka"
|
||||
And I set its volume to "0,7L"
|
||||
And I select its volume as "0,7L"
|
||||
Then I should see the product price "$25.00"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
@viewing_products
|
||||
Feature: Viewing enabled products only
|
||||
In order to see only available products
|
||||
As a Customer
|
||||
I want to see only enabled product variants
|
||||
|
||||
Background:
|
||||
Given the store operates on a channel named "Web-US" in "USD" currency
|
||||
And the store has a "Super Cool T-Shirt" product
|
||||
And the store has a "PHP T-Shirt" product
|
||||
And the store has a "Shiny T-Shirt" product
|
||||
And the "PHP T-shirt" product is disabled
|
||||
|
||||
@api
|
||||
Scenario: Seeing only enabled products
|
||||
When I browse products
|
||||
Then I should see only 2 products
|
||||
And I should not see the product with name "PHP T-shirt"
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@applying_taxes
|
||||
Feature: Applying correct taxes for shipping
|
||||
In order to pay proper amount for shipping and products
|
||||
As a Visitor
|
||||
I want to have correct taxes applied to my order
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And default tax zone is "US"
|
||||
And the store has "VAT" tax rate of 5% for "Clothes" within the "US" zone
|
||||
And the store has included in price "VAT included" tax rate of 5% for "Mugs" within the "US" zone
|
||||
And the store has "Shipping VAT" tax rate of 10% for "Shipping Services" within the "US" zone
|
||||
And the store has a product "PHP T-Shirt" priced at "$10.00"
|
||||
And it belongs to "Clothes" tax category
|
||||
And the store has a product "PHP Mug" priced at "$10.00"
|
||||
And it belongs to "Mugs" tax category
|
||||
And the store has "DHL" shipping method with "$10.00" fee within the "US" zone
|
||||
And shipping method "DHL" belongs to "Shipping Services" tax category
|
||||
|
||||
@ui
|
||||
Scenario: Applying correct taxes for shipping
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
Then my cart items total should be "$10.00"
|
||||
And my cart estimated shipping cost should be "$11.00"
|
||||
And my cart taxes should be "$1.50"
|
||||
And my cart total should be "$21.50"
|
||||
|
||||
@ui
|
||||
Scenario: Applying correct taxes for shipping
|
||||
When I add product "PHP Mug" to the cart
|
||||
Then my cart items total should be "$10.00"
|
||||
And my cart estimated shipping cost should be "$11.00"
|
||||
And my cart taxes should be "$1.00"
|
||||
And my cart included in price taxes should be "$0.48"
|
||||
And my cart total should be "$21.00"
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
@applying_taxes
|
||||
Feature: Applying correct taxes for shipping with tax rate included in price
|
||||
In order to pay proper amount for shipping and products
|
||||
As a Visitor
|
||||
I want to have correct taxes applied to my order
|
||||
|
||||
Background:
|
||||
Given the store operates on a single channel in "United States"
|
||||
And default tax zone is "US"
|
||||
And the store has "VAT" tax rate of 5% for "Clothes" within the "US" zone
|
||||
And the store has included in price "VAT included" tax rate of 5% for "Mugs" within the "US" zone
|
||||
And the store has included in price "Shipping VAT" tax rate of 10% for "Shipping Services" within the "US" zone
|
||||
And the store has a product "PHP T-Shirt" priced at "$10.00"
|
||||
And it belongs to "Clothes" tax category
|
||||
And the store has a product "PHP Mug" priced at "$10.00"
|
||||
And it belongs to "Mugs" tax category
|
||||
And the store has "DHL" shipping method with "$10.00" fee within the "US" zone
|
||||
And shipping method "DHL" belongs to "Shipping Services" tax category
|
||||
|
||||
@ui
|
||||
Scenario: Applying correct taxes for shipping with tax rate included in price
|
||||
When I add product "PHP T-Shirt" to the cart
|
||||
Then my cart items total should be "$10.00"
|
||||
And my cart estimated shipping cost should be "$10.00"
|
||||
And my cart taxes should be "$0.50"
|
||||
And my cart included in price taxes should be "$0.91"
|
||||
And my cart total should be "$20.50"
|
||||
|
||||
@ui
|
||||
Scenario: Applying correct taxes for shipping with tax rate included in price
|
||||
When I add product "PHP Mug" to the cart
|
||||
Then my cart items total should be "$10.00"
|
||||
And my cart estimated shipping cost should be "$10.00"
|
||||
And my cart included in price taxes should be "$1.39"
|
||||
And my cart total should be "$20.00"
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@managing_taxons
|
||||
Feature: Displaying products in proper taxon after trying to delete this taxon
|
||||
In order not to mess up the products to taxons assignments
|
||||
As an Administrator
|
||||
I want to keep the taxons structure the same after failed taxon deletion
|
||||
|
||||
Background:
|
||||
Given the store operates on a channel named "Web"
|
||||
And the store classifies its products as "T-Shirts"
|
||||
And the "T-Shirts" taxon has children taxon "Men" and "Women"
|
||||
And the store has a product "T-Shirt Coconut" available in "Web" channel
|
||||
And this product belongs to "T-Shirts"
|
||||
And the store has a product "T-Shirt Banana" available in "Web" channel
|
||||
And this product belongs to "Men"
|
||||
And the product "T-Shirt Banana" has a main taxon "Men"
|
||||
And the store has a product "T-Shirt Apple" available in "Web" channel
|
||||
And this product belongs to "Men"
|
||||
And the store has a product "T-Shirt Pear" available in "Web" channel
|
||||
And this product belongs to "Women"
|
||||
And the store has a product "T-Shirt Watermelon" available in "Web" channel
|
||||
And this product belongs to "Women"
|
||||
And I am logged in as an administrator
|
||||
|
||||
@ui @javascript
|
||||
Scenario: Displaying products in proper taxon after trying to delete this taxon
|
||||
When I try to delete taxon named "Men"
|
||||
Then I should be notified that I cannot delete a taxon in use
|
||||
And I should see in taxon "Men" in the store products "T-Shirt Banana" and "T-Shirt Apple"
|
||||
But I should not see in taxon "Men" in the store products "T-Shirt Pear" and "T-Shirt Watermelon"
|
||||
|
|
@ -19,7 +19,6 @@ suites:
|
|||
|
||||
AddressingBundle: { namespace: Sylius\Bundle\AddressingBundle, psr4_prefix: Sylius\Bundle\AddressingBundle, spec_path: src/Sylius/Bundle/AddressingBundle, src_path: src/Sylius/Bundle/AddressingBundle }
|
||||
AdminBundle: { namespace: Sylius\Bundle\AdminBundle, psr4_prefix: Sylius\Bundle\AdminBundle, spec_path: src/Sylius/Bundle/AdminBundle, src_path: src/Sylius/Bundle/AdminBundle }
|
||||
AdminApiBundle: { namespace: Sylius\Bundle\AdminApiBundle, psr4_prefix: Sylius\Bundle\AdminApiBundle, spec_path: src/Sylius/Bundle/AdminApiBundle, src_path: src/Sylius/Bundle/AdminApiBundle }
|
||||
ApiBundle: { namespace: Sylius\Bundle\ApiBundle, psr4_prefix: Sylius\Bundle\ApiBundle, spec_path: src/Sylius/Bundle/ApiBundle, src_path: src/Sylius/Bundle/ApiBundle }
|
||||
AttributeBundle: { namespace: Sylius\Bundle\AttributeBundle, psr4_prefix: Sylius\Bundle\AttributeBundle, spec_path: src/Sylius/Bundle/AttributeBundle, src_path: src/Sylius/Bundle/AttributeBundle }
|
||||
ChannelBundle: { namespace: Sylius\Bundle\ChannelBundle, psr4_prefix: Sylius\Bundle\ChannelBundle, spec_path: src/Sylius/Bundle/ChannelBundle, src_path: src/Sylius/Bundle/ChannelBundle }
|
||||
|
|
|
|||
13
psalm.xml
13
psalm.xml
|
|
@ -18,8 +18,6 @@
|
|||
<directory name="src/Sylius/Bundle/AddressingBundle/spec" />
|
||||
<directory name="src/Sylius/Bundle/AddressingBundle/test" />
|
||||
<directory name="src/Sylius/Bundle/AddressingBundle/Tests" />
|
||||
<directory name="src/Sylius/Bundle/AdminApiBundle/spec" />
|
||||
<directory name="src/Sylius/Bundle/AdminApiBundle/Tests" />
|
||||
<directory name="src/Sylius/Bundle/ApiBundle/spec" />
|
||||
<directory name="src/Sylius/Bundle/ApiBundle/Tests" />
|
||||
<directory name="src/Sylius/Bundle/ApiBundle/test" />
|
||||
|
|
@ -97,6 +95,10 @@
|
|||
<referencedClass name="Symfony\Component\Routing\RouteCollectionBuilder" /> <!-- deprecated in Symfony 5.1 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Role\Role" /> <!-- deprecated in Symfony 4.3 -->
|
||||
<referencedClass name="Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler" /> <!-- deprecated in Symfony 5.1 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Encoder\EncoderAwareInterface" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Exception\UsernameNotFoundException" /> <!-- deprecated in Symfony 5.3 -->
|
||||
</errorLevel>
|
||||
</DeprecatedClass>
|
||||
<DeprecatedInterface>
|
||||
|
|
@ -104,6 +106,7 @@
|
|||
<referencedClass name="Sylius\Component\Core\Calculator\ProductVariantPriceCalculatorInterface" />
|
||||
<referencedClass name="Symfony\Component\Security\Core\User\AdvancedUserInterface" /> <!-- deprecated in Symfony 4.1 -->
|
||||
<referencedClass name="Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface" /> <!-- deprecated in Symfony 5.1 -->
|
||||
<referencedClass name="Symfony\Component\Security\Core\Encoder\EncoderAwareInterface" /> <!-- deprecated in Symfony 5.3 -->
|
||||
</errorLevel>
|
||||
</DeprecatedInterface>
|
||||
<DeprecatedMethod>
|
||||
|
|
@ -111,6 +114,12 @@
|
|||
<referencedMethod name="Payum\Core\Model\GatewayConfigInterface::setFactoryName" />
|
||||
<referencedMethod name="Symfony\Component\EventDispatcher\Event::stopPropagation" /> <!-- deprecated in Symfony 4.3 -->
|
||||
<referencedMethod name="Symfony\Component\HttpFoundation\JsonResponse::create" /> <!-- deprecated in Symfony 5.1 -->
|
||||
<referencedMethod name="Symfony\Component\HttpFoundation\RequestStack::getMasterRequest" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedMethod name="Symfony\Component\Security\Core\Authentication\Token\TokenInterface::getUsername" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedMethod name="Symfony\Component\HttpKernel\Event\KernelEvent::isMasterRequest" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedMethod name="Symfony\Component\Security\Core\User\UserInterface::getUsername" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedMethod name="Symfony\Component\Security\Core\User\UserProviderInterface::loadUserByUsername" /> <!-- deprecated in Symfony 5.3 -->
|
||||
<referencedMethod name="Faker\Generator::__get"/>
|
||||
</errorLevel>
|
||||
</DeprecatedMethod>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
DirectoryIndex app.php
|
||||
DirectoryIndex index.php
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
|
|
|
|||
|
|
@ -187,6 +187,26 @@ final class ResponseChecker implements ResponseCheckerInterface
|
|||
return json_decode($response->getContent(), true);
|
||||
}
|
||||
|
||||
public function hasViolationWithMessage(Response $response, string $message, ?string $property = null): bool
|
||||
{
|
||||
if (!$this->hasKey($response, 'violations')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$violations = $this->getResponseContent($response)['violations'];
|
||||
foreach ($violations as $violation) {
|
||||
if ($violation['message'] === $message && $property === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($violation['message'] === $message && $property !== null && $violation['propertyPath'] === $property) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getResponseContentValue(Response $response, string $key)
|
||||
{
|
||||
$content = json_decode($response->getContent(), true);
|
||||
|
|
|
|||
|
|
@ -67,4 +67,6 @@ interface ResponseCheckerInterface
|
|||
public function hasItemWithValues(Response $response, array $parameters): bool;
|
||||
|
||||
public function getResponseContent(Response $response): array;
|
||||
|
||||
public function hasViolationWithMessage(Response $response, string $message, ?string $property = null): bool;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,15 @@ final class ManagingOrdersContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I limit number of items to :limit
|
||||
*/
|
||||
public function iLimitNumberOfItemsTo(int $limit): void
|
||||
{
|
||||
$this->client->addFilter('itemsPerPage', $limit);
|
||||
$this->client->filter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see a single order from customer :customer
|
||||
*/
|
||||
|
|
@ -131,6 +140,14 @@ final class ManagingOrdersContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see a single order in the list
|
||||
*/
|
||||
public function iShouldSeeASingleOrderInTheList(): void
|
||||
{
|
||||
Assert::same($this->responseChecker->countCollectionItems($this->client->getLastResponse()), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that it has been successfully updated
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ final class CartContext implements Context
|
|||
/**
|
||||
* @When I pick up my cart (again)
|
||||
* @When I pick up cart in the :localeCode locale
|
||||
* @When the visitor picks up the cart
|
||||
*/
|
||||
public function iPickUpMyCart(?string $localeCode = null): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Sylius\Behat\Context\Api\Shop;
|
|||
use Behat\Behat\Context\Context;
|
||||
use Sylius\Behat\Client\ApiClientInterface;
|
||||
use Sylius\Behat\Client\ResponseCheckerInterface;
|
||||
use Sylius\Behat\Service\SharedStorageInterface;
|
||||
use Sylius\Component\Core\Model\ChannelInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
|
|
@ -27,10 +28,25 @@ final class ChannelContext implements Context
|
|||
/** @var ResponseCheckerInterface */
|
||||
private $responseChecker;
|
||||
|
||||
public function __construct(ApiClientInterface $client, ResponseCheckerInterface $responseChecker)
|
||||
{
|
||||
/** @var SharedStorageInterface */
|
||||
private $sharedStorage;
|
||||
|
||||
public function __construct(
|
||||
ApiClientInterface $client,
|
||||
ResponseCheckerInterface $responseChecker,
|
||||
SharedStorageInterface $sharedStorage
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->responseChecker = $responseChecker;
|
||||
$this->sharedStorage = $sharedStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given I am browsing channel :channel
|
||||
*/
|
||||
public function iAmBrowsingChannel(ChannelInterface $channel): void
|
||||
{
|
||||
$this->sharedStorage->set('hostname', $channel->getHostname());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use Sylius\Component\Core\Model\CustomerInterface;
|
|||
use Sylius\Component\Core\Model\OrderInterface;
|
||||
use Sylius\Component\Core\Model\PaymentMethodInterface;
|
||||
use Sylius\Component\Core\Model\ProductInterface;
|
||||
use Sylius\Component\Core\Model\ProductVariantInterface;
|
||||
use Sylius\Component\Core\Model\ShippingMethodInterface;
|
||||
use Sylius\Component\Core\Model\ShopUserInterface;
|
||||
use Sylius\Component\Core\OrderCheckoutStates;
|
||||
|
|
@ -181,6 +182,33 @@ final class CheckoutContext implements Context
|
|||
$this->fillAddress('billingAddress', $address);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^the visitor try to specify the incorrect billing address as "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)" for "([^"]+)"$/
|
||||
*/
|
||||
public function iTryToSpecifyTheIncorrectBillingAddressAs(
|
||||
string $city,
|
||||
string $street,
|
||||
string $postcode,
|
||||
string $countryName,
|
||||
string $customerName
|
||||
): void {
|
||||
$addressType = 'billingAddress';
|
||||
|
||||
$this->addAddress($addressType, $city, $street, $postcode, $customerName, $countryName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^the visitor try to specify the billing address without country as "([^"]+)", "([^"]+)", "([^"]+)" for "([^"]+)"$/
|
||||
*/
|
||||
public function iTryToSpecifyTheBillingAddressWithoutCountryAs(
|
||||
string $city,
|
||||
string $street,
|
||||
string $postcode,
|
||||
string $customerName
|
||||
): void {
|
||||
$this->addAddress('billingAddress', $city, $street, $postcode, $customerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I specify the shipping (address as "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)" for "([^"]+)")$/
|
||||
* @When /^I specify the shipping (address for "([^"]+)" from "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)", "([^"]+)")$/
|
||||
|
|
@ -618,6 +646,41 @@ final class CheckoutContext implements Context
|
|||
Assert::same($this->getCheckoutState(), $this::CHECKOUT_STATE_TYPES[$stepType]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that :countryName country does not exist
|
||||
* @Then they should be notified that :countryName country does not exist
|
||||
*/
|
||||
public function iShouldBeNotifiedThatCountryDoesNotExist(string $countryName): void
|
||||
{
|
||||
$this->responseChecker->hasViolationWithMessage(
|
||||
$this->ordersClient->getLastResponse(),
|
||||
sprintf('The country %s does not exist.', StringInflector::nameToLowercaseCode($countryName))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that address without country cannot exist
|
||||
* @Then they should be notified that address without country cannot exist
|
||||
*/
|
||||
public function iShouldBeNotifiedThatAddressWithoutCountryCannotExist(): void
|
||||
{
|
||||
$this->responseChecker->hasViolationWithMessage(
|
||||
$this->ordersClient->getLastResponse(),
|
||||
'The address without country cannot exist'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then they should be notified that they cannot address an empty cart
|
||||
*/
|
||||
public function theyShouldBeNotifiedThatTheyCannotAddressAnEmptyCart(): void
|
||||
{
|
||||
$response = $this->ordersClient->getLastResponse();
|
||||
|
||||
Assert::false($this->responseChecker->isUpdateSuccessful($response));
|
||||
$this->responseChecker->hasViolationWithMessage($response, 'The empty cart cannot be addressed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see the thank you page
|
||||
* @Then /^the (?:visitor|customer) should see the thank you page$/
|
||||
|
|
@ -771,6 +834,7 @@ final class CheckoutContext implements Context
|
|||
|
||||
/**
|
||||
* @Then /^I should be informed that (this product) has been disabled$/
|
||||
* @Then /^I should be informed that (product "[^"]+") is disabled$/
|
||||
*/
|
||||
public function iShouldBeInformedThatThisProductHasBeenDisabled(ProductInterface $product): void
|
||||
{
|
||||
|
|
@ -780,6 +844,39 @@ final class CheckoutContext implements Context
|
|||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should be informed that (product "[^"]+") does not exist$/
|
||||
*/
|
||||
public function iShouldBeInformedThatThisProductDoesNotExist(ProductInterface $product): void
|
||||
{
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->ordersClient->getLastResponse(),
|
||||
sprintf('The product %s does not exist.', $product->getName())
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should be informed that ("([^"]*)" product variant) does not exist$/
|
||||
*/
|
||||
public function iShouldBeInformedThatProductVariantDoesNotExist(ProductVariantInterface $productVariant): void
|
||||
{
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->ordersClient->getLastResponse(),
|
||||
sprintf('The product variant with %s does not exist.', $productVariant->getCode())
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be informed that product variant with code :code does not exist
|
||||
*/
|
||||
public function iShouldBeInformedThatProductVariantWithCodeDoesNotExist(string $code): void
|
||||
{
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->ordersClient->getLastResponse(),
|
||||
sprintf('The product variant with %s does not exist.', $code)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not see the thank you page
|
||||
*/
|
||||
|
|
@ -833,6 +930,25 @@ final class CheckoutContext implements Context
|
|||
$this->putProductToCart($product, $tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I try to add ("([^"]+)" product variant)$/
|
||||
* @When /^I try to add ("([^"]+)" variant of product "([^"]+)")$/
|
||||
*/
|
||||
public function iTryToAddProductVariant(ProductVariantInterface $productVariant): void
|
||||
{
|
||||
$tokenValue = $this->getCartTokenValue();
|
||||
$this->putVariantToCart($productVariant, $tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I try to add (product "[^"]+") with variant code "([^"]+)"$/
|
||||
*/
|
||||
public function iTryToAddProductVariantWithCode(ProductInterface $product, string $code): void
|
||||
{
|
||||
$tokenValue = $this->getCartTokenValue();
|
||||
$this->putProductWithVariantCode($product, $tokenValue, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I try to remove (product "[^"]+") from the (cart)$/
|
||||
*/
|
||||
|
|
@ -1094,6 +1210,11 @@ final class CheckoutContext implements Context
|
|||
{
|
||||
Assert::notNull($productVariant = $this->productVariantResolver->getVariant($product));
|
||||
|
||||
$this->putVariantToCart($productVariant, $tokenValue, $quantity);
|
||||
}
|
||||
|
||||
private function putVariantToCart(ProductVariantInterface $productVariant, string $tokenValue, int $quantity = 1): void
|
||||
{
|
||||
$request = Request::customItemAction(
|
||||
'shop',
|
||||
'orders',
|
||||
|
|
@ -1103,7 +1224,7 @@ final class CheckoutContext implements Context
|
|||
);
|
||||
|
||||
$request->setContent([
|
||||
'productCode' => $product->getCode(),
|
||||
'productCode' => $productVariant->getProduct()->getCode(),
|
||||
'productVariantCode' => $productVariant->getCode(),
|
||||
'quantity' => $quantity,
|
||||
]);
|
||||
|
|
@ -1111,6 +1232,30 @@ final class CheckoutContext implements Context
|
|||
$this->sharedStorage->set('response', $this->ordersClient->executeCustomRequest($request));
|
||||
}
|
||||
|
||||
private function putProductWithVariantCode(ProductInterface $product, string $tokenValue, string $code): void
|
||||
{
|
||||
$request = $this->preparePutProductRequest($tokenValue);
|
||||
|
||||
$request->setContent([
|
||||
'productCode' => $product->getCode(),
|
||||
'productVariantCode' => $code,
|
||||
'quantity' => 1,
|
||||
]);
|
||||
|
||||
$this->sharedStorage->set('response', $this->ordersClient->executeCustomRequest($request));
|
||||
}
|
||||
|
||||
private function preparePutProductRequest(string $tokenValue): Request
|
||||
{
|
||||
return Request::customItemAction(
|
||||
'shop',
|
||||
'orders',
|
||||
$tokenValue,
|
||||
HTTPRequest::METHOD_PATCH,
|
||||
'items'
|
||||
);
|
||||
}
|
||||
|
||||
private function removeOrderItemFromCart(int $orderItemId, string $tokenValue): void
|
||||
{
|
||||
$request = Request::customItemAction(
|
||||
|
|
@ -1178,4 +1323,22 @@ final class CheckoutContext implements Context
|
|||
|
||||
return $this->ordersClient->executeCustomRequest($request);
|
||||
}
|
||||
|
||||
private function addAddress(
|
||||
string $addressType,
|
||||
string $city,
|
||||
string $street,
|
||||
string $postcode,
|
||||
string $customerName,
|
||||
?string $countryName = null
|
||||
): void {
|
||||
[$firstName, $lastName] = explode(' ', $customerName);
|
||||
|
||||
$this->content[$addressType]['city'] = $city;
|
||||
$this->content[$addressType]['street'] = $street;
|
||||
$this->content[$addressType]['postcode'] = $postcode;
|
||||
$this->content[$addressType]['firstName'] = $firstName;
|
||||
$this->content[$addressType]['lastName'] = $lastName;
|
||||
$this->content[$addressType]['countryCode'] = $countryName !== null ? StringInflector::nameToLowercaseCode($countryName) : null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,10 +203,10 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedThatFirstNameIsRequired(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
'First name must be at least 2 characters long.'
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -214,10 +214,10 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedThatLastNameIsRequired(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
'Last name must be at least 2 characters long.'
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,10 +225,10 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedThatEmailIsRequired(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
'Please enter your email.'
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -236,10 +236,10 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedThatTheEmailIsAlreadyUsed(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
'This email is already used.'
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -247,10 +247,10 @@ final class CustomerContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedThatElementIsInvalid(): void
|
||||
{
|
||||
$this->isViolationWithMessageInResponse(
|
||||
Assert::true($this->isViolationWithMessageInResponse(
|
||||
$this->customerClient->getLastResponse(),
|
||||
'This email is invalid.'
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -295,18 +295,6 @@ final class CustomerContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
private function isViolationWithMessageInResponse(Response $response, string $message): bool
|
||||
{
|
||||
$violations = $this->responseChecker->getResponseContent($response)['violations'];
|
||||
foreach ($violations as $violation) {
|
||||
if ($violation['message'] === $message) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that my password has been successfully changed
|
||||
*/
|
||||
|
|
@ -356,4 +344,16 @@ final class CustomerContext implements Context
|
|||
sprintf('%s must be %s.', ucfirst($elementName), $validationMessage)
|
||||
);
|
||||
}
|
||||
|
||||
private function isViolationWithMessageInResponse(Response $response, string $message): bool
|
||||
{
|
||||
$violations = $this->responseChecker->getResponseContent($response)['violations'];
|
||||
foreach ($violations as $violation) {
|
||||
if ($violation['message'] === $message) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,6 +298,14 @@ final class OrderContext implements Context
|
|||
Assert::false($this->responseChecker->isShowSuccessful($this->client->getLastResponse()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be denied an access to order list
|
||||
*/
|
||||
public function iShouldDeniedAnAccessToOrderList(): void
|
||||
{
|
||||
Assert::true($this->responseChecker->hasAccessDenied($this->client->getLastResponse()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should have :paymentMethod payment method on my order
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -133,6 +133,41 @@ final class ProductContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I browse products
|
||||
*/
|
||||
public function iViewProducts(): void
|
||||
{
|
||||
$this->client->index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I should see only (\d+) product(s)$/
|
||||
*/
|
||||
public function iShouldSeeOnlyProducts(int $count): void
|
||||
{
|
||||
Assert::same(
|
||||
count($this->responseChecker->getCollection($this->client->getLastResponse())),
|
||||
$count,
|
||||
'Number of products from response is different then expected'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not see the product with name :name
|
||||
*/
|
||||
public function iShouldNotSeeProductWithName(string $name): void
|
||||
{
|
||||
Assert::false(
|
||||
$this->responseChecker->hasItemWithTranslation(
|
||||
$this->client->getLastResponse(),
|
||||
'en_US',
|
||||
'name',
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see the product name :name
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -153,6 +153,21 @@ final class RegistrationContext implements Context
|
|||
$this->assertFieldValidationMessage('firstName', 'Please enter your first name.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should be notified that the "([^"]+)" and "([^"]+)" have to be provided$/
|
||||
*/
|
||||
public function iShouldBeNotifiedThatFieldHaveToBeProvided(string ...$fields): void
|
||||
{
|
||||
$fields = $this->convertElementsToCamelCase($fields);
|
||||
$content = $this->getResponseContent();
|
||||
|
||||
Assert::same(
|
||||
$content['message'],
|
||||
'Request does not have the following required fields specified: ' . implode(', ', $fields) . '.'
|
||||
);
|
||||
Assert::same($content['code'], 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that the last name is required
|
||||
*/
|
||||
|
|
@ -203,7 +218,7 @@ final class RegistrationContext implements Context
|
|||
|
||||
private function assertFieldValidationMessage(string $path, string $message): void
|
||||
{
|
||||
$decodedResponse = json_decode($this->client->getResponse()->getContent(), true, 512, \JSON_THROW_ON_ERROR);
|
||||
$decodedResponse = $this->getResponseContent();
|
||||
|
||||
Assert::keyExists($decodedResponse, 'violations');
|
||||
Assert::oneOf(
|
||||
|
|
@ -215,10 +230,22 @@ final class RegistrationContext implements Context
|
|||
private function fillContent(?string $email = 'example@example.com', ?string $password = 'example'): void
|
||||
{
|
||||
$this->content = [
|
||||
'firstName' => 'First',
|
||||
'lastName' => 'Last',
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
];
|
||||
}
|
||||
|
||||
private function getResponseContent(): array
|
||||
{
|
||||
return json_decode($this->client->getResponse()->getContent(), true);
|
||||
}
|
||||
|
||||
private function convertElementsToCamelCase(array $fields): array
|
||||
{
|
||||
foreach ($fields as $key => $field) {
|
||||
$fields[$key] = lcfirst(str_replace(' ', '', ucwords($field)));
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,11 +133,16 @@ final class OrderContext implements Context
|
|||
* @Given a customer :customer placed an order :orderNumber
|
||||
* @Given the customer :customer has already placed an order :orderNumber
|
||||
* @Given there is a customer :customer that placed an order :orderNumber in channel :channel
|
||||
* @Given /^(this customer) placed (another order "[^"]+")$/
|
||||
*/
|
||||
public function thereIsCustomerThatPlacedOrder(CustomerInterface $customer, $orderNumber = null, $channel = null)
|
||||
{
|
||||
public function thereIsCustomerThatPlacedOrder(
|
||||
CustomerInterface $customer,
|
||||
string $orderNumber = null,
|
||||
ChannelInterface $channel = null
|
||||
): void {
|
||||
$order = $this->createOrder($customer, $orderNumber, $channel);
|
||||
|
||||
$this->sharedStorage->set('customer', $customer);
|
||||
$this->sharedStorage->set('order', $order);
|
||||
|
||||
$this->orderRepository->add($order);
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ final class OrderContext implements Context
|
|||
/**
|
||||
* @Transform :orderNumber
|
||||
* @Transform /^an order "([^"]+)"$/
|
||||
* @Transform /^another order "([^"]+)"$/
|
||||
* @Transform /^the order "([^"]+)"$/
|
||||
* @Transform /^the "([^"]+)" order$/
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,22 +14,30 @@ declare(strict_types=1);
|
|||
namespace Sylius\Behat\Context\Ui\Admin;
|
||||
|
||||
use Behat\Behat\Context\Context;
|
||||
use Sylius\Behat\Page\Admin\Administrator\CreatePageInterface;
|
||||
use Sylius\Behat\Page\Admin\DashboardPageInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
final class LocaleContext implements Context
|
||||
{
|
||||
/** @var CreatePageInterface */
|
||||
private $createPage;
|
||||
|
||||
/** @var DashboardPageInterface */
|
||||
private $dashboardPage;
|
||||
|
||||
/** @var TranslatorInterface */
|
||||
private $translator;
|
||||
|
||||
public function __construct(DashboardPageInterface $dashboardPage, TranslatorInterface $translator)
|
||||
{
|
||||
public function __construct(
|
||||
DashboardPageInterface $dashboardPage,
|
||||
TranslatorInterface $translator,
|
||||
CreatePageInterface $createPage
|
||||
) {
|
||||
$this->dashboardPage = $dashboardPage;
|
||||
$this->translator = $translator;
|
||||
$this->createPage = $createPage;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,15 +53,23 @@ final class LocaleContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $text
|
||||
* @param string $localeCode
|
||||
*
|
||||
* @return string
|
||||
* @Then I should be notified that this email is not valid in :localeCode locale
|
||||
*/
|
||||
private function translate($text, $localeCode)
|
||||
public function iShouldBeNotifiedThatThisEmailIsNotValidInLocale(string $localeCode): void
|
||||
{
|
||||
$this->translator->setLocale($localeCode);
|
||||
Assert::same($this->createPage->getValidationMessage('email'), $this->translate('sylius.contact.email.invalid', $localeCode, 'validators'));
|
||||
}
|
||||
|
||||
return $this->translator->trans($text);
|
||||
/**
|
||||
* @Then I should see sidebar catalog section configuration in :localeCode locale
|
||||
*/
|
||||
public function iShouldSeeSidebarSectionConfigurationInLocale(string $localeCode): void
|
||||
{
|
||||
Assert::true($this->dashboardPage->isSectionWithLabelVisible($this->translate('sylius.menu.admin.main.catalog.header', $localeCode)));
|
||||
}
|
||||
|
||||
private function translate(string $text, string $localeCode, string $domain = null): string
|
||||
{
|
||||
return $this->translator->trans($text, [], $domain, $localeCode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -405,6 +405,17 @@ final class ManagingTaxonsContext implements Context
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should be notified that I cannot delete a taxon in use
|
||||
*/
|
||||
public function iShouldBeNotifiedThatICannotDeleteATaxonInUse(): void
|
||||
{
|
||||
$this->notificationChecker->checkNotification(
|
||||
'Cannot delete, the taxon is in use.',
|
||||
NotificationType::failure()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @When I move up :taxonName taxon
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -119,6 +119,14 @@ final class CartContext implements Context
|
|||
Assert::same($this->summaryPage->getBaseGrandTotal(), $total);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then my cart items total should be :total
|
||||
*/
|
||||
public function myCartItemsTotalShouldBe(string $itemsTotal): void
|
||||
{
|
||||
Assert::same($this->summaryPage->getItemsTotal(), $itemsTotal);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then my cart taxes should be :taxTotal
|
||||
*/
|
||||
|
|
@ -131,6 +139,7 @@ final class CartContext implements Context
|
|||
|
||||
/**
|
||||
* @Then my included in price taxes should be :taxTotal
|
||||
* @Then my cart included in price taxes should be :taxTotal
|
||||
*/
|
||||
public function myIncludedInPriceTaxesShouldBe(string $taxTotal): void
|
||||
{
|
||||
|
|
@ -152,8 +161,9 @@ final class CartContext implements Context
|
|||
/**
|
||||
* @Then my cart shipping total should be :shippingTotal
|
||||
* @Then my cart shipping should be for free
|
||||
* @Then my cart estimated shipping cost should be :shippingTotal
|
||||
*/
|
||||
public function myCartShippingFeeShouldBe($shippingTotal = '$0.00')
|
||||
public function myCartShippingFeeShouldBe(string $shippingTotal = '$0.00'): void
|
||||
{
|
||||
$this->summaryPage->open();
|
||||
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ final class LoginContext implements Context
|
|||
*/
|
||||
public function iShouldBeNotifiedAboutDisabledAccount(): void
|
||||
{
|
||||
Assert::true($this->loginPage->hasValidationErrorWith('Error Account is disabled.'));
|
||||
Assert::true($this->loginPage->hasValidationErrorWith('Error Invalid credentials.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -274,6 +274,30 @@ final class ProductContext implements Context
|
|||
Assert::false($this->indexPage->isProductOnList($productName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see in taxon :taxon in the store products :firstProductName and :secondProductName
|
||||
*/
|
||||
public function iShouldSeeInTaxonInTheStoreProducts(TaxonInterface $taxon, string ...$productNames): void
|
||||
{
|
||||
$this->iCheckListOfProductsForTaxon($taxon);
|
||||
|
||||
foreach ($productNames as $productName) {
|
||||
Assert::true($this->indexPage->isProductOnList($productName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not see in taxon :taxon in the store products :firstProductName and :secondProductName
|
||||
*/
|
||||
public function iShouldNotSeeInTaxonInTheStoreProducts(TaxonInterface $taxon, string ...$productNames): void
|
||||
{
|
||||
$this->iCheckListOfProductsForTaxon($taxon);
|
||||
|
||||
foreach ($productNames as $productName) {
|
||||
Assert::false($this->indexPage->isProductOnList($productName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should see empty list of products
|
||||
*/
|
||||
|
|
@ -327,9 +351,9 @@ final class ProductContext implements Context
|
|||
}
|
||||
|
||||
/**
|
||||
* @When I set its :optionName to :optionValue
|
||||
* @When I select its :optionName as :optionValue
|
||||
*/
|
||||
public function iSetItsOptionTo($optionName, $optionValue)
|
||||
public function iSelectItsOptionAs(string $optionName, string $optionValue): void
|
||||
{
|
||||
$this->showPage->selectOption($optionName, $optionValue);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ class RegistrationContext implements Context
|
|||
{
|
||||
$this->iLogInAsWithPassword($email, $password);
|
||||
|
||||
Assert::true($this->loginPage->hasValidationErrorWith('Error Account is disabled.'));
|
||||
Assert::true($this->loginPage->hasValidationErrorWith('Error Invalid credentials.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -69,6 +69,11 @@ class DashboardPage extends SymfonyPage implements DashboardPageInterface
|
|||
return trim($this->getElement('sub_header')->getText());
|
||||
}
|
||||
|
||||
public function isSectionWithLabelVisible(string $name): bool
|
||||
{
|
||||
return $this->getElement('admin_menu')->find('css', sprintf('div:contains(%s)', $name)) !== null;
|
||||
}
|
||||
|
||||
public function logOut(): void
|
||||
{
|
||||
$this->getElement('logout')->click();
|
||||
|
|
@ -97,6 +102,7 @@ class DashboardPage extends SymfonyPage implements DashboardPageInterface
|
|||
'total_sales' => '#total-sales',
|
||||
'sub_header' => '.ui.header .content .sub.header',
|
||||
'channel_choosing_link' => 'a:contains("%channelName%")',
|
||||
'admin_menu' => '.sylius-admin-menu',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue