Extra content to fix recurrences.

This commit is contained in:
James Cole 2021-03-15 08:51:21 +01:00
parent 8d84dfb3aa
commit 1783f0beb1
5 changed files with 137 additions and 29 deletions

View File

@ -80,6 +80,7 @@ class RecurrenceFactory
$description = ''; $description = '';
$applyRules = true; $applyRules = true;
$active = true; $active = true;
$repeatUntilString = null;
if (array_key_exists('first_date', $data['recurrence'])) { if (array_key_exists('first_date', $data['recurrence'])) {
/** @var Carbon $firstDate */ /** @var Carbon $firstDate */
$firstDate = $data['recurrence']['first_date']; $firstDate = $data['recurrence']['first_date'];
@ -102,8 +103,8 @@ class RecurrenceFactory
if (array_key_exists('active', $data['recurrence'])) { if (array_key_exists('active', $data['recurrence'])) {
$active = $data['recurrence']['active']; $active = $data['recurrence']['active'];
} }
if ($repetitions > 0 && null === $repeatUntil) { if (null !== $repeatUntil) {
$repeatUntil = Carbon::create()->addyear(); $repeatUntilString = $repeatUntil->format('Y-m-d');
} }
$recurrence = new Recurrence( $recurrence = new Recurrence(
@ -113,7 +114,7 @@ class RecurrenceFactory
'title' => $title, 'title' => $title,
'description' => $description, 'description' => $description,
'first_date' => $firstDate ? $firstDate->format('Y-m-d') : null, 'first_date' => $firstDate ? $firstDate->format('Y-m-d') : null,
'repeat_until' => $repetitions > 0 ? null : $repeatUntil->format('Y-m-d'), 'repeat_until' => $repetitions > 0 ? null : $repeatUntilString,
'latest_date' => null, 'latest_date' => null,
'repetitions' => $repetitions, 'repetitions' => $repetitions,
'apply_rules' => $applyRules, 'apply_rules' => $applyRules,

View File

@ -25,6 +25,7 @@ namespace FireflyIII\Http\Requests;
use Carbon\Carbon; use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\TransactionType; use FireflyIII\Models\TransactionType;
use FireflyIII\Rules\ValidRecurrenceRepetitionType; use FireflyIII\Rules\ValidRecurrenceRepetitionType;
@ -123,6 +124,19 @@ class RecurrenceFormRequest extends FormRequest
break; break;
} }
// replace category name with a new category:
$factory = app(CategoryFactory::class);
$factory->setUser(auth()->user());
foreach($return['transactions'] as $index => $transaction) {
$categoryName =$transaction['category_name'] ??null;
if(null !== $categoryName) {
$category = $factory->findOrCreate(null, $categoryName);
if(null !== $category) {
$return['transactions'][$index]['category_id'] = $category->id;
}
}
}
return $return; return $return;
} }

View File

@ -138,7 +138,9 @@ trait RecurringTransactionTrait
if (!$validator->validateDestination($destination->id, null, null)) { if (!$validator->validateDestination($destination->id, null, null)) {
throw new FireflyException(sprintf('Destination invalid: %s', $validator->destError)); // @codeCoverageIgnore throw new FireflyException(sprintf('Destination invalid: %s', $validator->destError)); // @codeCoverageIgnore
} }
if(array_key_exists('foreign_amount', $array) && '' === (string)$array['foreign_amount']) {
unset($array['foreign_amount']);
}
// TODO typeOverrule: the account validator may have another opinion on the transaction type. // TODO typeOverrule: the account validator may have another opinion on the transaction type.
$transaction = new RecurrenceTransaction( $transaction = new RecurrenceTransaction(
[ [

View File

@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Note; use FireflyIII\Models\Note;
use FireflyIII\Models\Recurrence; use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceRepetition; use FireflyIII\Models\RecurrenceRepetition;
use FireflyIII\Models\RecurrenceTransaction;
use FireflyIII\Services\Internal\Support\RecurringTransactionTrait; use FireflyIII\Services\Internal\Support\RecurringTransactionTrait;
use FireflyIII\Services\Internal\Support\TransactionTypeTrait; use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
use FireflyIII\User; use FireflyIII\User;
@ -103,15 +104,73 @@ class RecurrenceUpdateService
// update all transactions: // update all transactions:
// // update all transactions (and associated meta-data) // update all transactions (and associated meta-data)
// if (array_key_exists('transactions', $data)) { if (array_key_exists('transactions', $data)) {
// $this->deleteTransactions($recurrence); $this->updateTransactions($recurrence, $data['transactions'] ?? []);
// $this->createTransactions($recurrence, $data['transactions'] ?? []); // $this->deleteTransactions($recurrence);
// } // $this->createTransactions($recurrence, $data['transactions'] ?? []);
}
return $recurrence; return $recurrence;
} }
/**
* TODO this method is way too complex.
*
* @param Recurrence $recurrence
* @param array $transactions
*
* @throws FireflyException
*/
private function updateTransactions(Recurrence $recurrence, array $transactions): void
{
$originalCount = $recurrence->recurrenceTransactions()->count();
if (0 === count($transactions)) {
// wont drop transactions, rather avoid.
return;
}
// user added or removed repetitions, delete all and recreate:
if ($originalCount !== count($transactions)) {
Log::debug('Del + recreate');
$this->deleteTransactions($recurrence);
$this->createTransactions($recurrence, $transactions);
return;
}
// loop all and try to match them:
if ($originalCount === count($transactions)) {
Log::debug('Loop and find');
foreach ($transactions as $current) {
$match = $this->matchTransaction($recurrence, $current);
if (null === $match) {
throw new FireflyException('Cannot match recurring transaction to existing transaction. Not sure what to do. Break.');
}
// TODO find currency
// TODO find foreign currency
// update fields
$fields = [
'source_id' => 'source_id',
'destination_id' => 'destination_id',
'amount' => 'amount',
'foreign_amount' => 'foreign_amount',
'description' => 'description',
];
foreach ($fields as $field => $column) {
if (array_key_exists($field, $current)) {
$match->$column = $current[$field];
$match->save();
}
}
// update meta data
// budget_id
// category_id
// tags
// piggy_bank_id
}
}
}
/** /**
* @param Recurrence $recurrence * @param Recurrence $recurrence
* @param string $text * @param string $text
@ -172,7 +231,7 @@ class RecurrenceUpdateService
'moment' => 'repetition_moment', 'moment' => 'repetition_moment',
'skip' => 'repetition_skip', 'skip' => 'repetition_skip',
'weekend' => 'weekend', 'weekend' => 'weekend',
]; ];
foreach ($fields as $field => $column) { foreach ($fields as $field => $column) {
if (array_key_exists($field, $current)) { if (array_key_exists($field, $current)) {
$match->$column = $current[$field]; $match->$column = $current[$field];
@ -193,6 +252,7 @@ class RecurrenceUpdateService
$originalCount = $recurrence->recurrenceRepetitions()->count(); $originalCount = $recurrence->recurrenceRepetitions()->count();
if (1 === $originalCount) { if (1 === $originalCount) {
Log::debug('Return the first one'); Log::debug('Return the first one');
return $recurrence->recurrenceRepetitions()->first(); return $recurrence->recurrenceRepetitions()->first();
} }
// find it: // find it:
@ -211,4 +271,38 @@ class RecurrenceUpdateService
return $query->first(); return $query->first();
} }
/**
* @param array $data
*
* @return RecurrenceTransaction|null
*/
private function matchTransaction(Recurrence $recurrence, array $data): ?RecurrenceTransaction
{
$originalCount = $recurrence->recurrenceTransactions()->count();
if (1 === $originalCount) {
Log::debug('Return the first one');
return $recurrence->recurrenceTransactions()->first();
}
// find it based on data
$fields = [
'id' => 'id',
'currency_id' => 'transaction_currency_id',
'foreign_currency_id' => 'foreign_currency_id',
'source_id' => 'source_id',
'destination_id' => 'destination_id',
'amount' => 'amount',
'foreign_amount' => 'foreign_amount',
'description' => 'description',
];
$query = $recurrence->recurrenceTransactions();
foreach ($fields as $field => $column) {
if (array_key_exists($field, $data)) {
$query->where($column, $data[$field]);
}
}
return $query->first();
}
} }

View File

@ -212,29 +212,26 @@ class UpdateControllerTest extends TestCase
// now loop fields, enough to create sets I guess? // now loop fields, enough to create sets I guess?
// TODO maybe do some permutation stuff here? // TODO maybe do some permutation stuff here?
$extraTransaction = [ $extraTransaction = [
'description' => $faker->uuid, 'currency_id' => $faker->numberBetween(1, 4),
'amount' => number_format($faker->randomFloat(2, 10, 100), 2), 'foreign_currency_id' => $faker->numberBetween(4, 6),
'skip' => $faker->numberBetween(1, 3), 'source_id' => $faker->numberBetween(1, 3),
'weekend' => $faker->numberBetween(1, 4), 'destination_id' => $faker->numberBetween(8),
'budget_id' => $faker->numberBetween(1, 2), 'amount' => number_format($faker->randomFloat(2, 10, 100), 2),
'category_id' => $faker->numberBetween(1, 2), 'foreign_amount' => number_format($faker->randomFloat(2, 10, 100), 2),
'tags' => ['a', 'c', 'd'], 'description' => $faker->uuid,
'source_id' => 1,
'destination_id' => 8,
]; ];
$extraTransactions[] = $extraTransaction; $extraTransactions[] = $extraTransaction;
} }
// TODO later maybe $set[] = [
// $set[] = [ 'id' => 1,
// 'id' => 1, 'fields' => [
// 'fields' => [ 'transactions' => [
// 'transactions' => [ 'test_value' => $extraTransactions,
// 'test_value' => $extraTransactions, ],
// ], ],
// ], 'extra_ignore' => [],
// 'extra_ignore' => [], ];
// ];
} }
return $set; return $set;