+ {% block sw_settings_shipping_detail_advanced_prices_empty_state %}
+
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card %}
+
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_toolbar %}
+
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_rule_selection %}
+
+
+
+ {{ item.name }}
+
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_action_delete %}
+
+
+ {{ $tc('sw-settings-shipping.priceRules.buttonPriceRuleDelete') }}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_action_duplicate %}
+
+
+ {{ $tc('sw-settings-shipping.priceRules.buttonPriceRuleDuplicate') }}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_action_currency %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_action_currency_button %}
+
+
+ {{ $tc('sw-settings-shipping.priceRules.buttonPriceRuleCurrencyAdd') }}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_card_action_currency_menu %}
+
+ {{ currency.symbol }}
+ {{ currency.name }}
+ {{ (currency.isDefault) ? $tc('sw-settings-shipping.priceRules.textCurrencyDefault') : '' }}
+
+ {% endblock %}
+
+ {% endblock %}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_field_calculation %}
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix %}
+
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_title %}
+
+ {{ $tc('sw-settings-shipping.priceRules.textPriceRuleForCurrency') }}:
+ {{ currencyRule.currency.name }} {{ (currencyRule.currency.isDefault) ?
+ $tc('sw-settings-shipping.priceRules.textCurrencyDefault') : '' }}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid %}
+
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_columns %}
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_quantity_start %}
+
+
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_quantity_end %}
+
+
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_price %}
+
+
+
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_actions %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_actions_button %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_actions_duplicate %}
+
+ {{ $tc('sw-settings-shipping.priceRules.contextMenuDuplicate') }}
+
+ {% endblock %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_price_matrix_grid_actions_delete %}
+
+ {{ $tc('sw-settings-shipping.priceRules.contextMenuDelete') }}
+
+ {% endblock %}
+
+ {% endblock %}
+
+ {% endblock %}
+ {% endblock %}
+
+
+ {% endblock %}
+
+ {% endblock %}
+
{% endblock %}
- {% block sw_settings_shipping_detail_advanced_prices_field_price_table %}
-
-
- {% block sw_settings_shipping_detail_advanced_prices_field_table_quantity_start %}
-
-
-
-
- {% endblock %}
-
- {% block sw_settings_shipping_detail_advanced_prices_field_table_quantity_to %}
-
-
-
-
- {% endblock %}
-
- {% block sw_settings_shipping_detail_advanced_prices_field_table_price %}
-
-
-
- {% endblock %}
-
- {% block sw_settings_shipping_detail_advanced_prices_field_table_factor %}
-
-
-
- {% endblock %}
-
-
+ {% block sw_settings_shipping_detail_advanced_prices_actions %}
+
+ {% block sw_settings_shipping_detail_advanced_prices_actions_add_button %}
+
+ {{ $tc('sw-settings-shipping.priceRules.buttonAddAdditionalPriceRule') }}
+
+ {% endblock %}
+
{% endblock %}
-
+
{% endblock %}
diff --git a/src/Administration/Resources/administration/src/module/sw-settings-shipping/view/sw-settings-shipping-detail-advanced-prices/sw-settings-shipping-detail-advanced-prices.scss b/src/Administration/Resources/administration/src/module/sw-settings-shipping/view/sw-settings-shipping-detail-advanced-prices/sw-settings-shipping-detail-advanced-prices.scss
new file mode 100644
index 00000000000..5f94b66538c
--- /dev/null
+++ b/src/Administration/Resources/administration/src/module/sw-settings-shipping/view/sw-settings-shipping-detail-advanced-prices/sw-settings-shipping-detail-advanced-prices.scss
@@ -0,0 +1,33 @@
+.sw-settings-shipping-detail-advanced-prices {
+ .sw-settings-shipping-detail-advanced-prices__toolbar {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(200px, auto));
+ grid-gap: 10px 20px;
+ margin-bottom: 30px;
+
+ .sw-select__inner {
+ padding: 6px 50px 0 6px;
+ }
+
+ .sw-context-button {
+ .sw-button {
+ width: 100%;
+ height: 100%;
+ }
+ }
+ }
+
+ .sw-settings-shipping-detail-advanced-prices__prices {
+ margin-top: 30px;
+ }
+
+ .sw-settings-shipping-detail-advanced-prices__actions {
+ max-width: 800px;
+ margin: 40px auto;
+ display: grid;
+ grid-auto-flow: column;
+ justify-content: center;
+ justify-items: center;
+ align-items: center;
+ }
+}
diff --git a/src/Administration/Resources/e2e/repos/administration/page-objects/module/sw-shipping-method.page-object.js b/src/Administration/Resources/e2e/repos/administration/page-objects/module/sw-shipping-method.page-object.js
index 104dd4b0b20..ef9f5dffe24 100644
--- a/src/Administration/Resources/e2e/repos/administration/page-objects/module/sw-shipping-method.page-object.js
+++ b/src/Administration/Resources/e2e/repos/administration/page-objects/module/sw-shipping-method.page-object.js
@@ -10,7 +10,6 @@ class ShippingMethodPageObject extends GeneralPageObject {
shippingSaveAction: '.sw-settings-shipping-method-detail__save-action',
shippingBackToListViewAction: '.sw-icon.icon--default-action-settings.sw-icon--small'
}
-
};
}
@@ -26,6 +25,25 @@ class ShippingMethodPageObject extends GeneralPageObject {
.checkNotification(`Shipping rate "${name}" has been saved successfully.`);
}
+ createShippingMethodPriceRule(name) {
+ this.browser
+ .click('.sw-shipping-detail-page__price-settings')
+ .waitForElementVisible('.context-prices__actions button')
+ .click('.context-prices__actions button')
+ .click('.context-prices__rule')
+ .waitForElementVisible('.sw-select__results-list')
+ .click('.sw-select-option--0')
+ .expect.element('.sw-card__title').to.have.text.that.contains('Ruler');
+
+ this.browser
+ .waitForElementVisible('.context-prices__prices')
+ .fillField(`${this.elements.gridRow}--0 input[name=sw-field--item-quantityEnd]`, '20')
+ .fillField(`${this.elements.gridRow}--0 input[name=sw-field--item-price]`, '10')
+ .fillField(`${this.elements.gridRow}--1 input[name=sw-field--item-price]`, '8')
+ .click(this.elements.shippingSaveAction)
+ .checkNotification(`Shipping rate "${name}" has been saved successfully.`);
+ }
+
moveToListViewFromDetail() {
this.browser
.click(this.elements.shippingBackToListViewAction)
diff --git a/src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit.spec.js b/src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit-price-rules.spec.js
similarity index 50%
rename from src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit.spec.js
rename to src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit-price-rules.spec.js
index fc6dce96996..cb6e5b494c2 100644
--- a/src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit.spec.js
+++ b/src/Administration/Resources/e2e/repos/administration/specs/settings/shipping-method/shipping-method-edit-price-rules.spec.js
@@ -3,8 +3,13 @@ const shippingMethodPage = require('administration/page-objects/module/sw-shippi
const shippingMethodName = 'automated test shipping';
module.exports = {
- '@tags': ['settings', 'shipping-method', 'shipping-method-edit', 'edit'],
+ '@tags': ['settings', 'shipping-method', 'shipping-method-edit', 'edit', 'price-rule'],
'@disabled': !global.flags.isActive('next688'),
+ before: (browser, done) => {
+ global.AdminFixtureService.create('rule').then(() => {
+ done();
+ });
+ },
'navigate to shipping page': browser => {
browser
.openMainMenuEntry({
@@ -32,5 +37,29 @@ module.exports = {
.refresh()
.waitForElementVisible('textarea[name=sw-field--shippingMethod-description]')
.expect.element('textarea[name=sw-field--shippingMethod-description]').to.have.value.that.contains('Lorem ipsum');
+ },
+ 'create shippingMethod price rule': browser => {
+ const page = shippingMethodPage(browser);
+ page.createShippingMethodPriceRule(shippingMethodName);
+ },
+ 'edit shippingMethod price rule': browser => {
+ const page = shippingMethodPage(browser);
+ browser
+ .click('div[name=calculation]')
+ .waitForElementVisible('.sw-select__results-list')
+ .click('.sw-select__results-list .sw-select-option--1')
+ .clearValue(`.context-prices__prices ${page.elements.gridRow}--1 input[name=sw-field--item-price]`)
+ .fillField(`.context-prices__prices ${page.elements.gridRow}--1 input[name=sw-field--item-price]`, '9')
+ .click(page.elements.shippingSaveAction)
+ .checkNotification(`Shipping rate "${shippingMethodName}" has been saved successfully.`);
+ },
+ 'delete shippingMethod price rule': browser => {
+ const page = shippingMethodPage(browser);
+
+ browser
+ .clickContextMenuItem('.sw-context-menu-item--danger', `${page.elements.gridRow}--1 ${page.elements.contextMenuButton}`)
+ .assert.elementNotPresent(`${page.elements.gridRow}--1`)
+ .click('.sw-settings-shipping-detail__delete-action')
+ .assert.elementNotPresent('.context-price');
}
};
diff --git a/src/Core/Checkout/Cart/Delivery/DeliveryCalculator.php b/src/Core/Checkout/Cart/Delivery/DeliveryCalculator.php
index 7eefe6857db..9dddfe56a7e 100644
--- a/src/Core/Checkout/Cart/Delivery/DeliveryCalculator.php
+++ b/src/Core/Checkout/Cart/Delivery/DeliveryCalculator.php
@@ -2,7 +2,6 @@
namespace Shopware\Core\Checkout\Cart\Delivery;
-use Doctrine\DBAL\Connection;
use Shopware\Core\Checkout\Cart\Delivery\Struct\Delivery;
use Shopware\Core\Checkout\Cart\Delivery\Struct\DeliveryCollection;
use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
@@ -11,24 +10,15 @@
use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
use Shopware\Core\Checkout\Cart\Tax\PercentageTaxRuleBuilder;
use Shopware\Core\Checkout\CheckoutContext;
-use Shopware\Core\Checkout\Shipping\ShippingMethodEntity;
-use Shopware\Core\Framework\Context;
-use Shopware\Core\Framework\Struct\Uuid;
+use Shopware\Core\Checkout\Shipping\Aggregate\ShippingMethodPriceRule\ShippingMethodPriceRuleEntity;
class DeliveryCalculator
{
- public const CALCULATION_BY_WEIGHT = 0;
+ public const CALCULATION_BY_LINE_ITEM_COUNT = 1;
- public const CALCULATION_BY_PRICE = 1;
+ public const CALCULATION_BY_PRICE = 2;
- public const CALCULATION_BY_LINE_ITEM_COUNT = 2;
-
- public const CALCULATION_BY_CUSTOM = 3;
-
- /**
- * @var Connection
- */
- private $connection;
+ public const CALCULATION_BY_WEIGHT = 3;
/**
* @var QuantityPriceCalculator
@@ -41,11 +31,9 @@ class DeliveryCalculator
private $percentageTaxRuleBuilder;
public function __construct(
- Connection $connection,
QuantityPriceCalculator $priceCalculator,
PercentageTaxRuleBuilder $percentageTaxRuleBuilder
) {
- $this->connection = $connection;
$this->priceCalculator = $priceCalculator;
$this->percentageTaxRuleBuilder = $percentageTaxRuleBuilder;
}
@@ -59,6 +47,7 @@ public function calculate(DeliveryCollection $deliveries, CheckoutContext $conte
private function calculateDelivery(Delivery $delivery, CheckoutContext $context): void
{
+ $costs = null;
if ($delivery->getShippingCosts()->getUnitPrice() > 0) {
$costs = $this->calculateShippingCosts(
$delivery->getShippingCosts()->getTotalPrice(),
@@ -71,56 +60,52 @@ private function calculateDelivery(Delivery $delivery, CheckoutContext $context)
return;
}
- switch ($delivery->getShippingMethod()->getCalculation()) {
- case self::CALCULATION_BY_WEIGHT:
- $costs = $this->calculateShippingCosts(
- $this->findShippingCosts(
- $delivery->getShippingMethod(),
- $delivery->getPositions()->getWeight(),
- $context->getContext()
- ),
- $delivery->getPositions()->getLineItems(),
- $context
- );
+ foreach ($delivery->getShippingMethod()->getPriceRules() as $priceRule) {
+ // TODO: Ticket number: NEXT-2360, Price rules shouldn't be loaded in general (access price rules different at this point)
+ if (!in_array($priceRule->getRuleId(), $context->getRuleIds(), true)) {
+ continue;
+ }
- break;
- case self::CALCULATION_BY_PRICE:
- $costs = $this->calculateShippingCosts(
- $this->findShippingCosts(
- $delivery->getShippingMethod(),
- $delivery->getPositions()->getPrices()->sum()->getTotalPrice(),
- $context->getContext()
- ),
- $delivery->getPositions()->getLineItems(),
- $context
- );
+ if (!$this->matchesQuantity($delivery, $priceRule)) {
+ continue;
+ }
- break;
+ $costs = $this->calculateShippingCosts(
+ $priceRule->getPrice(),
+ $delivery->getPositions()->getLineItems(),
+ $context
+ );
+ break;
+ }
+
+ if (!$costs) {
+ return;
+ }
+ $delivery->setShippingCosts($costs);
+ }
+
+ private function matchesQuantity(Delivery $delivery, ShippingMethodPriceRuleEntity $shippingMethodPriceRule): bool
+ {
+ $start = $shippingMethodPriceRule->getQuantityStart();
+ $end = $shippingMethodPriceRule->getQuantityEnd();
+
+ switch ($shippingMethodPriceRule->getCalculation()) {
+ case self::CALCULATION_BY_PRICE:
+ $value = $delivery->getPositions()->getPrices()->sum()->getTotalPrice();
+ break;
case self::CALCULATION_BY_LINE_ITEM_COUNT:
- $costs = $this->calculateShippingCosts(
- $this->findShippingCosts(
- $delivery->getShippingMethod(),
- $delivery->getPositions()->getQuantity(),
- $context->getContext()
- ),
- $delivery->getPositions()->getLineItems(),
- $context
- );
+ $value = $delivery->getPositions()->getQuantity();
+ break;
+ case self::CALCULATION_BY_WEIGHT:
+ $value = $delivery->getPositions()->getWeight();
break;
-
- case self::CALCULATION_BY_CUSTOM:
- return;
default:
- $price = $delivery->getPositions()->getLineItems()->getPrices()->sum()->getTotalPrice() / 100;
- $costs = $this->calculateShippingCosts(
- $price,
- $delivery->getPositions()->getLineItems(),
- $context
- );
+ $value = $delivery->getPositions()->getLineItems()->getPrices()->sum()->getTotalPrice() / 100;
+ break;
}
- $delivery->setShippingCosts($costs);
+ return ($value >= $start) && (!$end || $value <= $end);
}
private function calculateShippingCosts(float $price, LineItemCollection $calculatedLineItems, CheckoutContext $context): CalculatedPrice
@@ -133,19 +118,4 @@ private function calculateShippingCosts(float $price, LineItemCollection $calcul
return $this->priceCalculator->calculate($definition, $context);
}
-
- private function findShippingCosts(ShippingMethodEntity $shippingMethod, float $value, Context $context): float
- {
- $query = $this->connection->createQueryBuilder();
- $query->select('costs.price');
- $query->from('shipping_method_price', 'costs');
- $query->andWhere('costs.`quantity_from` <= :value');
- $query->andWhere('costs.shipping_method_id = :id');
- $query->setParameter('id', Uuid::fromHexToBytes($shippingMethod->getId()));
- $query->setParameter('value', $value);
- $query->addOrderBy('price', 'DESC');
- $query->setMaxResults(1);
-
- return (float) $query->execute()->fetchColumn();
- }
}
diff --git a/src/Core/Checkout/DependencyInjection/cart.xml b/src/Core/Checkout/DependencyInjection/cart.xml
index f21527e4fb3..fca4ccfdbf3 100644
--- a/src/Core/Checkout/DependencyInjection/cart.xml
+++ b/src/Core/Checkout/DependencyInjection/cart.xml
@@ -84,7 +84,6 @@