Skip to content

Commit

Permalink
Merge pull request #14148 from craftcms/feature/money-field-condition…
Browse files Browse the repository at this point in the history
…-rule

Update money condition rule to use money inputs
  • Loading branch information
brandonkelly authored Jan 16, 2024
2 parents e5b749c + 2014408 commit 53c6210
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 13 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Entries can now have multiple authors. ([#12380](https://github.com/craftcms/cms/pull/12380))
- The “Save as a new entry” action is now available to all users with the “Create entries” permission, and will create a new unpublished draft rather than a fully-saved entry. ([#9577](https://github.com/craftcms/cms/issues/9577), [#10244](https://github.com/craftcms/cms/discussions/10244))
- Entry conditions can now have a “Matrix field” rule. ([#13794](https://github.com/craftcms/cms/discussions/13794))
- Money field condition rules now use money inputs. ([#14148](https://github.com/craftcms/cms/pull/14148))
- Selected elements within relational fields now include a context menu with “View in a new tab”, “Edit”, and “Remove” options.
- Selected elements within relational fields now include a dedicated drag handle.
- Selected assets within Assets fields no longer open the file preview modal when their thumbnail is clicked on. The “Preview file” quick action, or the <kbd>Shift</kbd> + <kbd>Spacebar</kbd> keyboard shortcut, can be used instead.
Expand Down Expand Up @@ -211,8 +212,14 @@
- Added `craft\fields\Matrix::getSupportedSitesForElement()`.
- Added `craft\fields\Matrix::setEntryTypes()`.
- Added `craft\fields\Matrix::supportedSiteIds()`.
- Added `craft\fields\Money::currencyLabel()`.
- Added `craft\fields\Money::currencyLabel()`.
- Added `craft\fields\Money::subunits()`.
- Added `craft\fields\Money::subunits()`.
- Added `craft\fields\conditions\FieldConditionRuleTrait::fieldInstances()`.
- Added `craft\fields\conditions\FieldConditionRuleTrait::setLayoutElementUid()`.
- Added `craft\fields\conditions\MoneyFieldConditionRule`.
- Added `craft\fields\conditions\MoneyFieldConditionRule`.
- Added `craft\helpers\App::isWindows()`.
- Added `craft\helpers\App::silence()`.
- Added `craft\helpers\ArrayHelper::lastValue()`.
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Unreleased

- Money field condition rules now use money inputs. ([#14148](https://github.com/craftcms/cms/pull/14148))
- Improved the accessibility of element indexes. ([#14120](https://github.com/craftcms/cms/pull/14120))
- Added `craft\fields\Money::currencyLabel()`.
- Added `craft\fields\Money::subunits()`.
- Added `craft\fields\conditions\MoneyFieldConditionRule`.
- `craft\base\BaseFsInterface::renameFile()` and `copyFile()` now have a `$config` argument. ([#14147](https://github.com/craftcms/cms/pull/14147))
- Fixed a bug where `craft\helpers\Db::prepareValueForDb()` wasn’t converting objects to arrays for JSON columns.
- Fixed a bug where Checkboxes, Multi-select, Dropdown, and Radio Buttons fields weren’t displaying `0` option labels within element indexes. ([#14127](https://github.com/craftcms/cms/issues/14127))
Expand Down
42 changes: 29 additions & 13 deletions src/fields/Money.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use craft\base\Field;
use craft\base\InlineEditableFieldInterface;
use craft\base\SortableFieldInterface;
use craft\fields\conditions\NumberFieldConditionRule;
use craft\fields\conditions\MoneyFieldConditionRule;
use craft\gql\types\Money as MoneyType;
use craft\helpers\Cp;
use craft\helpers\Db;
Expand Down Expand Up @@ -144,7 +144,7 @@ public function getSettingsHtml(): ?string
return Craft::$app->getView()->renderTemplate('_components/fieldtypes/Money/settings.twig', [
'field' => $this,
'currencies' => $this->_isoCurrencies,
'subUnits' => $this->_isoCurrencies->subunitFor(new Currency($this->currency)),
'subUnits' => $this->subunits(),
]);
}

Expand Down Expand Up @@ -257,30 +257,23 @@ protected function inputHtml(mixed $value, ?ElementInterface $element, bool $inl
$decimals = null;

if ($value instanceof MoneyLibrary) {
$decimals = $this->_isoCurrencies->subunitFor($value->getCurrency());
$decimals = $this->subunits($value->getCurrency());
$value = MoneyHelper::toNumber($value);
}

if ($decimals === null) {
$decimals = $this->_isoCurrencies->subunitFor(new Currency($this->currency));
}
$decimals = $decimals ?? $this->subunits();

$defaultValue = null;
if (isset($this->defaultValue)) {
$defaultValue = MoneyHelper::toNumber(new MoneyLibrary($this->defaultValue, new Currency($this->currency)));
}

$currencyLabel = Craft::t('app', '({currencyCode}) {currencySymbol}', [
'currencyCode' => $this->currency,
'currencySymbol' => Craft::$app->getFormattingLocale()->getCurrencySymbol($this->currency),
]);

return Cp::moneyInputHtml([
'id' => $this->getInputId(),
'name' => $this->handle,
'size' => $this->size,
'currency' => $this->currency,
'currencyLabel' => $currencyLabel,
'currencyLabel' => $this->currencyLabel(),
'showCurrency' => $this->showCurrency,
'decimals' => $decimals,
'defaultValue' => $defaultValue,
Expand All @@ -290,6 +283,29 @@ protected function inputHtml(mixed $value, ?ElementInterface $element, bool $inl
]);
}

/**
* @return string
* @since 5.0.0
*/
public function currencyLabel(): string
{
return Craft::t('app', '({currencyCode}) {currencySymbol}', [
'currencyCode' => $this->currency,
'currencySymbol' => Craft::$app->getFormattingLocale()->getCurrencySymbol($this->currency),
]);
}

/**
* @param Currency|null $currency
* @return int
* @since 5.0.0
*/
public function subunits(?Currency $currency = null): int
{
$currency = $currency ?? new Currency($this->currency);
return $this->_isoCurrencies->subunitFor($currency);
}

/**
* @inheritdoc
*/
Expand All @@ -305,7 +321,7 @@ public function getElementValidationRules(): array
*/
public function getElementConditionRuleType(): array|string|null
{
return NumberFieldConditionRule::class;
return MoneyFieldConditionRule::class;
}

/**
Expand Down
136 changes: 136 additions & 0 deletions src/fields/conditions/MoneyFieldConditionRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace craft\fields\conditions;

use Craft;
use craft\base\conditions\BaseNumberConditionRule;
use craft\fields\Money;
use craft\helpers\ArrayHelper;
use craft\helpers\Cp;
use craft\helpers\Html;
use craft\helpers\MoneyHelper;
use Money\Currency;
use Money\Money as MoneyLibrary;

/**
* Money field condition rule.
*
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 5.0.0
*/
class MoneyFieldConditionRule extends BaseNumberConditionRule implements FieldConditionRuleInterface
{
use FieldConditionRuleTrait;

/**
* @inheritdoc
*/
public function setAttributes($values, $safeOnly = true): void
{
// Hold setting of the value attribute until we have all the info we need
if (isset($values['value']) && is_array($values['value'])) {
/** @var array $value */
$value = ArrayHelper::remove($values, 'value');
}

if (isset($values['maxValue']) && is_array($values['maxValue'])) {
/** @var array $maxValue */
$maxValue = ArrayHelper::remove($values, 'maxValue');
}

parent::setAttributes($values, $safeOnly);

/** @var Money $field */
$field = $this->field();

if (isset($value) && isset($this->_fieldUid)) {
if (!isset($value['currency'])) {
$value['currency'] = $field->currency;
}
$this->value = MoneyHelper::toDecimal(MoneyHelper::toMoney($value));
}

if (isset($maxValue) && isset($this->_fieldUid)) {
if (!isset($maxValue['currency'])) {
$maxValue['currency'] = $field->currency;
}
$this->maxValue = MoneyHelper::toDecimal(MoneyHelper::toMoney($maxValue));
}
}

/**
* @inheritdoc
*/
protected function inputHtml(): string
{
// don't show the value input if the condition checks for empty/notempty
if ($this->operator === self::OPERATOR_EMPTY || $this->operator === self::OPERATOR_NOT_EMPTY) {
return '';
}

if ($this->operator === self::OPERATOR_BETWEEN) {
return Html::tag('div',
Html::hiddenLabel(Craft::t('app', 'Min Value'), 'min') .
// Min value (value) input
Cp::moneyInputHtml($this->inputOptions()) .
Html::tag('span', Craft::t('app', 'and')) .
Html::hiddenLabel(Craft::t('app', 'Max Value'), 'max') .
// Max value input
Cp::moneyInputHtml(array_merge(
$this->inputOptions(),
['id' => 'maxValue', 'name' => 'maxValue', 'value' => $this->maxValue]
)) .
Html::tag('span', Craft::t('app', 'The values are matched inclusively.'), ['class' => 'info']),
['class' => 'flex flex-center']
);
}

return Cp::moneyInputHtml($this->inputOptions());
}

/**
* @inheritdoc
*/
protected function inputOptions(): array
{
/** @var Money $field */
$field = $this->field();
$defaultValue = null;
if ($field->defaultValue !== null) {
$defaultValue = MoneyHelper::toNumber(new MoneyLibrary($field->defaultValue, new Currency($field->currency)));
}

return [
'type' => 'text',
'id' => 'value',
'name' => 'value',
'value' => $this->value,
'autocomplete' => false,
'currency' => $field->currency,
'currencyLabel' => $field->currencyLabel(),
'showCurrency' => $field->showCurrency,
'decimals' => $field->subunits(),
'defaultValue' => $defaultValue,
'describedBy' => $field->describedBy,
'field' => $field,
'showClear' => false,
];
}

/**
* @inheritdoc
*/
protected function elementQueryParam(): ?string
{
return $this->paramValue();
}

/**
* @inheritdoc
*/
protected function matchFieldValue($value): bool
{
/** @var int|float|null $value */
return $this->matchValue($value);
}
}

0 comments on commit 53c6210

Please sign in to comment.