Fix a few small bugs and rearrange code.

This commit is contained in:
James Cole 2024-03-10 11:57:21 +01:00
parent 3413b9b5b5
commit d5ea78025e
No known key found for this signature in database
GPG Key ID: B49A324B7EAD6D80
10 changed files with 192 additions and 40 deletions

View File

@ -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'];

View File

@ -0,0 +1,127 @@
<?php
/*
* SetAmount.php
* Copyright (c) 2024 james@firefly-iii.org.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
declare(strict_types=1);
namespace FireflyIII\TransactionRules\Actions;
use FireflyIII\Events\Model\Rule\RuleActionFailedOnArray;
use FireflyIII\Events\TriggeredAuditLog;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Support\Facades\Steam;
use FireflyIII\TransactionRules\Traits\RefreshNotesTrait;
class SetAmount implements ActionInterface
{
use RefreshNotesTrait;
private RuleAction $action;
/**
* TriggerInterface constructor.
*/
public function __construct(RuleAction $action)
{
$this->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();
}
}

View File

@ -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',
];

View File

@ -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'),

View File

@ -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) {

View File

@ -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;

View File

@ -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',

View File

@ -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',

View File

@ -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.',
];

View File

@ -22,6 +22,12 @@
<code>{{ logEntry.after }}</code>
{% endif %}
{% if 'update_amount' == logEntry.action %}
{{ formatAmountBySymbol(logEntry.before.amount, logEntry.before.currency_symbol, logEntry.before.decimal_places, true) }}
&rarr;
{{ formatAmountBySymbol(logEntry.after.amount, logEntry.after.currency_symbol, logEntry.after.decimal_places, true) }}
{% endif %}
{% if 'update_group_title' == logEntry.action %}
<code><s>{{ logEntry.before }}</s></code>
&rarr;