Approval Process feature integration
Edit on GitHubInstall feature core
Prerequisites
To start feature integration, review and install the necessary features:
NAME | VERSION |
---|---|
Company Account | 202108.0 |
Shared Carts | 202108.0 |
Checkout | 202108.0 |
Spryker Core | 202108.0 |
1) Install the required modules using Composer
Run the following command to install the required modules:
composer require spryker-feature/approval-process:"202108.0" --update-with-dependencies
Make sure that the following modules were installed:
MODULE | EXPECTED DIRECTORY |
---|---|
QuoteApproval | vendor/spryker/quote-approval |
2) Set up configuration
Add the following configuration to your project:
src/Pyz/Shared/QuoteApproval/QuoteApprovalConfig.php
<?php
namespace Pyz\Shared\QuoteApproval;
use Generated\Shared\Transfer\QuoteTransfer;
use Spryker\Shared\QuoteApproval\QuoteApprovalConfig as SprykerQuoteApprovalConfig;
class QuoteApprovalConfig extends SprykerQuoteApprovalConfig
{
/**
* @return string[]
*/
public function getRequiredQuoteFieldsForApprovalProcess(): array
{
return [
QuoteTransfer::BILLING_ADDRESS,
QuoteTransfer::PAYMENT,
];
}
}
Make sure that the configuration returns the billing address and payment keys.
3) Set up database schema and transfer objects
Run the following commands to apply database changes and generate entity and transfer changes:
console transfer:generate
console propel:install
console transfer:generate
Make sure that the following changes were applied by checking your database:
DATABASE ENTITY | TYPE | EVENT |
---|---|---|
spy_quote_approval | table | created |
Make sure that the following changes were applied in transfer objects:
TRANSFER | TYPE | EVENT | PATH |
---|---|---|---|
QuoteTransfer.quoteApprovals | column | created | src/Generated/Shared/Transfer/QuoteTransfer |
QuoteActivationRequestTransfer | class | created | src/Generated/Shared/Transfer/QuoteApprovalTransfer |
QuoteApprovalRequestTransfer | class | created | src/Generated/Shared/Transfer/QuoteApprovalRequestTransfer |
QuoteApprovalResponseTransfer | class | created | src/Generated/Shared/Transfer/QuoteApprovalResponseTransfer |
QuoteApprovalCollectionTransfer | class | created | src/Generated/Shared/Transfer/QuoteApprovalResponseTransfer |
4) Add translations
Append glossary for the approval process feature:
src/data/import/glossary.csv
quote_approval.request.send,Send Request,en_US
quote_approval.request.send,Anfrage Senden,de_DE
quote_approval.remove,Cancel Request,en_US
quote_approval.remove,Anfrage Abbrechen,de_DE
quote_approval.cart.require_approval,"You can't place this order because of your purchasing limit, please send your cart for approval or contact your manager.",en_US
quote_approval.cart.require_approval,"Sie können diese Bestellung aufgrund Ihres Einkaufslimits nicht aufgeben. Senden Sie Ihren Einkaufswagen zur Genehmigung oder wenden Sie sich an Ihren Kontakmanager.",de_DE
quote_approval.cart.waiting_approval,"You can't place this order due to pending approval request.",en_US
quote_approval.cart.waiting_approval,"Sie können diese Bestellung aufgrund einer ausstehenden Genehmigungsanfrage nicht aufgeben.",de_DE
quote_approval.create.approver_cant_approve_quote,"Selected approver cannot approve your request due to approver limit.",en_US
quote_approval.create.approver_cant_approve_quote,"Der ausgewählte Manager kann Ihre Anfrage aufgrund des Genehmigungslimits nicht genehmigen.",de_DE
quote_approval.create.you_cant_approve_quote,"You can't approve or decline this cart because it's amount higher that your Approver limit.",en_US
quote_approval.create.you_cant_approve_quote,"Sie können diesen Einkaufswagen nicht genehmigen oder ablehnen, weil dessen Betrag höher als ihr Genehmigungslimit ist.",de_DE
quote_approval.create.quote_already_approved,"This Cart was already approved.",en_US
quote_approval.create.quote_already_approved,"Dieser Einkaufswagen wurde schon zur Genehmigung gesendet.",de_DE
quote_approval.create.quote_already_declined,"This Cart was already declined.",en_US
quote_approval.create.quote_already_declined,"Dieser Einkaufswagen wurde schon abgelehnt.",de_DE
quote_approval.create.quote_already_cancelled,"You can't work with this Cart it was already sent to another approver.",en_US
quote_approval.create.quote_already_cancelled,"Sie können nicht mit diesem Einkaufswagen arbeiten, er wurde schon dem anderen Manager gesendet.",de_DE
quote_approval.create.quote_already_waiting_for_approval,"This Cart was already sent for approval.",en_US
quote_approval.create.quote_already_waiting_for_approval,"",de_DE
quote_approval.create.only_quote_owner_can_send_request,"You can't sent Cart for Approval, only Cart owner can do it.",en_US
quote_approval.create.only_quote_owner_can_send_request,"Sie können den Einkaufswagen zur Genehmigung nicht senden, das kann nur Inhaber des Einkaufswagens machen.",de_DE
quote_approval.cancel.do_not_have_permission,"You don't have permissions to cancel Approval request.",en_US
quote_approval.cancel.do_not_have_permission,"Sie haben nicht die notwendigen Rechte um die Genehmigungsanfrage zu abbrechen.",de_DE
quote_approval.request.approval_by,by,en_US
quote_approval.request.approval_by,von,de_DE
quote_approval.created,"Your request for Approval was send to %first_name% %last_name%.",en_US
quote_approval.created,"Ihre Anfrage zur Genehmigung wurde an %first_name% %last_name% gesendet.",de_DE
quote_approval.removed,"Your request for Approval was canceled.",en_US
quote_approval.removed,"Ihre Genehmigungsanfrage wurde abgebrochen.",de_DE
quote_approval.request.waiting_for_approval_from,Waiting for Approval from,en_US
quote_approval.request.waiting_for_approval_from,Wartet auf die Genehmigung von,de_DE
quote_approval.request.approved_by,Approved by,en_US
quote_approval.request.approved_by,Genehmigt von,de_DE
quote_approval.request.declined_by,Declined by,en_US
quote_approval.request.declined_by,Abgelehnt um,de_DE
To import the glossary data, run the following console command:
console data:import glossary
Make sure that the configured data has been added to the spy_glossary
table in the database.
4) Set up behavior
Set up permission integration
Register the following plugins:
PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
---|---|---|---|
ApproveQuotePermissionPlugin | Checks if the customer can approve the quote in the client layer. | None | Spryker\Client\QuoteApproval\Plugin\Permission |
PlaceOrderPermissionPlugin | Checks if the customer can place an order in the client layer. | None | Spryker\Client\QuoteApproval\Plugin\Permission |
RequestQuoteApprovalPermissionPlugin | Checks if the customer can request for approval in the client layer. | None | Spryker\Client\QuoteApproval\Plugin\Permission |
ApproveQuotePermissionPlugin | Checks if the customer can approve quote approval in the Zed layer. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Permission |
PlaceOrderPermissionPlugin | Checks if the customer can place an order in the Zed layer. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Permission |
SanitizeQuoteApprovalQuoteLockPreResetPlugin | Allows complete removal of all the approval process-related data from the quote on cart lock reset. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Cart |
src/Pyz/Client/Permission/PermissionDependencyProvider.php
<?php
namespace Pyz\Client\Permission;
use Spryker\Client\Permission\PermissionDependencyProvider as SprykerPermissionDependencyProvider;
use Spryker\Client\QuoteApproval\Plugin\Permission\ApproveQuotePermissionPlugin;
use Spryker\Client\QuoteApproval\Plugin\Permission\PlaceOrderPermissionPlugin;
use Spryker\Client\QuoteApproval\Plugin\Permission\RequestQuoteApprovalPermissionPlugin;
class PermissionDependencyProvider extends SprykerPermissionDependencyProvider
{
/**
* @return \Spryker\Shared\PermissionExtension\Dependency\Plugin\PermissionPluginInterface[]
*/
protected function getPermissionPlugins(): array
{
return [
new RequestQuoteApprovalPermissionPlugin(),
new PlaceOrderPermissionPlugin(),
new ApproveQuotePermissionPlugin(),
];
}
}
src/Pyz/Zed/Permission/PermissionDependencyProvider.php
<?php
namespace Pyz\Zed\Permission;
use Spryker\Zed\Permission\PermissionDependencyProvider as SprykerPermissionDependencyProvider;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Permission\ApproveQuotePermissionPlugin;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Permission\PlaceOrderPermissionPlugin;
class PermissionDependencyProvider extends SprykerPermissionDependencyProvider
{
/**
* @return \Spryker\Shared\PermissionExtension\Dependency\Plugin\PermissionPluginInterface[]
*/
protected function getPermissionPlugins()
{
return [
new PlaceOrderPermissionPlugin(),
new ApproveQuotePermissionPlugin(),
];
}
}
Pyz\Zed\Cart\CartDependencyProvider.php
<?php
namespace Pyz\Zed\Cart;
use Spryker\Zed\Cart\CartDependencyProvider as SprykerCartDependencyProvider;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Cart\SanitizeQuoteApprovalQuoteLockPreResetPlugin;
class CartDependencyProvider extends SprykerCartDependencyProvider
{
/**
* @return \Spryker\Zed\CartExtension\Dependency\Plugin\QuotePreUnlockPluginInterface[]
*/
protected function getQuoteLockPreResetPlugins(): array
{
return [
new SanitizeQuoteApprovalQuoteLockPreResetPlugin(),
];
}
}
Check that the customer with the permission RequestQuoteApprovalPermission
can request for approval.
Check that the customer with the permission ApproveQuotePermission
can approve the request.
Check that the customer with the permission PlaceOrderPermissionPlugin
can place an order from the quote with the approved request for approval.
Check that when you reset the cart lock, all the approval process-related data is removed from the quote.
Set up quote integration
Register the following plugins:
PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
---|---|---|---|
QuoteApprovalExpanderPlugin | Expands the quote with the QuoteApproval data. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Quote |
RemoveQuoteApprovalsBeforeQuoteDeletePlugin | Removes quote approvals from the database before the quote deletion. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Quote |
QuoteApprovalQuoteFieldsAllowedForSavingProviderPlugin | Returns required quote fields from the configuration if the approval request is not canceled. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Quote |
src/Pyz/Zed/Quote/QuoteDependencyProvider.php
<?php
namespace Pyz\Zed\Quote;
use Spryker\Zed\Quote\QuoteDependencyProvider as SprykerQuoteDependencyProvider;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Quote\QuoteApprovalExpanderPlugin;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Quote\QuoteApprovalQuoteFieldsAllowedForSavingProviderPlugin;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Quote\RemoveQuoteApprovalsBeforeQuoteDeletePlugin;
class QuoteDependencyProvider extends SprykerQuoteDependencyProvider
{
/**
* @return \Spryker\Zed\QuoteExtension\Dependency\Plugin\QuoteWritePluginInterface[]
*/
protected function getQuoteDeleteBeforePlugins(): array
{
return [
new RemoveQuoteApprovalsBeforeQuoteDeletePlugin(),
];
}
/**
* @return \Spryker\Zed\QuoteExtension\Dependency\Plugin\QuoteExpanderPluginInterface[]
*/
protected function getQuoteExpanderPlugins(): array
{
return [
new QuoteApprovalExpanderPlugin(),
];
}
/**
* @return \Spryker\Zed\QuoteExtension\Dependency\Plugin\QuoteFieldsAllowedForSavingProviderPluginInterface[]
*/
protected function getQuoteFieldsAllowedForSavingProviderPlugins(): array
{
return [
new QuoteApprovalQuoteFieldsAllowedForSavingProviderPlugin(),
];
}
}
Make sure that the quote will be expanded with data from database table spy_quote_approval
on quote loading.
Make sure that the records from the database table spy_quote_approval
related to the quote will be removed before the quote deletion.
Make sure that the billing address and payment are saved with the quote in the spy_quote
table after sending an approval request.
Set up checkout integration
Register the following plugins:
PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
---|---|---|---|
QuoteApprovalCheckoutPreConditionPlugin | Checks if the quote is ready to checkout. | None | Spryker\Zed\QuoteApproval\Communication\Plugin\Checkout |
src/Pyz/Zed/Checkout/CheckoutDependencyProvider.php
<?php
namespace Pyz\Zed\Checkout;
use Spryker\Zed\Checkout\CheckoutDependencyProvider as SprykerCheckoutDependencyProvider;
use Spryker\Zed\QuoteApproval\Communication\Plugin\Checkout\QuoteApprovalCheckoutPreConditionPlugin;
class CheckoutDependencyProvider extends SprykerCheckoutDependencyProvider
{
/**
* @param \Spryker\Zed\Kernel\Container $container ’
*
* @return \Spryker\Zed\CheckoutExtension\Dependency\Plugin\CheckoutPreConditionPluginInterface[]
*/
protected function getCheckoutPreConditions(Container $container)
{
return [
new QuoteApprovalCheckoutPreConditionPlugin(),
];
}
}
Check that the customer without PlaceOrderPermission
cannot proceed to checkout.
Install feature frontend
Prerequisites
To start feature integration, review and install the necessary features:
NAME | VERSION |
---|---|
Cart | 202108.0 |
Checkout | 202108.0 |
Spryker Core | 202108.0 |
1) Install the required modules using Composer
Run the following command to install the required modules:
composer require spryker-feature/approval-process: "202108.0" --update-with-dependencies
Make sure that the following modules were installed:
MODULE | EXPECTED DIRECTORY |
---|---|
QuoteApprovalWidget | vendor/spryker-shop/quote-approval-widget |
2) Add translations
Append glossary according to your configuration:
src/data/import/glossary.csv
quote_approval_widget.title,Approval Request,en_US
quote_approval_widget.title,Genehmigungsanfrage,de_DE
quote_approval_widget.limit.unlimited,Unlimited,en_US
quote_approval_widget.limit.unlimited,Unbegrenzt,de_DE
quote_approval_widget.no_approvers_found,Keine Genehmiger gefunden.,de_DE
quote_approval_widget.no_approvers_found,No approvers found.,en_US
quote_approval_widget.cart.status.approved,"Approved",en_US
quote_approval_widget.cart.status.approved,"Genehmigt",de_DE
quote_approval_widget.cart.status.declined,"Declined",en_US
quote_approval_widget.cart.status.declined,"Abgelehnt",de_DE
quote_approval_widget.cart.status.waiting,"Waiting",en_US
quote_approval_widget.cart.status.waiting,"Wartet",de_DE
quote_approval_widget.shared_cart_warning,"After a cart has been sent to approval, all of its shares will be dismissed.",en_US
quote_approval_widget.shared_cart_warning,"Nachdem der Warenkorb zur Genehmigung gesendet wurde, wird sein Sharing aufgehoben.",de_DE
quote_approval_widget.limit_text,"Your purchase limit is %amount%. To spend more, request approval from your manager.",en_US
quote_approval_widget.limit_text,"Ihr Einkaufsrahmen liegt bei %amount%. Um mehr auszugeben, fordern Sie bitte die Genehmigung bei Ihrem Manager an",de_DE
quote_approval_widget.no_limit_text,"You do not have a purchase limit",en_US
quote_approval_widget.no_limit_text,"Sie haben kein Einkaufslimit",de_DE
quote_approval_widget.quote_not_applicable_for_approval_process,"This cart can't be processed. Required information is missing.",en_US
quote_approval_widget.quote_not_applicable_for_approval_process,Diese Anfrage kann nicht bearbeitet werden. Es fehlen erforderliche Informationen.,de_DE
quote_approval_widget.cart.status,"Status",en_US
quote_approval_widget.cart.status,"Status",de_DE
quote_approval_widget.cart.approve,"Approve",en_US
quote_approval_widget.cart.approve,"Genehmigen",de_DE
quote_approval_widget.cart.decline,"Decline",en_US
quote_approval_widget.cart.decline,"Ablehnen",de_DE
quote_approval_widget.cart.cancel,"Cancel",en_US
quote_approval_widget.cart.cancel,"Abbrechen",de_DE
quote_approval_widget.cart.success_message.approved,"Request from %first_name% %last_name% was successfully approved",en_US
quote_approval_widget.cart.success_message.approved,"Anfrage von %first_name% %last_name% wurde erfolgreich genehmigt",de_DE
quote_approval_widget.cart.success_message.declined,"Request from %first_name% %last_name% was successfully declined",en_US
quote_approval_widget.cart.success_message.declined,"Anfrage von %first_name% %last_name% wurde erfolgreich abgelehnt",de_DE
quote_approval_widget.cart.success_message.canceled,"Request from %first_name% %last_name% was successfully canceled",en_US
quote_approval_widget.cart.success_message.canceled,"Anfrage von %first_name% %last_name% wurde erfolgreich abgebrochen",de_DE
Run the following console command to import the glossary data:
console data:import glossary
Make sure that the configured data is added to the spy_glossary
table in the database.
3) Set up behavior
Set up permission integration
Register the following plugins:
PLUGIN | SPECIFICATION | PREREQUISITES | NAMESPACE |
---|---|---|---|
QuoteApprovalCheckerCheckoutAddressStepEnterPreCheckPlugin | Checks if the quote approval status is approved or waiting on the address step of checkout. | None | SprykerShop\Yves\QuoteApprovalWidget\Plugin\CheckoutPage |
QuoteApprovalCheckerCheckoutPaymentStepEnterPreCheckPlugin | Checks if the quote approval status is approved or waiting on the payment step of checkout. | None | SprykerShop\Yves\QuoteApprovalWidget\Plugin\CheckoutPage |
src/Pyz/Yves/CheckoutPage/CheckoutPageDependencyProvider.php
<?php
namespace Pyz\Yves\CheckoutPage;
use SprykerShop\Yves\CheckoutPage\CheckoutPageDependencyProvider as SprykerShopCheckoutPageDependencyProvider;
use SprykerShop\Yves\QuoteApprovalWidget\Plugin\CheckoutPage\QuoteApprovalCheckerCheckoutAddressStepEnterPreCheckPlugin;
use SprykerShop\Yves\QuoteApprovalWidget\Plugin\CheckoutPage\QuoteApprovalCheckerCheckoutPaymentStepEnterPreCheckPlugin;
/**
* @method \Pyz\Yves\CheckoutPage\CheckoutPageConfig getConfig()
*/
class CheckoutPageDependencyProvider extends SprykerShopCheckoutPageDependencyProvider
{
/**
* @return \SprykerShop\Yves\CheckoutPageExtension\Dependency\Plugin\CheckoutAddressStepEnterPreCheckPluginInterface[]
*/
protected function getCheckoutAddressStepEnterPreCheckPlugins(): array
{
return [
new QuoteApprovalCheckerCheckoutAddressStepEnterPreCheckPlugin(),
];
}
/**
* @return \SprykerShop\Yves\CheckoutPageExtension\Dependency\Plugin\CheckoutPaymentStepEnterPreCheckPluginInterface[]
*/
protected function getCheckoutPaymentStepEnterPreCheckPlugins(): array
{
return [
new QuoteApprovalCheckerCheckoutPaymentStepEnterPreCheckPlugin(),
];
}
}
Check that the customer with the sent approval request cannot open the address step on the cart page.
Check that the customer with the sent approval request cannot open the payment step on the cart page.
4) Set up widgets
Register the following global widgets:
WIDGET | DESCRIPTION | PREREQUISITES | NAMESPACE |
---|---|---|---|
QuoteApprovalStatusWidget | Adds a quote approval status for the multicart list in the header and on the multicart list page. | None | SprykerShop\Yves\QuoteApprovalWidget\Widget |
QuoteApprovalWidget | Adds an approve functionality to the Cart page. | None | SprykerShop\Yves\QuoteApprovalWidget\Widget |
QuoteApproveRequestWidget | Adds the request for quote approve functionality to the Cart page. | None | SprykerShop\Yves\QuoteApprovalWidget\Widget |
src/Pyz/Yves/ShopApplication/ShopApplicationDependencyProvider.php
<?php
namespace Pyz\Yves\ShopApplication;
use SprykerShop\Yves\QuoteApprovalWidget\Widget\QuoteApprovalStatusWidget;
use SprykerShop\Yves\QuoteApprovalWidget\Widget\QuoteApprovalWidget;
use SprykerShop\Yves\QuoteApprovalWidget\Widget\QuoteApproveRequestWidget;
use SprykerShop\Yves\ShopApplication\ShopApplicationDependencyProvider as SprykerShopApplicationDependencyProvider;
class ShopApplicationDependencyProvider extends SprykerShopApplicationDependencyProvider
{
/**
* @return string[]
*/
protected function getGlobalWidgets(): array
{
return [
QuoteApprovalStatusWidget::class,
QuoteApproveRequestWidget::class,
QuoteApprovalWidget::class,
];
}
}
Run the following command to enable the Javascript and CSS changes:
console frontend:yves:build
Make sure that the following plugin was registered:
- Open Yves and log in to the customer account.
- Open
https://mysprykershop.com/company/company-role/
and assignRequestQuoteApprovalPermission
,PlaceOrderPermission
,ApproveQuotePermission
permissions to any role related to the current customer. - Add the record to the
spy_quote_approval
for the current customer quote id and current customer company user as an approver.
MODULE | TEST |
---|---|
QuoteApprovalStatusWidget | Hover over the multicart list in the header: should contain quote approval status column. Open the https://mysprykershop.com/multi-cart/ , table should contain the quote approval status column. |
QuoteApproveRequestWidget | Open the https://mysprykershop.com/checkout/summary/ - should contain widget request for approval with list approvers. |
QuoteApprovalWidget | Open the https://mysprykershop.com/cart/ - should contain widget approver functionality with buttons to approve or decline. |
4) Enable controllers
Register the following plugin:
WIDGET | DESCRIPTION | PREREQUISITES | NAMESPACE |
---|---|---|---|
QuoteApprovalControllerProvider | Provides routes used in the QuoteApprovalWidget . |
None | SprykerShop\Yves\QuoteApprovalWidget\Plugin\Provider |
src/Pyz/Yves/ShopApplication/YvesBootstrap.php
<?php
namespace Pyz\Yves\ShopApplication;
use SprykerShop\Yves\QuoteApprovalWidget\Plugin\Provider\QuoteApprovalControllerProvider;
use SprykerShop\Yves\ShopApplication\YvesBootstrap as SprykerYvesBootstrap;
class YvesBootstrap extends SprykerYvesBootstrap
{
/**
* @param bool|null $isSsl
*
* @return \SprykerShop\Yves\ShopApplication\Plugin\Provider\AbstractYvesControllerProvider[]
*/
protected function getControllerProviderStack($isSsl)
{
return [
new QuoteApprovalControllerProvider($isSsl), #SharedCartFeature
];
}
}
Make sure that the following plugin was registered:
- Open Yves and log in to the customer account.
- Open
https://mysprykershop.com/company/company-role/
and assignRequestQuoteApprovalPermission
,PlaceOrderPermission
,ApproveQuotePermission
permissions to any role related to current customer. - Add the record to the
spy_quote_approval
for the current customer quote id and current customer company user as an approver. - Open
https://mysprykershop.com/cart/
- Click “Approve” button. Quote approval status should become approved and the “proceed to checkout” button must be displayed. Create a new quote with items. Openhttps://mysprykershop.com/cart/
- Click “Request for Approval” button. Quote approval status should become waiting and approver functionality must be shown.
Thank you!
For submitting the form