diff --git a/app/Models/RuleAction.php b/app/Models/RuleAction.php
index eed2a1dc13..ae949c89d7 100644
--- a/app/Models/RuleAction.php
+++ b/app/Models/RuleAction.php
@@ -67,12 +67,12 @@ class RuleAction extends Model
protected $casts
= [
- 'created_at' => 'datetime',
- 'updated_at' => 'datetime',
- 'active' => 'boolean',
- 'order' => 'int',
- 'stop_processing' => 'boolean',
- ];
+ 'created_at' => 'datetime',
+ 'updated_at' => 'datetime',
+ 'active' => 'boolean',
+ 'order' => 'int',
+ 'stop_processing' => 'boolean',
+ ];
protected $fillable = ['rule_id', 'action_type', 'action_value', 'order', 'active', 'stop_processing'];
diff --git a/app/TransactionRules/Actions/SetAmount.php b/app/TransactionRules/Actions/SetAmount.php
new file mode 100644
index 0000000000..54501e6659
--- /dev/null
+++ b/app/TransactionRules/Actions/SetAmount.php
@@ -0,0 +1,127 @@
+action = $action;
+ }
+
+ public function actOnArray(array $journal): bool
+ {
+ $this->refreshNotes($journal);
+
+ // not on slpit transactions
+ $groupCount = TransactionJournal::where('transaction_group_id', $journal['transaction_group_id'])->count();
+ if ($groupCount > 1) {
+ app('log')->error(sprintf('Group #%d has more than one transaction in it, cannot convert to transfer.', $journal['transaction_group_id']));
+ event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.split_group')));
+
+ return false;
+ }
+
+ $value = $this->action->getValue($journal);
+
+ if (!is_numeric($value) || '' === $value || 0 === bccomp((string)$value, '0')) {
+ app('log')->debug(sprintf('RuleAction SetAmount, amount "%s" is not a number or is zero, will not continue.', $value));
+ event(new RuleActionFailedOnArray($this->action, $journal, trans('rules.journal_invalid_amount', ['amount' => $value])));
+
+ return false;
+ }
+
+ /** @var TransactionJournal $object */
+ $object = TransactionJournal::where('user_id', $journal['user_id'])->find($journal['transaction_journal_id']);
+
+ // doesn't actually do anything!
+ $positive = Steam::positive($value);
+ $negative = Steam::negative($value);
+
+ $this->updatePositive($object, $positive);
+ $this->updateNegative($object, $negative);
+ $object->transactionGroup->touch();
+
+ // event for audit log entry
+
+ event(new TriggeredAuditLog(
+ $this->action->rule,
+ $object,
+ 'update_amount',
+ [
+ 'currency_symbol' => $object->transactionCurrency->symbol,
+ 'decimal_places' => $object->transactionCurrency->decimal_places,
+ 'amount' => $journal['amount'],
+ ],
+ [
+ 'currency_symbol' => $object->transactionCurrency->symbol,
+ 'decimal_places' => $object->transactionCurrency->decimal_places,
+ 'amount' => $value,
+ ]
+ ));
+
+ return true;
+ }
+
+ private function updatePositive(TransactionJournal $object, string $amount): void
+ {
+ /** @var null|Transaction $transaction */
+ $transaction = $object->transactions()->where('amount', '>', 0)->first();
+ if (null === $transaction) {
+ return;
+ }
+ $this->updateAmount($transaction, $amount);
+ }
+
+ private function updateNegative(TransactionJournal $object, string $amount): void
+ {
+ /** @var null|Transaction $transaction */
+ $transaction = $object->transactions()->where('amount', '<', 0)->first();
+ if (null === $transaction) {
+ return;
+ }
+ $this->updateAmount($transaction, $amount);
+ }
+
+ private function updateAmount(Transaction $transaction, string $amount): void
+ {
+ $transaction->amount = $amount;
+ $transaction->save();
+ $transaction->transactionJournal->touch();
+ }
+}
diff --git a/app/TransactionRules/Expressions/ActionExpression.php b/app/TransactionRules/Expressions/ActionExpression.php
index 1e089ad0e4..40708487fe 100644
--- a/app/TransactionRules/Expressions/ActionExpression.php
+++ b/app/TransactionRules/Expressions/ActionExpression.php
@@ -30,31 +30,31 @@ use Symfony\Component\ExpressionLanguage\SyntaxError;
class ActionExpression
{
private static array $NAMES = [
- 'transaction_group_id',
- 'user_id',
- 'user_group_id',
+ // 'transaction_group_id',
+ // 'user_id',
+ // 'user_group_id',
'created_at',
'updated_at',
'transaction_group_title',
'group_created_at',
'group_updated_at',
- 'transaction_journal_id',
- 'transaction_type_id',
+ // 'transaction_journal_id',
+ // 'transaction_type_id',
'description',
'date',
- 'order',
+ // 'order',
'transaction_type_type',
- 'source_transaction_id',
+ // 'source_transaction_id',
'source_account_id',
- 'reconciled',
+ // 'reconciled',
'amount',
- 'currency_id',
+ // 'currency_id',
'currency_code',
'currency_name',
'currency_symbol',
'currency_decimal_places',
'foreign_amount',
- 'foreign_currency_id',
+ // 'foreign_currency_id',
'foreign_currency_code',
'foreign_currency_name',
'foreign_currency_symbol',
@@ -71,14 +71,14 @@ class ActionExpression
'budget_id',
'budget_name',
'tags',
- 'attachments',
+ // 'attachments',
'interest_date',
'payment_date',
'invoice_date',
'book_date',
'due_date',
'process_date',
- 'destination_transaction_id',
+ // 'destination_transaction_id',
'notes',
];
diff --git a/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php b/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php
index 03b3d69970..a608fc6848 100644
--- a/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php
+++ b/app/TransactionRules/Expressions/ActionExpressionLanguageProvider.php
@@ -32,24 +32,34 @@ class ActionExpressionLanguageProvider implements ExpressionFunctionProviderInte
public function getFunctions(): array
{
return [
- new ExpressionFunction('constant', function ($str): string {
- return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'!');
- }, function ($arguments, $str): string {
- if (!is_string($str)) {
- return $str;
- }
+ new ExpressionFunction(
+ 'constant',
+ function ($str): string {
+ return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'!');
+ },
+ // @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ function ($arguments, $str): string {
+ if (!is_string($str)) {
+ return (string) $str;
+ }
- return strtolower($str.'!');
- }),
- new ExpressionFunction('enum', function ($str): string {
- return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'?');
- }, function ($arguments, $str): string {
- if (!is_string($str)) {
- return $str;
+ return strtolower($str.'!');
}
+ ),
+ new ExpressionFunction(
+ 'enum',
+ function ($str): string {
+ return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str.'?');
+ },
+ // @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ function ($arguments, $str): string {
+ if (!is_string($str)) {
+ return (string) $str;
+ }
- return strtolower($str).'?';
- }),
+ return strtolower($str).'?';
+ }
+ ),
ExpressionFunction::fromPhp('substr'),
ExpressionFunction::fromPhp('strlen'),
diff --git a/app/Transformers/V2/AccountTransformer.php b/app/Transformers/V2/AccountTransformer.php
index 727c1962ef..4e0fb1e6c0 100644
--- a/app/Transformers/V2/AccountTransformer.php
+++ b/app/Transformers/V2/AccountTransformer.php
@@ -91,7 +91,7 @@ class AccountTransformer extends AbstractTransformer
// TODO needs separate method.
$sort = $this->parameters->get('sort');
- if (count($sort) > 0) {
+ if (is_countable($sort) && count($sort) > 0) {
foreach ($sort as $column => $direction) {
// account_number + iban
if ('iban' === $column) {
diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php
index 9517d92188..9331479b7b 100644
--- a/app/Validation/FireflyValidator.php
+++ b/app/Validation/FireflyValidator.php
@@ -829,7 +829,8 @@ class FireflyValidator extends Validator
->where('trigger', $trigger)
->where('response', $response)
->where('delivery', $delivery)
- ->where('url', $url)->count();
+ ->where('url', $url)->count()
+ ;
}
return false;
diff --git a/config/firefly.php b/config/firefly.php
index 4c081b593e..fa0ee36959 100644
--- a/config/firefly.php
+++ b/config/firefly.php
@@ -83,6 +83,7 @@ use FireflyIII\TransactionRules\Actions\PrependDescription;
use FireflyIII\TransactionRules\Actions\PrependNotes;
use FireflyIII\TransactionRules\Actions\RemoveAllTags;
use FireflyIII\TransactionRules\Actions\RemoveTag;
+use FireflyIII\TransactionRules\Actions\SetAmount;
use FireflyIII\TransactionRules\Actions\SetBudget;
use FireflyIII\TransactionRules\Actions\SetCategory;
use FireflyIII\TransactionRules\Actions\SetDescription;
@@ -109,11 +110,11 @@ return [
],
// some feature flags:
'feature_flags' => [
- 'export' => true,
- 'telemetry' => false,
- 'webhooks' => true,
- 'handle_debts' => true,
- 'expression_engine' => false,
+ 'export' => true,
+ 'telemetry' => false,
+ 'webhooks' => true,
+ 'handle_debts' => true,
+ 'expression_engine' => true,
// see cer.php for exchange rates feature flag.
],
'version' => 'develop/2024-03-07',
@@ -521,6 +522,9 @@ return [
'move_notes_to_descr' => MoveNotesToDescription::class,
'set_source_to_cash' => SetSourceToCashAccount::class,
'set_destination_to_cash' => SetDestinationToCashAccount::class,
+ 'set_amount' => SetAmount::class,
+ // 'set_foreign_amount' => SetForeignAmount::class,
+ // 'set_foreign_currency' => SetForeignCurrency::class,
],
'context-rule-actions' => [
'set_category',
diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php
index 66accd2b86..caf38e16cb 100644
--- a/resources/lang/en_US/firefly.php
+++ b/resources/lang/en_US/firefly.php
@@ -1250,6 +1250,8 @@ return [
'rule_action_append_notes_to_descr' => 'Append notes to description',
'rule_action_move_descr_to_notes' => 'Replace notes with description',
'rule_action_move_notes_to_descr' => 'Replace description with notes',
+ 'rule_action_set_amount_choice' => 'Set amount to ..',
+ 'rule_action_set_amount' => 'Set amount to ":action_value"',
'rule_action_set_destination_to_cash_choice' => 'Set destination account to (cash)',
'rule_action_set_source_to_cash_choice' => 'Set source account to (cash)',
'rulegroup_for_bills_title' => 'Rule group for bills',
@@ -2678,6 +2680,7 @@ return [
'ale_action_add_to_piggy' => 'Piggy bank',
'ale_action_remove_from_piggy' => 'Piggy bank',
'ale_action_add_tag' => 'Added tag',
+ 'ale_action_update_amount' => 'Updated amount',
// dashboard
'enable_auto_convert' => 'Enable currency conversion',
diff --git a/resources/lang/en_US/rules.php b/resources/lang/en_US/rules.php
index 8d4b44ad76..020162caf3 100644
--- a/resources/lang/en_US/rules.php
+++ b/resources/lang/en_US/rules.php
@@ -70,4 +70,5 @@ return [
'cannot_find_budget' => 'Firefly III can\'t find budget ":name"',
'cannot_find_category' => 'Firefly III can\'t find category ":name"',
'cannot_set_budget' => 'Firefly III can\'t set budget ":name" to a transaction of type ":type"',
+ 'journal_invalid_amount' => 'Firefly III can\'t set amount ":amount" because it is not a valid number.',
];
diff --git a/resources/views/list/ale.twig b/resources/views/list/ale.twig
index 3632ec3bd1..09433efa82 100644
--- a/resources/views/list/ale.twig
+++ b/resources/views/list/ale.twig
@@ -22,6 +22,12 @@
{{ logEntry.after }}
{% endif %}
+ {% if 'update_amount' == logEntry.action %}
+ {{ formatAmountBySymbol(logEntry.before.amount, logEntry.before.currency_symbol, logEntry.before.decimal_places, true) }}
+ →
+ {{ formatAmountBySymbol(logEntry.after.amount, logEntry.after.currency_symbol, logEntry.after.decimal_places, true) }}
+ {% endif %}
+
{% if 'update_group_title' == logEntry.action %}
{{ logEntry.before }}
→