diff --git a/CHANGELOG.md b/CHANGELOG.md index 22446a092b..c401c5a157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Release Notes for Craft Commerce +## Unreleased + +- Fixed a bug where variant indexes weren’t displaying promotion prices as currency values. +- Fixed a PHP error that could occur when sending an order email. ([#3596](https://github.com/craftcms/commerce/issues/3596)) +- Fixed a bug where dimension fields were not displaying values in the correct formatting locale. ([#3636](https://github.com/craftcms/commerce/issues/3636)) +- Fixed a bug where users couldn’t access catalog pricing rules when the current user had permission. ([#3639](https://github.com/craftcms/commerce/issues/3639)) +- Fixed a bug where available shipping methods were not returned in order of price. ([#3631](https://github.com/craftcms/commerce/issues/3631)) + ## 5.1.0-beta.2 - 2024-08-16 - Fixed a bug where it wasn’t possible to select shipping and tax categories for custom line items on the Edit Order page. @@ -75,6 +83,10 @@ ### System - Craft Commerce now requires Craft CMS 5.2 or later. +## 5.0.16.2 - 2024-08-16 + +- Fixed a bug where variants’ `sku` values could be cleared out when saving a product revision. + ## 5.0.16.1 - 2024-08-16 - Fixed a bug where variants’ `sku` values could be cleared out when saving a product. diff --git a/src/base/Purchasable.php b/src/base/Purchasable.php index 52fbbeb1dd..fff94221b4 100644 --- a/src/base/Purchasable.php +++ b/src/base/Purchasable.php @@ -14,6 +14,7 @@ use craft\commerce\elements\Order; use craft\commerce\errors\StoreNotFoundException; use craft\commerce\helpers\Currency; +use craft\commerce\helpers\Localization; use craft\commerce\helpers\Purchasable as PurchasableHelper; use craft\commerce\models\InventoryItem; use craft\commerce\models\InventoryLevel; @@ -292,6 +293,34 @@ public function currencyAttributes(): array ]; } + /** + * @inheritdoc + */ + public function setAttributesFromRequest(array $values): void + { + $length = ArrayHelper::remove($values, 'length'); + if ($length !== null) { + $this->length = $length ? (float)Localization::normalizeNumber($length) : null; + } + + $width = ArrayHelper::remove($values, 'width'); + if ($width !== null) { + $this->width = $width ? (float)Localization::normalizeNumber($width) : null; + } + + $height = ArrayHelper::remove($values, 'height'); + if ($height !== null) { + $this->height = $height ? (float)Localization::normalizeNumber($height) : null; + } + + $weight = ArrayHelper::remove($values, 'weight'); + if ($weight !== null) { + $this->weight = $weight ? (float)Localization::normalizeNumber($weight) : null; + } + + $this->setAttributes($values); + } + /** * @inheritdoc */ @@ -927,7 +956,7 @@ public function afterSave(bool $isNew): void $isOwnerDraftApplying = $owner && $owner->getIsCanonical() && $owner->duplicateOf !== null && $owner->duplicateOf->getIsDraft(); } - if ($this->duplicateOf !== null && !$isOwnerDraftApplying) { + if ($this->duplicateOf !== null && !$this->getIsRevision() && !$isOwnerDraftApplying) { $this->sku = PurchasableHelper::tempSku() . '-' . $this->getSku(); // Nullify inventory item so a new one is created $this->inventoryItemId = null; @@ -1188,10 +1217,10 @@ protected function attributeHtml(string $attribute): string 'sku' => (string)Html::encode($this->getSkuAsText()), 'price' => $this->basePriceAsCurrency, 'promotionalPrice' => $this->basePromotionalPriceAsCurrency, - 'weight' => $this->weight !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->weightUnits : '', - 'length' => $this->length !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', - 'width' => $this->width !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', - 'height' => $this->height !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', + 'weight' => $this->weight !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->weightUnits : '', + 'length' => $this->length !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', + 'width' => $this->width !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', + 'height' => $this->height !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits : '', 'minQty' => (string)$this->minQty, 'maxQty' => (string)$this->maxQty, 'stock' => $stock, diff --git a/src/elements/Product.php b/src/elements/Product.php index f8617363df..0e3ce31183 100644 --- a/src/elements/Product.php +++ b/src/elements/Product.php @@ -1576,7 +1576,7 @@ protected function attributeHtml(string $attribute): string case 'defaultWeight': { if ($productType->hasDimensions) { - return Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->weightUnits; + return Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->weightUnits; } return ''; @@ -1586,7 +1586,7 @@ protected function attributeHtml(string $attribute): string case 'defaultHeight': { if ($productType->hasDimensions) { - return Craft::$app->getLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits; + return Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($this->$attribute) . ' ' . Plugin::getInstance()->getSettings()->dimensionUnits; } return ''; diff --git a/src/fieldlayoutelements/PurchasableDimensionsField.php b/src/fieldlayoutelements/PurchasableDimensionsField.php index 282a9d1096..af645c9b2a 100644 --- a/src/fieldlayoutelements/PurchasableDimensionsField.php +++ b/src/fieldlayoutelements/PurchasableDimensionsField.php @@ -73,7 +73,7 @@ public function inputHtml(ElementInterface $element = null, bool $static = false Cp::fieldHtml(Cp::textHtml([ 'id' => 'length', 'name' => 'length', - 'value' => $element->length !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($element->length) : '', + 'value' => $element->length !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($element->length) : '', 'class' => 'text', 'size' => 10, 'unit' => Plugin::getInstance()->getSettings()->dimensionUnits, @@ -81,7 +81,7 @@ public function inputHtml(ElementInterface $element = null, bool $static = false Cp::fieldHtml(Cp::textHtml([ 'id' => 'width', 'name' => 'width', - 'value' => $element->width !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($element->width) : '', + 'value' => $element->width !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($element->width) : '', 'class' => 'text', 'size' => 10, 'unit' => Plugin::getInstance()->getSettings()->dimensionUnits, @@ -89,7 +89,7 @@ public function inputHtml(ElementInterface $element = null, bool $static = false Cp::fieldHtml(Cp::textHtml([ 'id' => 'height', 'name' => 'height', - 'value' => $element->height !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($element->height) : '', + 'value' => $element->height !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($element->height) : '', 'class' => 'text', 'size' => 10, 'unit' => Plugin::getInstance()->getSettings()->dimensionUnits, diff --git a/src/fieldlayoutelements/PurchasableWeightField.php b/src/fieldlayoutelements/PurchasableWeightField.php index 42db333672..94eec2eaf0 100755 --- a/src/fieldlayoutelements/PurchasableWeightField.php +++ b/src/fieldlayoutelements/PurchasableWeightField.php @@ -71,7 +71,7 @@ public function inputHtml(ElementInterface $element = null, bool $static = false return Cp::textHtml([ 'id' => 'weight', 'name' => 'weight', - 'value' => $element->weight !== null ? Craft::$app->getLocale()->getFormatter()->asDecimal($element->weight) : '', + 'value' => $element->weight !== null ? Craft::$app->getFormattingLocale()->getFormatter()->asDecimal($element->weight) : '', 'class' => 'text', 'size' => 10, 'unit' => Plugin::getInstance()->getSettings()->weightUnits, diff --git a/src/models/Email.php b/src/models/Email.php index 9ab616a8fb..210b23ea18 100644 --- a/src/models/Email.php +++ b/src/models/Email.php @@ -227,7 +227,7 @@ public function getSenderAddress(bool $parse = true): ?string } if (!$senderAddress = App::parseEnv($this->_senderAddress)) { - $senderAddress = App::mailSettings()->fromEmail; + $senderAddress = App::parseEnv(App::mailSettings()->fromEmail); } return $senderAddress; @@ -258,7 +258,7 @@ public function getSenderName(bool $parse = true): ?string } if (!$senderName = App::parseEnv($this->_senderName)) { - $senderName = App::mailSettings()->fromName; + $senderName = App::parseEnv(App::mailSettings()->fromName); } return $senderName; diff --git a/src/services/Pdfs.php b/src/services/Pdfs.php index 53270139f5..86875b8ab6 100644 --- a/src/services/Pdfs.php +++ b/src/services/Pdfs.php @@ -106,7 +106,7 @@ class Pdfs extends Component public const EVENT_AFTER_SAVE_PDF = 'afterSavePdf'; /** - * @event PdfEvent The event that is triggered before an order’s PDF is rendered. + * @event PdfRenderEvent The event that is triggered before an order’s PDF is rendered. * * Event handlers can customize PDF rendering by modifying several properties on the event object: * @@ -136,7 +136,7 @@ class Pdfs extends Component public const EVENT_BEFORE_RENDER_PDF = 'beforeRenderPdf'; /** - * @event PdfEvent The event that is triggered after an order’s PDF has been rendered. + * @event PdfRenderEvent The event that is triggered after an order’s PDF has been rendered. * * Event handlers can override Commerce’s PDF generation by setting the `pdf` property on the event to a custom-rendered PDF string. The event properties will be the same as those from `beforeRenderPdf`, but `pdf` will contain a rendered PDF string and is the only one for which setting a value will make any difference for the resulting PDF output. * diff --git a/src/services/ShippingMethods.php b/src/services/ShippingMethods.php index aba59bf161..13f3132fc7 100644 --- a/src/services/ShippingMethods.php +++ b/src/services/ShippingMethods.php @@ -145,7 +145,7 @@ public function getMatchingShippingMethods(Order $order): array // Sort by price. Using the cached price and don't call `$method->getPriceForOrder($order);` again. uasort($matchingMethods, static function($a, $b) { - return ($a['price'] < $b['price']) ? -1 : 1; + return $a['price'] <=> $b['price']; }); $shippingMethods = []; diff --git a/src/templates/store-management/pricing-rules/index.twig b/src/templates/store-management/pricing-rules/index.twig index 4239af8488..de5136b733 100644 --- a/src/templates/store-management/pricing-rules/index.twig +++ b/src/templates/store-management/pricing-rules/index.twig @@ -16,7 +16,7 @@ ]) %} {% block actionButton %} - {% if currentUser.can('commerce-createPricingCatalogRules') %} + {% if currentUser.can('commerce-createCatalogPricingRules') %} {{ 'New catalog pricing rule'|t('commerce') }} {% endif %} {% endblock %} @@ -57,7 +57,7 @@ {% js %} var actions = [ - {% if currentUser.can('commerce-editPricingCatalogRules') %} + {% if currentUser.can('commerce-editCatalogPricingRules') %} { label: Craft.t('commerce', 'Set status'), actions: [ @@ -78,7 +78,7 @@ var actions = [ ] }, {% endif %} - {% if currentUser.can('commerce-deletePricingCatalogRules') %} + {% if currentUser.can('commerce-deleteCatalogPricingRules') %} { label: Craft.t('commerce', 'Delete'), action: 'commerce/catalog-pricing-rules/delete', @@ -106,7 +106,7 @@ new Craft.VueAdminTable({ columns: columns, fullPane: false, container: '#pcr-vue-admin-table', - deleteAction: {{ currentUser.can('commerce-deletePricingCatalogRules')? '"commerce/catalog-pricing-rules/delete"' : 'null' }}, + deleteAction: {{ currentUser.can('commerce-deleteCatalogPricingRules')? '"commerce/catalog-pricing-rules/delete"' : 'null' }}, emptyMessage: Craft.t('commerce', 'No catalog pricing rules exist yet.'), padded: true, tableData: {{ tableData|json_encode|raw }}