From e542265d0badc404cd68078d27f6b7eeca93d0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Noco=C5=84?= Date: Thu, 16 Oct 2025 01:20:38 +0200 Subject: [PATCH 1/2] [WIP] Current status --- code_samples/discounts/config/services.yaml | 29 ++++ .../PurchaseParityValueFormatter.php | 17 ++ docs/discounts/discounts.md | 3 +- docs/discounts/extend_discounts.md | 152 ++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 code_samples/discounts/config/services.yaml create mode 100644 code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php create mode 100644 docs/discounts/extend_discounts.md diff --git a/code_samples/discounts/config/services.yaml b/code_samples/discounts/config/services.yaml new file mode 100644 index 0000000000..0706a557c9 --- /dev/null +++ b/code_samples/discounts/config/services.yaml @@ -0,0 +1,29 @@ +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration +parameters: + +services: + # default configuration for services in *this* file + _defaults: + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. + + # makes classes in src/ available to be used as services + # this creates a service per class whose id is the fully-qualified class name + App\: + resource: '../src/' + exclude: + - '../src/DependencyInjection/' + - '../src/Entity/' + - '../src/Kernel.php' + + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones + + App\Discounts\CustomDiscountValueFormatter: + tags: + - name: ibexa.discounts.value.formatter + rule_type: 'referral_rule' diff --git a/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php b/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php new file mode 100644 index 0000000000..79049bffb5 --- /dev/null +++ b/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php @@ -0,0 +1,17 @@ +`is_product_in_product_codes()` | `true/false`, depending if the product is part of the given list.| Conditions, rules | +| Variable | `cart` | [Cart object](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Cart-Value-CartInterface.html) associated with current context.| Conditions, rules | +| Variable | `currency` | [Currency object](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-CurrencyInterface.html) of the current siteaccess. | Conditions, rules | +| Variable | `customer_group` | [Customer group object](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-CustomerGroupInterface.html) associated with given price context or the current user.| Conditions, rules | +| Variable | `amount` | Original price of the product | Rules | +| Variable | `product` | [Product object](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductInterface.html)| Rules | + +### Custom expressions + +You can create your own variables and functions to make creating the conditions easier. +To create the condition checking the registration date, the following example will use an additinal variable and a function: + +- `current_user`, a variable with the current [User object](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Core-Repository-Values-User-User.html) + +To add it, create a class implementing the [`DiscountVariablesResolverInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-DiscountVariablesResolverInterface.html): + +``` php +todo: verify +``` + +And mark it as a service using the `ibexa.discounts.expression_language.variable_resolver` service tag: + +``` yaml +todo: verify +``` + +- `is_anniversary()`, a function returning a boolean value indicating if the two dates passed as arguments fall on the same day. + +``` php +todo: verify +``` + +Mark it as a service using the `ibexa.discounts.expression_language.function` service tag and specify the function name in the service definition. + +``` yaml +todo: verify +``` + +Two new expressions are now available for use in custom conditions and rules. + +### Implement custom condition + +Now, create the condition by creating a class implementing the [`DiscountConditionInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-Value-DiscountConditionInterface.html). + +``` php +todo: verify +``` + +The expression can evaluate to `true` or `false` depending on the custom expressions values. +An additional variable, `today`, is defined to store the current date for comparison. + +For each condition class you must create a dedicated condition factory, a class implementing the `\Ibexa\Discounts\Repository\DiscountCondition\DiscountConditionFactoryInterface` inteface. + +This allows you to create conditions when working in the context of the Symfony service container. + +``` php +todo +``` + +Mark it as a service using the `ibexa.discounts.condition.factory` service tag and specify the condition's identifier. + +``` yaml +todo +``` + +## Create custom rules + +To implement a custom rule, create a class implementing the [`DiscountRuleInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-Value-DiscountRuleInterface.html). + +The following example implements a [purchasing power parity discount](https://en.wikipedia.org/wiki/Purchasing_power_parity), adjusting product's price in the cart based on buyer's region. + +``` php +todo +``` + +As with conditions, create a dedicated rule factory. + +``` php +todo +``` + +Mark it as a service using the `ibexa.discounts.condition.factory` service tag and specify the rule's type. + +``` yaml +todo +``` + +### Custom discount formatting + +You can adjust how each discount type is displayed when using the [`ibexa_discounts_render_discount_badge` Twig function](discounts_twig_functions.md#ibexa_discounts_render_discount_badge) by implementing a custom formatter. + +To do it, create a class implementing the [`DiscountValueFormatterInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-DiscountValueFormatterInterface.html) and use the `ibexa.discounts.value.formatter` service tag: + +``` php +todo +``` + +``` yaml +todo +``` + +## Change discount priority + +You can change the [the defualt discount priority](discounts_guide.md#discounts-priority) by creating a class implementing the [`DiscountPrioritizationStrategyInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-Discounts-DiscountPrioritizationStrategyInterface.html) and aliasing to it the default implementation. + +The example below decorates the default implementation to prioritize recently created discounts above all the others. + +``` php +todo +``` + +``` yaml +todo +``` + +## Form integration + +### Condition + +### Rules diff --git a/mkdocs.yml b/mkdocs.yml index 68158e1d8b..31d1649fe4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -412,6 +412,7 @@ nav: - Install Discounts: discounts/install_discounts.md - Customize Discounts: discounts/configure_discounts.md - Discounts API: discounts/discounts_api.md + - Extend Discounts: discounts/extend_discounts.md - Customer management: - Customer Portal: customer_management/customer_portal.md - Customer Portal guide: customer_management/customer_portal_guide.md From d10add4d0fb2192e973422d5b7f766f7ca536ebd Mon Sep 17 00:00:00 2001 From: mnocon Date: Wed, 15 Oct 2025 23:35:55 +0000 Subject: [PATCH 2/2] PHP & JS CS Fixes --- .../discounts/src/Discounts/PurchaseParityValueFormatter.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php b/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php index 79049bffb5..a88ffceac5 100644 --- a/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php +++ b/code_samples/discounts/src/Discounts/PurchaseParityValueFormatter.php @@ -4,14 +4,13 @@ namespace App\Discounts; -use Ibexa\Contracts\Discounts\Value\DiscountInterface; use Ibexa\Contracts\Discounts\DiscountValueFormatterInterface; +use Ibexa\Contracts\Discounts\Value\DiscountInterface; use Money\Money; final class PurchaseParityValueFormatter implements DiscountValueFormatterInterface { public function format(DiscountInterface $discount, ?Money $money = null): string { - } }