diff --git a/app/Api/V1/Controllers/Chart/AccountController.php b/app/Api/V1/Controllers/Chart/AccountController.php index 7547cbb248..062748cfe5 100644 --- a/app/Api/V1/Controllers/Chart/AccountController.php +++ b/app/Api/V1/Controllers/Chart/AccountController.php @@ -26,10 +26,9 @@ namespace FireflyIII\Api\V1\Controllers\Chart; use Carbon\Carbon; use FireflyIII\Api\V1\Controllers\Controller; -use FireflyIII\Api\V1\Requests\DateRequest; +use FireflyIII\Api\V1\Requests\Data\DateRequest; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; -use FireflyIII\Models\TransactionCurrency; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; use FireflyIII\Support\Http\Api\ApiSupport; @@ -44,8 +43,7 @@ class AccountController extends Controller use ApiSupport; private CurrencyRepositoryInterface $currencyRepository; - - private AccountRepositoryInterface $repository; + private AccountRepositoryInterface $repository; /** @@ -71,92 +69,6 @@ class AccountController extends Controller ); } - /** - * @param DateRequest $request - * @deprecated - * @return JsonResponse - */ - public function expenseOverview(DateRequest $request): JsonResponse - { - // parameters for chart: - $dates = $request->getAll(); - /** @var Carbon $start */ - $start = $dates['start']; - /** @var Carbon $end */ - $end = $dates['end']; - - $start->subDay(); - - // prep some vars: - $currencies = []; - $chartData = []; - $tempData = []; - - // grab all accounts and names - $accounts = $this->repository->getAccountsByType([AccountType::EXPENSE]); - $accountNames = $this->extractNames($accounts); - $startBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $start); - $endBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $end); - - // loop the end balances. This is an array for each account ($expenses) - foreach ($endBalances as $accountId => $expenses) { - $accountId = (int) $accountId; - // loop each expense entry (each entry can be a different currency). - foreach ($expenses as $currencyId => $endAmount) { - $currencyId = (int) $currencyId; - - // see if there is an accompanying start amount. - // grab the difference and find the currency. - $startAmount = $startBalances[$accountId][$currencyId] ?? '0'; - $diff = bcsub($endAmount, $startAmount); - $currencies[$currencyId] = $currencies[$currencyId] ?? $this->currencyRepository->findNull($currencyId); - if (0 !== bccomp($diff, '0')) { - // store the values in a temporary array. - $tempData[] = [ - 'name' => $accountNames[$accountId], - 'difference' => $diff, - 'diff_float' => (float) $diff, - 'currency_id' => $currencyId, - ]; - } - } - } - - // sort temp array by amount. - $amounts = array_column($tempData, 'diff_float'); - array_multisort($amounts, SORT_DESC, $tempData); - - // loop all found currencies and build the data array for the chart. - /** - * @var int $currencyId - * @var TransactionCurrency $currency - */ - foreach ($currencies as $currencyId => $currency) { - $currentSet = [ - 'label' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]), - 'currency_id' => $currency->id, - 'currency_code' => $currency->code, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => $currency->decimal_places, - 'type' => 'bar', // line, area or bar - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => $this->expandNames($tempData), - ]; - $chartData[$currencyId] = $currentSet; - } - - // loop temp data and place data in correct array: - foreach ($tempData as $entry) { - $currencyId = $entry['currency_id']; - $name = $entry['name']; - $chartData[$currencyId]['entries'][$name] = round((float) $entry['difference'], $chartData[$currencyId]['currency_decimal_places']); - } - $chartData = array_values($chartData); - - return response()->json($chartData); - } - - /** * @param DateRequest $request * @@ -193,7 +105,7 @@ class AccountController extends Controller } $currentSet = [ 'label' => $account->name, - 'currency_id' => (string) $currency->id, + 'currency_id' => (string)$currency->id, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => $currency->decimal_places, @@ -206,11 +118,11 @@ class AccountController extends Controller /** @var Carbon $currentStart */ $currentStart = clone $start; $range = app('steam')->balanceInRange($account, $start, clone $end); - $previous = round((float) array_values($range)[0], 12); + $previous = round((float)array_values($range)[0], 12); while ($currentStart <= $end) { $format = $currentStart->format('Y-m-d'); $label = $currentStart->format('Y-m-d'); - $balance = array_key_exists($format, $range) ? round((float) $range[$format], 12) : $previous; + $balance = array_key_exists($format, $range) ? round((float)$range[$format], 12) : $previous; $previous = $balance; $currentStart->addDay(); $currentSet['entries'][$label] = $balance; @@ -220,91 +132,4 @@ class AccountController extends Controller return response()->json($chartData); } - - /** - * @param DateRequest $request - * @deprecated - * @return JsonResponse - */ - public function revenueOverview(DateRequest $request): JsonResponse - { - // parameters for chart: - $dates = $request->getAll(); - /** @var Carbon $start */ - $start = $dates['start']; - /** @var Carbon $end */ - $end = $dates['end']; - - $start->subDay(); - - // prep some vars: - $currencies = []; - $chartData = []; - $tempData = []; - - // grab all accounts and names - $accounts = $this->repository->getAccountsByType([AccountType::REVENUE]); - $accountNames = $this->extractNames($accounts); - $startBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $start); - $endBalances = app('steam')->balancesPerCurrencyByAccounts($accounts, $end); - - // loop the end balances. This is an array for each account ($expenses) - foreach ($endBalances as $accountId => $expenses) { - $accountId = (int) $accountId; - // loop each expense entry (each entry can be a different currency). - foreach ($expenses as $currencyId => $endAmount) { - $currencyId = (int) $currencyId; - - // see if there is an accompanying start amount. - // grab the difference and find the currency. - $startAmount = $startBalances[$accountId][$currencyId] ?? '0'; - $diff = bcsub($endAmount, $startAmount); - $currencies[$currencyId] = $currencies[$currencyId] ?? $this->currencyRepository->findNull($currencyId); - if (0 !== bccomp($diff, '0')) { - // store the values in a temporary array. - $tempData[] = [ - 'name' => $accountNames[$accountId], - 'difference' => bcmul($diff, '-1'), - // For some reason this line is never covered in code coverage: - 'diff_float' => ((float) $diff) * -1, // @codeCoverageIgnore - 'currency_id' => $currencyId, - ]; - } - } - } - - // sort temp array by amount. - $amounts = array_column($tempData, 'diff_float'); - array_multisort($amounts, SORT_DESC, $tempData); - - // loop all found currencies and build the data array for the chart. - /** - * @var int $currencyId - * @var TransactionCurrency $currency - */ - foreach ($currencies as $currencyId => $currency) { - $currentSet = [ - 'label' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]), - 'currency_id' => $currency->id, - 'currency_code' => $currency->code, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => $currency->decimal_places, - 'type' => 'bar', // line, area or bar - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => $this->expandNames($tempData), - ]; - $chartData[$currencyId] = $currentSet; - } - - // loop temp data and place data in correct array: - foreach ($tempData as $entry) { - $currencyId = $entry['currency_id']; - $name = $entry['name']; - $chartData[$currencyId]['entries'][$name] = round((float) $entry['difference'], $chartData[$currencyId]['currency_decimal_places']); - } - $chartData = array_values($chartData); - - return response()->json($chartData); - } - } diff --git a/app/Api/V1/Controllers/Chart/AvailableBudgetController.php b/app/Api/V1/Controllers/Chart/AvailableBudgetController.php deleted file mode 100644 index 039ebffe49..0000000000 --- a/app/Api/V1/Controllers/Chart/AvailableBudgetController.php +++ /dev/null @@ -1,115 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Api\V1\Controllers\Chart; - - -use FireflyIII\Api\V1\Controllers\Controller; -use FireflyIII\Models\AvailableBudget; -use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; -use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; -use FireflyIII\User; -use Illuminate\Http\JsonResponse; - -/** - * Class AvailableBudgetController - */ -class AvailableBudgetController extends Controller -{ - private OperationsRepositoryInterface $opsRepository; - private BudgetRepositoryInterface $repository; - - /** - * AvailableBudgetController constructor. - * @deprecated - * @codeCoverageIgnore - */ - public function __construct() - { - parent::__construct(); - $this->middleware( - function ($request, $next) { - /** @var User $user */ - $user = auth()->user(); - $this->repository = app(BudgetRepositoryInterface::class); - $this->opsRepository = app(OperationsRepositoryInterface::class); - $this->repository->setUser($user); - $this->opsRepository->setUser($user); - - return $next($request); - } - ); - } - - /** - * @param AvailableBudget $availableBudget - * @deprecated - * @return JsonResponse - */ - public function overview(AvailableBudget $availableBudget): JsonResponse - { - $currency = $availableBudget->transactionCurrency; - $budgets = $this->repository->getActiveBudgets(); - $newBudgetInformation = $this->opsRepository->sumExpenses($availableBudget->start_date, $availableBudget->end_date, null, $budgets); - $spent = '0'; - - foreach ($newBudgetInformation as $currencyId => $info) { - if ($currencyId === (int) $availableBudget->transaction_currency_id) { - $spent = $info['sum']; - } - } - - $left = bcadd($availableBudget->amount, $spent); - // left less than zero? Set to zero. - if (-1 === bccomp($left, '0')) { - $left = '0'; - } - - $chartData = [ - [ - 'label' => trans('firefly.spent'), - 'currency_id' => $currency->id, - 'currency_code' => $currency->code, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => $currency->decimal_places, - 'type' => 'pie', - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => [$spent * -1], - ], - [ - 'label' => trans('firefly.left'), - 'currency_id' => $currency->id, - 'currency_code' => $currency->code, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => $currency->decimal_places, - 'type' => 'line', // line, area or bar - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => [round((float) $left, $currency->decimal_places)], - ], - ]; - - return response()->json($chartData); - } - -} diff --git a/app/Api/V1/Controllers/Chart/BudgetController.php b/app/Api/V1/Controllers/Chart/BudgetController.php deleted file mode 100644 index 3a1ad355aa..0000000000 --- a/app/Api/V1/Controllers/Chart/BudgetController.php +++ /dev/null @@ -1,297 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Api\V1\Controllers\Chart; - - -use Carbon\Carbon; -use FireflyIII\Api\V1\Controllers\Controller; -use FireflyIII\Api\V1\Requests\DateRequest; -use FireflyIII\Models\Budget; -use FireflyIII\Models\BudgetLimit; -use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface; -use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; -use FireflyIII\Repositories\Budget\OperationsRepositoryInterface; -use Illuminate\Http\JsonResponse; -use Illuminate\Support\Collection; - -/** - * Class BudgetController - */ -class BudgetController extends Controller -{ - private BudgetLimitRepositoryInterface $blRepository; - - private OperationsRepositoryInterface $opsRepository; - - private BudgetRepositoryInterface $repository; - - - /** - * BudgetController constructor. - * @deprecated - * @codeCoverageIgnore - */ - public function __construct() - { - parent::__construct(); - - $this->middleware( - function ($request, $next) { - $this->repository = app(BudgetRepositoryInterface::class); - $this->opsRepository = app(OperationsRepositoryInterface::class); - $this->blRepository = app(BudgetLimitRepositoryInterface::class); - - return $next($request); - } - ); - } - - /** - * [ - * 'label' => 'label for entire set' - * 'currency_id' => 0, - * 'currency_code' => 'EUR', - * 'currency_symbol' => '$', - * 'currency_decimal_places' => 2, - * 'type' => 'bar', // line, area or bar - * 'yAxisID' => 0, // 0, 1, 2 - * 'entries' => ['a' => 1, 'b' => 4], - * ], - * - * @param DateRequest $request - * @deprecated - * @return JsonResponse - */ - public function overview(DateRequest $request): JsonResponse - { - $dates = $request->getAll(); - $budgets = $this->repository->getActiveBudgets(); - $budgetNames = []; - $currencyNames = []; - $sets = []; - /** @var Budget $budget */ - foreach ($budgets as $budget) { - $expenses = $this->getExpenses($budget, $dates['start'], $dates['end']); - $expenses = $this->filterNulls($expenses); - foreach ($expenses as $set) { - $budgetNames[] = $set['budget_name']; - $currencyNames[] = $set['currency_name']; - $sets[] = $set; - } - } - $budgetNames = array_unique($budgetNames); - $currencyNames = array_unique($currencyNames); - $basic = $this->createSets($budgetNames, $currencyNames); - $filled = $this->fillSets($basic, $sets); - $keys = array_values($filled); - - return response()->json($keys); - } - - /** - * @param Collection $limits - * @param Carbon $start - * @param Carbon $end - * @deprecated - * @return array - */ - protected function getExpenses(Budget $budget, Carbon $start, Carbon $end): array - { - $limits = $this->blRepository->getBudgetLimits($budget, $start, $end); - if (0 === $limits->count()) { - return $this->getExpenseInRange($budget, $start, $end); - } - $arr = []; - /** @var BudgetLimit $limit */ - foreach ($limits as $limit) { - $arr[] = $this->getExpensesForLimit($limit); - } - - return $arr; - } - - /** - * @param Budget $budget - * @param Carbon $start - * @param Carbon $end - * @deprecated - * @return array - */ - private function getExpenseInRange(Budget $budget, Carbon $start, Carbon $end): array - { - $spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]), null); - $return = []; - /** @var array $set */ - foreach ($spent as $set) { - $current = [ - 'label' => sprintf('%s (%s)', $budget->name, $set['currency_name']), - 'budget_name' => $budget->name, - 'start_date' => $start->format('Y-m-d'), - 'end_date' => $end->format('Y-m-d'), - 'currency_id' => (int) $set['currency_id'], - 'currency_code' => $set['currency_code'], - 'currency_name' => $set['currency_name'], - 'currency_symbol' => $set['currency_symbol'], - 'currency_decimal_places' => (int) $set['currency_decimal_places'], - 'type' => 'bar', // line, area or bar, - 'entries' => [], - ]; - $sumSpent = bcmul($set['sum'], '-1'); // spent - $current['entries']['spent'] = $sumSpent; - $current['entries']['amount'] = '0'; - $current['entries']['spent_capped'] = $sumSpent; - $current['entries']['left'] = '0'; - $current['entries']['overspent'] = '0'; - $return[] = $current; - } - - return $return; - } - - /** - * @param BudgetLimit $limit - * @deprecated - * @return array - */ - private function getExpensesForLimit(BudgetLimit $limit): array - { - $budget = $limit->budget; - $spent = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $limit->transactionCurrency); - $currency = $limit->transactionCurrency; - // when limited to a currency, the count is always one. Or it's empty. - $set = array_shift($spent); - if (null === $set) { - return []; - } - $return = [ - 'label' => sprintf('%s (%s)', $budget->name, $set['currency_name']), - 'budget_name' => $budget->name, - 'start_date' => $limit->start_date->format('Y-m-d'), - 'end_date' => $limit->end_date->format('Y-m-d'), - 'currency_id' => (int) $currency->id, - 'currency_code' => $currency->code, - 'currency_name' => $currency->name, - 'currency_symbol' => $currency->symbol, - 'currency_decimal_places' => (int) $currency->decimal_places, - 'type' => 'bar', // line, area or bar, - 'entries' => [], - ]; - $sumSpent = bcmul($set['sum'], '-1'); // spent - $return['entries']['spent'] = $sumSpent; - $return['entries']['amount'] = $limit->amount; - $return['entries']['spent_capped'] = 1 === bccomp($sumSpent, $limit->amount) ? $limit->amount : $sumSpent; - $return['entries']['left'] = 1 === bccomp($limit->amount, $sumSpent) ? bcadd($set['sum'], $limit->amount) : '0'; // left - $return['entries']['overspent'] = 1 === bccomp($limit->amount, $sumSpent) ? '0' : bcmul(bcadd($set['sum'], $limit->amount), '-1'); // overspent - - return $return; - } - - /** - * @param array $expenses - * @deprecated - * @return array - */ - private function filterNulls(array $expenses): array - { - $return = []; - /** @var array|null $arr */ - foreach ($expenses as $arr) { - if ([] !== $arr) { - $return[] = $arr; - } - } - - return $return; - } - - /** - * @param array $budgetNames - * @param array $currencyNames - * @deprecated - * @return array - */ - private function createSets(array $budgetNames, array $currencyNames): array - { - $return = []; - foreach ($currencyNames as $currencyName) { - $entries = []; - foreach ($budgetNames as $budgetName) { - $label = sprintf('%s (%s)', $budgetName, $currencyName); - $entries[$label] = '0'; - } - - // left - $return['left'] = [ - 'label' => sprintf('%s (%s)', trans('firefly.left'), $currencyName), - 'data_type' => 'left', - 'currency_name' => $currencyName, - 'type' => 'bar', - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => $entries, - ]; - - // spent_capped - $return['spent_capped'] = [ - 'label' => sprintf('%s (%s)', trans('firefly.spent'), $currencyName), - 'data_type' => 'spent_capped', - 'currency_name' => $currencyName, - 'type' => 'bar', - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => $entries, - ]; - - // overspent - $return['overspent'] = [ - 'label' => sprintf('%s (%s)', trans('firefly.overspent'), $currencyName), - 'data_type' => 'overspent', - 'currency_name' => $currencyName, - 'type' => 'bar', - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => $entries, - ]; - - } - - return $return; - } - - /** - * @param array $basic - * @param array $sets - * @deprecated - * @return array - */ - private function fillSets(array $basic, array $sets): array - { - foreach ($sets as $set) { - $label = $set['label']; - $basic['spent_capped']['entries'][$label] = $set['entries']['spent_capped']; - $basic['left']['entries'][$label] = $set['entries']['left']; - $basic['overspent']['entries'][$label] = $set['entries']['overspent']; - } - - return $basic; - } - -} diff --git a/app/Api/V1/Controllers/Chart/CategoryController.php b/app/Api/V1/Controllers/Chart/CategoryController.php deleted file mode 100644 index 04d525cd87..0000000000 --- a/app/Api/V1/Controllers/Chart/CategoryController.php +++ /dev/null @@ -1,157 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace FireflyIII\Api\V1\Controllers\Chart; - -use Carbon\Carbon; -use FireflyIII\Api\V1\Controllers\Controller; -use FireflyIII\Api\V1\Requests\DateRequest; -use FireflyIII\Repositories\Category\CategoryRepositoryInterface; -use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface; -use FireflyIII\Repositories\Category\OperationsRepositoryInterface; -use FireflyIII\User; -use Illuminate\Http\JsonResponse; - -/** - * Class CategoryController - */ -class CategoryController extends Controller -{ - private CategoryRepositoryInterface $categoryRepository; - private NoCategoryRepositoryInterface $noCatRepository; - private OperationsRepositoryInterface $opsRepository; - private array $categories; - - /** - * AccountController constructor. - * @deprecated - * @codeCoverageIgnore - */ - public function __construct() - { - parent::__construct(); - $this->middleware( - function ($request, $next) { - /** @var User $user */ - $user = auth()->user(); - $this->categoryRepository = app(CategoryRepositoryInterface::class); - $this->opsRepository = app(OperationsRepositoryInterface::class); - $this->noCatRepository = app(NoCategoryRepositoryInterface::class); - $this->categories = []; - $this->categoryRepository->setUser($user); - $this->opsRepository->setUser($user); - $this->noCatRepository->setUser($user); - - return $next($request); - } - ); - } - - - /** - * @param DateRequest $request - * @deprecated - * @return JsonResponse - */ - public function overview(DateRequest $request): JsonResponse - { - // parameters for chart: - $dates = $request->getAll(); - /** @var Carbon $start */ - $start = $dates['start']; - /** @var Carbon $end */ - $end = $dates['end']; - - $tempData = []; - $spentWith = $this->opsRepository->listExpenses($start, $end); - $spentWithout = $this->noCatRepository->listExpenses($start, $end); - - /** @var array $set */ - foreach ([$spentWith, $spentWithout,] as $set) { - $tempData = $this->processArray($tempData, $set); - } - - $chartData = $this->sortArray($tempData); - - return response()->json($chartData); - } - - /** - * @param array $tempData - * @param array $set - * @deprecated - * @return array - */ - private function processArray(array $tempData, array $set): array - { - foreach ($set as $currency) { - foreach ($currency['categories'] as $category) { - $this->categories[] = $category['name']; - $outKey = sprintf('%d-e', $currency['currency_id']); - $tempData[$outKey] = $tempData[$outKey] ?? [ - 'currency_id' => $currency['currency_id'], - 'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]), - 'currency_code' => $currency['currency_code'], - 'currency_symbol' => $currency['currency_symbol'], - 'currency_decimal_places' => $currency['currency_decimal_places'], - 'type' => 'bar', // line, area or bar - 'yAxisID' => 0, // 0, 1, 2 - 'entries' => [], - ]; - - foreach ($category['transaction_journals'] as $journal) { - // is it expense or income? - $currentKey = sprintf('%d-%s', $currency['currency_id'], 'e'); - $name = $category['name']; - $tempData[$currentKey]['entries'][$name] = $tempData[$currentKey]['entries'][$name] ?? '0'; - $tempData[$currentKey]['entries'][$name] = bcadd($tempData[$currentKey]['entries'][$name], $journal['amount']); - } - } - } - - return $tempData; - } - - /** - * @param array $tempData - * @deprecated - * @return array - */ - private function sortArray(array $tempData): array - { - // re-sort every spent array and add 0 for missing entries. - foreach ($tempData as $index => $set) { - $oldSet = $set['entries']; - $newSet = []; - foreach ($this->categories as $category) { - $value = $oldSet[$category] ?? '0'; - $value = -1 === bccomp($value, '0') ? bcmul($value, '-1') : $value; - $newSet[$category] = $value; - } - $tempData[$index]['entries'] = $newSet; - } - - return array_values($tempData); - } -} diff --git a/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php b/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php index c3f980007f..5c988790f4 100644 --- a/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Recurrence/UpdateController.php @@ -73,14 +73,14 @@ class UpdateController extends Controller public function update(UpdateRequest $request, Recurrence $recurrence): JsonResponse { $data = $request->getAll(); - $category = $this->repository->update($recurrence, $data); + $recurrence = $this->repository->update($recurrence, $data); $manager = $this->getManager(); /** @var RecurrenceTransformer $transformer */ $transformer = app(RecurrenceTransformer::class); $transformer->setParameters($this->parameters); - $resource = new Item($category, $transformer, 'recurrences'); + $resource = new Item($recurrence, $transformer, 'recurrences'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php index 0a44df523a..6c3aea75c3 100644 --- a/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Recurrence/UpdateRequest.php @@ -43,7 +43,6 @@ class UpdateRequest extends FormRequest use ConvertsDataTypes, RecurrenceValidation, TransactionValidation, CurrencyValidation, GetRecurrenceData, ChecksLogin; - /** * Get all data from the request. * @@ -51,46 +50,46 @@ class UpdateRequest extends FormRequest */ public function getAll(): array { - $active = null; - $applyRules = null; - if (null !== $this->get('active')) { - $active = $this->boolean('active'); + // this is the way: + $fields = [ + 'title' => ['title', 'string'], + 'description' => ['description', 'string'], + 'first_date' => ['first_date', 'date'], + 'repeat_until' => ['repeat_until', 'date'], + 'nr_of_repetitions' => ['nr_of_repetitions', 'integer'], + 'apply_rules' => ['apply_rules', 'boolean'], + 'active' => ['active', 'boolean'], + 'notes' => ['notes', 'string'], + ]; + $reps = $this->getRepetitionData(); + $transactions = $this->getTransactionData(); + $return = [ + 'recurrence' => $this->getAllData($fields), + ]; + if (null !== $reps) { + $return['repetitions'] = $reps; } - if (null !== $this->get('apply_rules')) { - $applyRules = $this->boolean('apply_rules'); + if (null !== $transactions) { + $return['transactions'] = $transactions; } - return [ - 'recurrence' => [ - 'type' => $this->nullableString('type'), - 'title' => $this->nullableString('title'), - 'description' => $this->nullableString('description'), - 'first_date' => $this->date('first_date'), - 'notes' => $this->nullableNlString('notes'), - 'repeat_until' => $this->date('repeat_until'), - 'nr_of_repetitions' => $this->nullableInteger('nr_of_repetitions'), - 'apply_rules' => $applyRules, - 'active' => $active, - ], - 'transactions' => $this->getTransactionData(), - 'repetitions' => $this->getRepetitionData(), - ]; + return $return; } /** * Returns the transaction data as it is found in the submitted data. It's a complex method according to code * standards but it just has a lot of ??-statements because of the fields that may or may not exist. * - * @return array + * @return array|null */ - private function getTransactionData(): array + private function getTransactionData(): ?array { $return = []; // transaction data: /** @var array $transactions */ $transactions = $this->get('transactions'); if (null === $transactions) { - return []; + return null; } /** @var array $transaction */ foreach ($transactions as $transaction) { @@ -103,25 +102,36 @@ class UpdateRequest extends FormRequest /** * Returns the repetition data as it is found in the submitted data. * - * @return array + * @return array|null */ - private function getRepetitionData(): array + private function getRepetitionData(): ?array { $return = []; // repetition data: /** @var array $repetitions */ $repetitions = $this->get('repetitions'); if (null === $repetitions) { - return []; + return null; } /** @var array $repetition */ foreach ($repetitions as $repetition) { - $return[] = [ - 'type' => $repetition['type'], - 'moment' => $repetition['moment'], - 'skip' => (int) $repetition['skip'], - 'weekend' => (int) $repetition['weekend'], - ]; + $current = []; + if(array_key_exists('type', $repetition)) { + $current['type'] = $repetition['type']; + } + + if(array_key_exists('moment', $repetition)) { + $current['moment'] = $repetition['moment']; + } + + if(array_key_exists('skip', $repetition)) { + $current['skip'] = (int)$repetition['skip']; + } + + if(array_key_exists('weekend', $repetition)) { + $current['weekend'] = (int) $repetition['weekend']; + } + $return[] = $current; } return $return; @@ -138,7 +148,6 @@ class UpdateRequest extends FormRequest $recurrence = $this->route()->parameter('recurrence'); return [ - 'type' => 'in:withdrawal,transfer,deposit', 'title' => sprintf('between:1,255|uniqueObjectForUser:recurrences,title,%d', $recurrence->id), 'description' => 'between:1,65000', 'first_date' => 'date', @@ -148,11 +157,11 @@ class UpdateRequest extends FormRequest 'nr_of_repetitions' => 'numeric|between:1,31', 'repetitions.*.type' => 'in:daily,weekly,ndom,monthly,yearly', 'repetitions.*.moment' => 'between:0,10', - 'repetitions.*.skip' => 'required|numeric|between:0,31', - 'repetitions.*.weekend' => 'required|numeric|min:1|max:4', + 'repetitions.*.skip' => 'numeric|between:0,31', + 'repetitions.*.weekend' => 'numeric|min:1|max:4', - 'transactions.*.description' => 'required|between:1,255', - 'transactions.*.amount' => 'required|numeric|gt:0', + 'transactions.*.description' => 'between:1,255', + 'transactions.*.amount' => 'numeric|gt:0', 'transactions.*.foreign_amount' => 'numeric|gt:0', 'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id', 'transactions.*.currency_code' => 'min:3|max:3|exists:transaction_currencies,code', @@ -186,9 +195,9 @@ class UpdateRequest extends FormRequest { $validator->after( function (Validator $validator) { - $this->validateOneRecurrenceTransaction($validator); - $this->validateOneRepetitionUpdate($validator); - $this->validateRecurrenceRepetition($validator); + //$this->validateOneRecurrenceTransaction($validator); + //$this->validateOneRepetitionUpdate($validator); + //$this->validateRecurrenceRepetition($validator); $this->validateRepetitionMoment($validator); $this->validateForeignCurrencyInformation($validator); $this->valUpdateAccountInfo($validator); diff --git a/app/Console/Commands/Upgrade/MigrateRecurrenceType.php b/app/Console/Commands/Upgrade/MigrateRecurrenceType.php index 0a2ee674e8..bb86826544 100644 --- a/app/Console/Commands/Upgrade/MigrateRecurrenceType.php +++ b/app/Console/Commands/Upgrade/MigrateRecurrenceType.php @@ -42,7 +42,7 @@ class MigrateRecurrenceType extends Command $this->migrateTypes(); - //$this->markAsExecuted(); + $this->markAsExecuted(); $end = round(microtime(true) - $start, 2); $this->info(sprintf('Update recurring transaction types in %s seconds.', $end)); diff --git a/app/Repositories/Recurring/RecurringRepository.php b/app/Repositories/Recurring/RecurringRepository.php index 05780c8bbe..80ba813e26 100644 --- a/app/Repositories/Recurring/RecurringRepository.php +++ b/app/Repositories/Recurring/RecurringRepository.php @@ -570,7 +570,6 @@ class RecurringRepository implements RecurringRepositoryInterface { /** @var RecurrenceUpdateService $service */ $service = app(RecurrenceUpdateService::class); - return $service->update($recurrence, $data); } diff --git a/app/Services/Internal/Update/AccountUpdateService.php b/app/Services/Internal/Update/AccountUpdateService.php index 9380edd624..2393772dd6 100644 --- a/app/Services/Internal/Update/AccountUpdateService.php +++ b/app/Services/Internal/Update/AccountUpdateService.php @@ -108,31 +108,31 @@ class AccountUpdateService /** * @param Account $account * @param array $data + * + * @return Account */ - private function updateLocation(Account $account, array $data): void + private function updateAccount(Account $account, array $data): Account { - $updateLocation = $data['update_location'] ?? false; - // location must be updated? - if (true === $updateLocation) { - // if all set to NULL, delete - if (null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level']) { - $account->locations()->delete(); - } + // update the account itself: + $account->name = $data['name'] ?? $account->name; + $account->active = $data['active'] ?? $account->active; + $account->iban = $data['iban'] ?? $account->iban; - // otherwise, update or create. - if (!(null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level'])) { - $location = $this->accountRepository->getLocation($account); - if (null === $location) { - $location = new Location; - $location->locatable()->associate($account); - } - - $location->latitude = $data['latitude'] ?? config('firefly.default_location.latitude'); - $location->longitude = $data['longitude'] ?? config('firefly.default_location.longitude'); - $location->zoom_level = $data['zoom_level'] ?? config('firefly.default_location.zoom_level'); - $location->save(); - } + // liability stuff: + $liabilityType = $data['liability_type'] ?? ''; + if ($this->isLiability($account) && $this->isLiabilityType($liabilityType)) { + $type = $this->getAccountType($liabilityType); + $account->account_type_id = $type->id; } + + // update virtual balance (could be set to zero if empty string). + if (null !== $data['virtual_balance']) { + $account->virtual_balance = '' === trim($data['virtual_balance']) ? '0' : $data['virtual_balance']; + } + + $account->save(); + + return $account; } /** @@ -169,93 +169,6 @@ class AccountUpdateService return AccountType::whereType($type)->first(); } - /** - * @param Account $account - * @param array $data - * - * @return Account - */ - private function updateAccount(Account $account, array $data): Account - { - // update the account itself: - $account->name = $data['name'] ?? $account->name; - $account->active = $data['active'] ?? $account->active; - $account->iban = $data['iban'] ?? $account->iban; - - // liability stuff: - $liabilityType = $data['liability_type'] ?? ''; - if ($this->isLiability($account) && $this->isLiabilityType($liabilityType)) { - $type = $this->getAccountType($liabilityType); - $account->account_type_id = $type->id; - } - - // update virtual balance (could be set to zero if empty string). - if (null !== $data['virtual_balance']) { - $account->virtual_balance = '' === trim($data['virtual_balance']) ? '0' : $data['virtual_balance']; - } - - $account->save(); - - return $account; - } - - /** - * @param Account $account - * @param array $data - */ - private function updatePreferences(Account $account, array $data): void - { - Log::debug(sprintf('Now in updatePreferences(#%d)', $account->id)); - if (array_key_exists('active', $data) && (false === $data['active'] || 0 === $data['active'])) { - Log::debug('Account was marked as inactive.'); - $preference = app('preferences')->getForUser($account->user, 'frontpageAccounts'); - if (null !== $preference) { - $removeAccountId = (int)$account->id; - $array = $preference->data; - Log::debug('Current list of accounts: ', $array); - Log::debug(sprintf('Going to remove account #%d', $removeAccountId)); - $filtered = array_filter( - $array, function ($accountId) use ($removeAccountId) { - return (int)$accountId !== $removeAccountId; - } - ); - Log::debug('Left with accounts', array_values($filtered)); - app('preferences')->setForUser($account->user, 'frontpageAccounts', array_values($filtered)); - app('preferences')->forget($account->user, 'frontpageAccounts'); - - return; - } - Log::debug("Found no frontpageAccounts preference, do nothing."); - - return; - } - Log::debug('Account was not marked as inactive, do nothing.'); - } - - /** - * @param Account $account - * @param array $data - */ - private function updateOpeningBalance(Account $account, array $data): void - { - - // has valid initial balance (IB) data? - $type = $account->accountType; - // if it can have a virtual balance, it can also have an opening balance. - - if (in_array($type->type, $this->canHaveVirtual, true)) { - - // check if is submitted as empty, that makes it valid: - if ($this->validOBData($data) && !$this->isEmptyOBData($data)) { - $this->updateOBGroup($account, $data); - } - - if (!$this->validOBData($data) && $this->isEmptyOBData($data)) { - $this->deleteOBGroup($account); - } - } - } - /** * @param Account $account * @param array $data @@ -314,4 +227,91 @@ class AccountUpdateService return $return; } + + /** + * @param Account $account + * @param array $data + */ + private function updateLocation(Account $account, array $data): void + { + $updateLocation = $data['update_location'] ?? false; + // location must be updated? + if (true === $updateLocation) { + // if all set to NULL, delete + if (null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level']) { + $account->locations()->delete(); + } + + // otherwise, update or create. + if (!(null === $data['latitude'] && null === $data['longitude'] && null === $data['zoom_level'])) { + $location = $this->accountRepository->getLocation($account); + if (null === $location) { + $location = new Location; + $location->locatable()->associate($account); + } + + $location->latitude = $data['latitude'] ?? config('firefly.default_location.latitude'); + $location->longitude = $data['longitude'] ?? config('firefly.default_location.longitude'); + $location->zoom_level = $data['zoom_level'] ?? config('firefly.default_location.zoom_level'); + $location->save(); + } + } + } + + /** + * @param Account $account + * @param array $data + */ + private function updateOpeningBalance(Account $account, array $data): void + { + + // has valid initial balance (IB) data? + $type = $account->accountType; + // if it can have a virtual balance, it can also have an opening balance. + + if (in_array($type->type, $this->canHaveVirtual, true)) { + + // check if is submitted as empty, that makes it valid: + if ($this->validOBData($data) && !$this->isEmptyOBData($data)) { + $this->updateOBGroup($account, $data); + } + + if (!$this->validOBData($data) && $this->isEmptyOBData($data)) { + $this->deleteOBGroup($account); + } + } + } + + /** + * @param Account $account + * @param array $data + */ + private function updatePreferences(Account $account, array $data): void + { + Log::debug(sprintf('Now in updatePreferences(#%d)', $account->id)); + if (array_key_exists('active', $data) && (false === $data['active'] || 0 === $data['active'])) { + Log::debug('Account was marked as inactive.'); + $preference = app('preferences')->getForUser($account->user, 'frontpageAccounts'); + if (null !== $preference) { + $removeAccountId = (int)$account->id; + $array = $preference->data; + Log::debug('Current list of accounts: ', $array); + Log::debug(sprintf('Going to remove account #%d', $removeAccountId)); + $filtered = array_filter( + $array, function ($accountId) use ($removeAccountId) { + return (int)$accountId !== $removeAccountId; + } + ); + Log::debug('Left with accounts', array_values($filtered)); + app('preferences')->setForUser($account->user, 'frontpageAccounts', array_values($filtered)); + app('preferences')->forget($account->user, 'frontpageAccounts'); + + return; + } + Log::debug("Found no frontpageAccounts preference, do nothing."); + + return; + } + Log::debug('Account was not marked as inactive, do nothing.'); + } } diff --git a/app/Services/Internal/Update/BillUpdateService.php b/app/Services/Internal/Update/BillUpdateService.php index ca4168ebf0..2aeffabf75 100644 --- a/app/Services/Internal/Update/BillUpdateService.php +++ b/app/Services/Internal/Update/BillUpdateService.php @@ -136,6 +136,69 @@ class BillUpdateService return $bill; } + /** + * @param Bill $bill + * @param array $data + * + * @return Bill + */ + private function updateBillProperties(Bill $bill, array $data): Bill + { + + if (isset($data['name']) && '' !== (string)$data['name']) { + $bill->name = $data['name']; + } + + if (isset($data['amount_min']) && '' !== (string)$data['amount_min']) { + $bill->amount_min = $data['amount_min']; + } + if (isset($data['amount_max']) && '' !== (string)$data['amount_max']) { + $bill->amount_max = $data['amount_max']; + } + if (isset($data['date']) && '' !== (string)$data['date']) { + $bill->date = $data['date']; + } + if (isset($data['repeat_freq']) && '' !== (string)$data['repeat_freq']) { + $bill->repeat_freq = $data['repeat_freq']; + } + if (isset($data['skip']) && '' !== (string)$data['skip']) { + $bill->skip = $data['skip']; + } + if (isset($data['active']) && is_bool($data['active'])) { + $bill->active = $data['active']; + } + + $bill->match = 'EMPTY'; + $bill->automatch = true; + $bill->save(); + + return $bill; + } + + /** + * @param Bill $bill + * @param int $oldOrder + * @param int $newOrder + */ + private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void + { + if ($newOrder > $oldOrder) { + $this->user->bills()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder) + ->where('bills.id', '!=', $bill->id) + ->update(['order' => DB::raw('bills.order-1')]); + $bill->order = $newOrder; + $bill->save(); + } + if ($newOrder < $oldOrder) { + $this->user->bills()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder) + ->where('bills.id', '!=', $bill->id) + ->update(['order' => DB::raw('bills.order+1')]); + $bill->order = $newOrder; + $bill->save(); + } + + } + /** * @param Bill $bill * @param array $oldData @@ -195,7 +258,6 @@ class BillUpdateService } } - /** * @param Rule $rule * @param string $key @@ -206,67 +268,4 @@ class BillUpdateService { return $rule->ruleTriggers()->where('trigger_type', $key)->first(); } - - /** - * @param Bill $bill - * @param int $oldOrder - * @param int $newOrder - */ - private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void - { - if ($newOrder > $oldOrder) { - $this->user->bills()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder) - ->where('bills.id', '!=', $bill->id) - ->update(['order' => DB::raw('bills.order-1')]); - $bill->order = $newOrder; - $bill->save(); - } - if ($newOrder < $oldOrder) { - $this->user->bills()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder) - ->where('bills.id', '!=', $bill->id) - ->update(['order' => DB::raw('bills.order+1')]); - $bill->order = $newOrder; - $bill->save(); - } - - } - - /** - * @param Bill $bill - * @param array $data - * - * @return Bill - */ - private function updateBillProperties(Bill $bill, array $data): Bill - { - - if (isset($data['name']) && '' !== (string)$data['name']) { - $bill->name = $data['name']; - } - - if (isset($data['amount_min']) && '' !== (string)$data['amount_min']) { - $bill->amount_min = $data['amount_min']; - } - if (isset($data['amount_max']) && '' !== (string)$data['amount_max']) { - $bill->amount_max = $data['amount_max']; - } - if (isset($data['date']) && '' !== (string)$data['date']) { - $bill->date = $data['date']; - } - if (isset($data['repeat_freq']) && '' !== (string)$data['repeat_freq']) { - $bill->repeat_freq = $data['repeat_freq']; - } - if (isset($data['skip']) && '' !== (string)$data['skip']) { - $bill->skip = $data['skip']; - } - if (isset($data['active']) && is_bool($data['active'])) { - $bill->active = $data['active']; - } - - $bill->match = 'EMPTY'; - $bill->automatch = true; - $bill->save(); - - return $bill; - } } diff --git a/app/Services/Internal/Update/CategoryUpdateService.php b/app/Services/Internal/Update/CategoryUpdateService.php index aa78e1161a..5a00fd9da5 100644 --- a/app/Services/Internal/Update/CategoryUpdateService.php +++ b/app/Services/Internal/Update/CategoryUpdateService.php @@ -23,13 +23,13 @@ declare(strict_types=1); namespace FireflyIII\Services\Internal\Update; +use Exception; use FireflyIII\Models\Category; use FireflyIII\Models\Note; use FireflyIII\Models\RecurrenceTransactionMeta; use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleTrigger; use Log; -use Exception; /** * Class CategoryUpdateService @@ -54,6 +54,14 @@ class CategoryUpdateService } } + /** + * @param mixed $user + */ + public function setUser($user): void + { + $this->user = $user; + } + /** * @param Category $category * @param array $data @@ -75,27 +83,6 @@ class CategoryUpdateService return $category; } - /** - * @param string $oldName - * @param string $newName - */ - private function updateRuleActions(string $oldName, string $newName): void - { - $types = ['set_category',]; - $actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id') - ->where('rules.user_id', $this->user->id) - ->whereIn('rule_actions.action_type', $types) - ->where('rule_actions.action_value', $oldName) - ->get(['rule_actions.*']); - Log::debug(sprintf('Found %d actions to update.', $actions->count())); - /** @var RuleAction $action */ - foreach ($actions as $action) { - $action->action_value = $newName; - $action->save(); - Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value)); - } - } - /** * @param string $oldName * @param string $newName @@ -118,11 +105,24 @@ class CategoryUpdateService } /** - * @param mixed $user + * @param string $oldName + * @param string $newName */ - public function setUser($user): void + private function updateRuleActions(string $oldName, string $newName): void { - $this->user = $user; + $types = ['set_category',]; + $actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id') + ->where('rules.user_id', $this->user->id) + ->whereIn('rule_actions.action_type', $types) + ->where('rule_actions.action_value', $oldName) + ->get(['rule_actions.*']); + Log::debug(sprintf('Found %d actions to update.', $actions->count())); + /** @var RuleAction $action */ + foreach ($actions as $action) { + $action->action_value = $newName; + $action->save(); + Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value)); + } } /** @@ -145,7 +145,7 @@ class CategoryUpdateService * @param Category $category * @param array $data * - * @throws \Exception + * @throws Exception */ private function updateNotes(Category $category, array $data): void { diff --git a/app/Services/Internal/Update/GroupCloneService.php b/app/Services/Internal/Update/GroupCloneService.php index e5fb261197..81abc35a3f 100644 --- a/app/Services/Internal/Update/GroupCloneService.php +++ b/app/Services/Internal/Update/GroupCloneService.php @@ -108,16 +108,15 @@ class GroupCloneService } /** - * @param TransactionJournalMeta $meta - * @param TransactionJournal $newJournal + * @param Transaction $transaction + * @param TransactionJournal $newJournal */ - private function cloneMeta(TransactionJournalMeta $meta, TransactionJournal $newJournal): void + private function cloneTransaction(Transaction $transaction, TransactionJournal $newJournal): void { - $newMeta = $meta->replicate(); - $newMeta->transaction_journal_id = $newJournal->id; - if ('recurrence_id' !== $newMeta->name) { - $newMeta->save(); - } + $newTransaction = $transaction->replicate(); + $newTransaction->transaction_journal_id = $newJournal->id; + $newTransaction->reconciled = false; + $newTransaction->save(); } /** @@ -137,15 +136,16 @@ class GroupCloneService } /** - * @param Transaction $transaction - * @param TransactionJournal $newJournal + * @param TransactionJournalMeta $meta + * @param TransactionJournal $newJournal */ - private function cloneTransaction(Transaction $transaction, TransactionJournal $newJournal): void + private function cloneMeta(TransactionJournalMeta $meta, TransactionJournal $newJournal): void { - $newTransaction = $transaction->replicate(); - $newTransaction->transaction_journal_id = $newJournal->id; - $newTransaction->reconciled = false; - $newTransaction->save(); + $newMeta = $meta->replicate(); + $newMeta->transaction_journal_id = $newJournal->id; + if ('recurrence_id' !== $newMeta->name) { + $newMeta->save(); + } } diff --git a/app/Services/Internal/Update/GroupUpdateService.php b/app/Services/Internal/Update/GroupUpdateService.php index d6ae83693e..0c7bf27885 100644 --- a/app/Services/Internal/Update/GroupUpdateService.php +++ b/app/Services/Internal/Update/GroupUpdateService.php @@ -96,37 +96,6 @@ class GroupUpdateService return $transactionGroup; } - /** - * @param TransactionGroup $transactionGroup - * @param array $data - * - * @throws FireflyException - */ - private function createTransactionJournal(TransactionGroup $transactionGroup, array $data): void - { - - $submission = [ - 'transactions' => [ - $data, - ], - ]; - /** @var TransactionJournalFactory $factory */ - $factory = app(TransactionJournalFactory::class); - $factory->setUser($transactionGroup->user); - try { - $collection = $factory->create($submission); - } catch (FireflyException $e) { - Log::error($e->getMessage()); - Log::error($e->getTraceAsString()); - throw new FireflyException(sprintf('Could not create new transaction journal: %s', $e->getMessage())); - } - $collection->each( - function (TransactionJournal $journal) use ($transactionGroup) { - $transactionGroup->transactionJournals()->save($journal); - } - ); - } - /** * Update single journal. * @@ -191,4 +160,35 @@ class GroupUpdateService return $updated; } + /** + * @param TransactionGroup $transactionGroup + * @param array $data + * + * @throws FireflyException + */ + private function createTransactionJournal(TransactionGroup $transactionGroup, array $data): void + { + + $submission = [ + 'transactions' => [ + $data, + ], + ]; + /** @var TransactionJournalFactory $factory */ + $factory = app(TransactionJournalFactory::class); + $factory->setUser($transactionGroup->user); + try { + $collection = $factory->create($submission); + } catch (FireflyException $e) { + Log::error($e->getMessage()); + Log::error($e->getTraceAsString()); + throw new FireflyException(sprintf('Could not create new transaction journal: %s', $e->getMessage())); + } + $collection->each( + function (TransactionJournal $journal) use ($transactionGroup) { + $transactionGroup->transactionJournals()->save($journal); + } + ); + } + } diff --git a/app/Services/Internal/Update/JournalUpdateService.php b/app/Services/Internal/Update/JournalUpdateService.php index ee893e6154..5394209ba8 100644 --- a/app/Services/Internal/Update/JournalUpdateService.php +++ b/app/Services/Internal/Update/JournalUpdateService.php @@ -161,47 +161,61 @@ class JournalUpdateService } /** - * Get destination transaction. - * - * @return Transaction + * @return bool */ - private function getDestinationTransaction(): Transaction + private function hasValidAccounts(): bool { - if (null === $this->destinationTransaction) { - $this->destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first(); - } - - return $this->destinationTransaction; + return $this->hasValidSourceAccount() && $this->hasValidDestinationAccount(); } /** - * This method returns the current or expected type of the journal (in case of a change) based on the data in the array. - * - * If the array contains key 'type' and the value is correct, this is returned. Otherwise, the original type is returned. - * - * @return string + * @return bool */ - private function getExpectedType(): string + private function hasValidSourceAccount(): bool { - Log::debug('Now in getExpectedType()'); - if ($this->hasFields(['type'])) { - return ucfirst('opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']); + Log::debug('Now in hasValidSourceAccount().'); + $sourceId = $this->data['source_id'] ?? null; + $sourceName = $this->data['source_name'] ?? null; + + if (!$this->hasFields(['source_id', 'source_name'])) { + $origSourceAccount = $this->getOriginalSourceAccount(); + $sourceId = $origSourceAccount->id; + $sourceName = $origSourceAccount->name; } - return $this->transactionJournal->transactionType->type; + // make new account validator. + $expectedType = $this->getExpectedType(); + Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType)); + + // make a new validator. + /** @var AccountValidator $validator */ + $validator = app(AccountValidator::class); + $validator->setTransactionType($expectedType); + $validator->setUser($this->transactionJournal->user); + + $result = $validator->validateSource($sourceId, $sourceName, null); + Log::debug(sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true))); + + // TODO typeOverrule: the account validator may have another opinion on the transaction type. + + // validate submitted info: + return $result; } /** - * @return Account + * @param array $fields + * + * @return bool */ - private function getOriginalDestinationAccount(): Account + private function hasFields(array $fields): bool { - if (null === $this->destinationAccount) { - $destination = $this->getDestinationTransaction(); - $this->destinationAccount = $destination->account; + foreach ($fields as $field) { + if (array_key_exists($field, $this->data)) { + return true; + } } - return $this->destinationAccount; + return false; } /** @@ -231,96 +245,20 @@ class JournalUpdateService } /** - * Does a validation and returns the destination account. This method will break if the dest isn't really valid. + * This method returns the current or expected type of the journal (in case of a change) based on the data in the array. * - * @return Account - */ - private function getValidDestinationAccount(): Account - { - Log::debug('Now in getValidDestinationAccount().'); - - if (!$this->hasFields(['destination_id', 'destination_name'])) { - return $this->getOriginalDestinationAccount(); - } - - $destInfo = [ - 'id' => (int)($this->data['destination_id'] ?? null), - 'name' => $this->data['destination_name'] ?? null, - 'iban' => $this->data['destination_iban'] ?? null, - 'number' => $this->data['destination_number'] ?? null, - 'bic' => $this->data['destination_bic'] ?? null, - ]; - - // make new account validator. - $expectedType = $this->getExpectedType(); - Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType)); - try { - $result = $this->getAccount($expectedType, 'destination', $destInfo); - } catch (FireflyException $e) { - Log::error(sprintf('getValidDestinationAccount() threw unexpected error: %s', $e->getMessage())); - $result = $this->getOriginalDestinationAccount(); - } - - return $result; - } - - /** - * Does a validation and returns the source account. This method will break if the source isn't really valid. + * If the array contains key 'type' and the value is correct, this is returned. Otherwise, the original type is returned. * - * @return Account + * @return string */ - private function getValidSourceAccount(): Account + private function getExpectedType(): string { - Log::debug('Now in getValidSourceAccount().'); - - if (!$this->hasFields(['source_id', 'source_name'])) { - return $this->getOriginalSourceAccount(); + Log::debug('Now in getExpectedType()'); + if ($this->hasFields(['type'])) { + return ucfirst('opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']); } - $sourceInfo = [ - 'id' => (int)($this->data['source_id'] ?? null), - 'name' => $this->data['source_name'] ?? null, - 'iban' => $this->data['source_iban'] ?? null, - 'number' => $this->data['source_number'] ?? null, - 'bic' => $this->data['source_bic'] ?? null, - ]; - - $expectedType = $this->getExpectedType(); - try { - $result = $this->getAccount($expectedType, 'source', $sourceInfo); - } catch (FireflyException $e) { - Log::error(sprintf('Cant get the valid source account: %s', $e->getMessage())); - - $result = $this->getOriginalSourceAccount(); - } - - Log::debug(sprintf('getValidSourceAccount() will return #%d ("%s")', $result->id, $result->name)); - - return $result; - } - - /** - * @param array $fields - * - * @return bool - */ - private function hasFields(array $fields): bool - { - foreach ($fields as $field) { - if (array_key_exists($field, $this->data)) { - return true; - } - } - - return false; - } - - /** - * @return bool - */ - private function hasValidAccounts(): bool - { - return $this->hasValidSourceAccount() && $this->hasValidDestinationAccount(); + return $this->transactionJournal->transactionType->type; } /** @@ -361,36 +299,64 @@ class JournalUpdateService } /** - * @return bool + * @return Account */ - private function hasValidSourceAccount(): bool + private function getOriginalDestinationAccount(): Account { - Log::debug('Now in hasValidSourceAccount().'); - $sourceId = $this->data['source_id'] ?? null; - $sourceName = $this->data['source_name'] ?? null; - - if (!$this->hasFields(['source_id', 'source_name'])) { - $origSourceAccount = $this->getOriginalSourceAccount(); - $sourceId = $origSourceAccount->id; - $sourceName = $origSourceAccount->name; + if (null === $this->destinationAccount) { + $destination = $this->getDestinationTransaction(); + $this->destinationAccount = $destination->account; } - // make new account validator. + return $this->destinationAccount; + } + + /** + * Get destination transaction. + * + * @return Transaction + */ + private function getDestinationTransaction(): Transaction + { + if (null === $this->destinationTransaction) { + $this->destinationTransaction = $this->transactionJournal->transactions()->where('amount', '>', 0)->first(); + } + + return $this->destinationTransaction; + } + + /** + * Does a validation and returns the source account. This method will break if the source isn't really valid. + * + * @return Account + */ + private function getValidSourceAccount(): Account + { + Log::debug('Now in getValidSourceAccount().'); + + if (!$this->hasFields(['source_id', 'source_name'])) { + return $this->getOriginalSourceAccount(); + } + + $sourceInfo = [ + 'id' => (int)($this->data['source_id'] ?? null), + 'name' => $this->data['source_name'] ?? null, + 'iban' => $this->data['source_iban'] ?? null, + 'number' => $this->data['source_number'] ?? null, + 'bic' => $this->data['source_bic'] ?? null, + ]; + $expectedType = $this->getExpectedType(); - Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType)); + try { + $result = $this->getAccount($expectedType, 'source', $sourceInfo); + } catch (FireflyException $e) { + Log::error(sprintf('Cant get the valid source account: %s', $e->getMessage())); - // make a new validator. - /** @var AccountValidator $validator */ - $validator = app(AccountValidator::class); - $validator->setTransactionType($expectedType); - $validator->setUser($this->transactionJournal->user); + $result = $this->getOriginalSourceAccount(); + } - $result = $validator->validateSource($sourceId, $sourceName, null); - Log::debug(sprintf('hasValidSourceAccount(%d, "%s") will return %s', $sourceId, $sourceName, var_export($result, true))); + Log::debug(sprintf('getValidSourceAccount() will return #%d ("%s")', $result->id, $result->name)); - // TODO typeOverrule: the account validator may have another opinion on the transaction type. - - // validate submitted info: return $result; } @@ -427,36 +393,68 @@ class JournalUpdateService } /** + * Does a validation and returns the destination account. This method will break if the dest isn't really valid. * + * @return Account */ - private function updateAmount(): void + private function getValidDestinationAccount(): Account { - if (!$this->hasFields(['amount'])) { - return; + Log::debug('Now in getValidDestinationAccount().'); + + if (!$this->hasFields(['destination_id', 'destination_name'])) { + return $this->getOriginalDestinationAccount(); } - $value = $this->data['amount'] ?? ''; + $destInfo = [ + 'id' => (int)($this->data['destination_id'] ?? null), + 'name' => $this->data['destination_name'] ?? null, + 'iban' => $this->data['destination_iban'] ?? null, + 'number' => $this->data['destination_number'] ?? null, + 'bic' => $this->data['destination_bic'] ?? null, + ]; + + // make new account validator. + $expectedType = $this->getExpectedType(); + Log::debug(sprintf('Expected type (new or unchanged) is %s', $expectedType)); try { - $amount = $this->getAmount($value); + $result = $this->getAccount($expectedType, 'destination', $destInfo); } catch (FireflyException $e) { - Log::debug(sprintf('getAmount("%s") returns error: %s', $value, $e->getMessage())); + Log::error(sprintf('getValidDestinationAccount() threw unexpected error: %s', $e->getMessage())); + $result = $this->getOriginalDestinationAccount(); + } + + return $result; + } + + /** + * Updates journal transaction type. + */ + private function updateType(): void + { + Log::debug('Now in updateType()'); + if ($this->hasFields(['type'])) { + $type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']; + Log::debug( + sprintf( + 'Trying to change journal #%d from a %s to a %s.', + $this->transactionJournal->id, $this->transactionJournal->transactionType->type, $type + ) + ); + + /** @var TransactionTypeFactory $typeFactory */ + $typeFactory = app(TransactionTypeFactory::class); + $result = $typeFactory->find($this->data['type']); + if (null !== $result) { + Log::debug('Changed transaction type!'); + $this->transactionJournal->transaction_type_id = $result->id; + $this->transactionJournal->save(); + + return; + } return; } - $origSourceTransaction = $this->getSourceTransaction(); - $origSourceTransaction->amount = app('steam')->negative($amount); - $origSourceTransaction->save(); - - - $destTransaction = $this->getDestinationTransaction(); - $destTransaction->amount = app('steam')->positive($amount); - $destTransaction->save(); - - - // refresh transactions. - $this->sourceTransaction->refresh(); - $this->destinationTransaction->refresh(); - Log::debug(sprintf('Updated amount to "%s"', $amount)); + Log::debug('No type field present.'); } /** @@ -479,6 +477,47 @@ class JournalUpdateService } } + /** + * Update journal generic field. Cannot be set to NULL. + * + * @param string $fieldName + */ + private function updateField(string $fieldName): void + { + if (array_key_exists($fieldName, $this->data) && '' !== (string)$this->data[$fieldName]) { + $value = $this->data[$fieldName]; + + if ('date' === $fieldName) { + if ($value instanceof Carbon) { + // update timezone. + $value->setTimezone(config('app.timezone')); + } + if (!($value instanceof Carbon)) { + $value = new Carbon($value); + } + // do some parsing. + Log::debug(sprintf('Create date value from string "%s".', $value)); + } + + + $this->transactionJournal->$fieldName = $value; + Log::debug(sprintf('Updated %s', $fieldName)); + } + } + + /** + * + */ + private function updateCategory(): void + { + // update category + if ($this->hasFields(['category_id', 'category_name'])) { + Log::debug('Will update category.'); + + $this->storeCategory($this->transactionJournal, new NullArrayObject($this->data)); + } + } + /** * */ @@ -494,13 +533,103 @@ class JournalUpdateService /** * */ - private function updateCategory(): void + private function updateTags(): void { - // update category - if ($this->hasFields(['category_id', 'category_name'])) { - Log::debug('Will update category.'); + if ($this->hasFields(['tags'])) { + Log::debug('Will update tags.'); + $tags = $this->data['tags'] ?? null; + $this->storeTags($this->transactionJournal, $tags); + } + } - $this->storeCategory($this->transactionJournal, new NullArrayObject($this->data)); + /** + * + */ + private function updateReconciled(): void + { + if (array_key_exists('reconciled', $this->data) && is_bool($this->data['reconciled'])) { + $this->transactionJournal->transactions()->update(['reconciled' => $this->data['reconciled']]); + } + } + + /** + * + */ + private function updateNotes(): void + { + // update notes. + if ($this->hasFields(['notes'])) { + $notes = '' === (string)$this->data['notes'] ? null : $this->data['notes']; + $this->storeNotes($this->transactionJournal, $notes); + } + } + + /** + * + */ + private function updateMeta(): void + { + // update meta fields. + // first string + if ($this->hasFields($this->metaString)) { + Log::debug('Meta string fields are present.'); + $this->updateMetaFields(); + } + + // then date fields. + if ($this->hasFields($this->metaDate)) { + Log::debug('Meta date fields are present.'); + $this->updateMetaDateFields(); + } + } + + /** + * + */ + private function updateMetaFields(): void + { + /** @var TransactionJournalMetaFactory $factory */ + $factory = app(TransactionJournalMetaFactory::class); + + foreach ($this->metaString as $field) { + if ($this->hasFields([$field])) { + $value = '' === $this->data[$field] ? null : $this->data[$field]; + Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value)); + $set = [ + 'journal' => $this->transactionJournal, + 'name' => $field, + 'data' => $value, + ]; + $factory->updateOrCreate($set); + } + } + } + + /** + * + */ + private function updateMetaDateFields(): void + { + /** @var TransactionJournalMetaFactory $factory */ + $factory = app(TransactionJournalMetaFactory::class); + + foreach ($this->metaDate as $field) { + if ($this->hasFields([$field])) { + try { + $value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]); + } catch (Exception $e) { + Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage())); + + return; + } + Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value)); + $set = [ + 'journal' => $this->transactionJournal, + 'name' => $field, + 'data' => $value, + ]; + $factory->updateOrCreate($set); + } } } @@ -537,33 +666,37 @@ class JournalUpdateService } /** - * Update journal generic field. Cannot be set to NULL. * - * @param string $fieldName */ - private function updateField(string $fieldName): void + private function updateAmount(): void { - if (array_key_exists($fieldName, $this->data) && '' !== (string)$this->data[$fieldName]) { - $value = $this->data[$fieldName]; - - if ('date' === $fieldName) { - if ($value instanceof Carbon) { - // update timezone. - $value->setTimezone(config('app.timezone')); - } - if (!($value instanceof Carbon)) { - $value = new Carbon($value); - } - // do some parsing. - Log::debug(sprintf('Create date value from string "%s".', $value)); - } - - - $this->transactionJournal->$fieldName = $value; - Log::debug(sprintf('Updated %s', $fieldName)); + if (!$this->hasFields(['amount'])) { + return; } - } + $value = $this->data['amount'] ?? ''; + try { + $amount = $this->getAmount($value); + } catch (FireflyException $e) { + Log::debug(sprintf('getAmount("%s") returns error: %s', $value, $e->getMessage())); + + return; + } + $origSourceTransaction = $this->getSourceTransaction(); + $origSourceTransaction->amount = app('steam')->negative($amount); + $origSourceTransaction->save(); + + + $destTransaction = $this->getDestinationTransaction(); + $destTransaction->amount = app('steam')->positive($amount); + $destTransaction->save(); + + + // refresh transactions. + $this->sourceTransaction->refresh(); + $this->destinationTransaction->refresh(); + Log::debug(sprintf('Updated amount to "%s"', $amount)); + } /** * @@ -628,138 +761,4 @@ class JournalUpdateService $this->sourceTransaction->refresh(); $this->destinationTransaction->refresh(); } - - /** - * - */ - private function updateMeta(): void - { - // update meta fields. - // first string - if ($this->hasFields($this->metaString)) { - Log::debug('Meta string fields are present.'); - $this->updateMetaFields(); - } - - // then date fields. - if ($this->hasFields($this->metaDate)) { - Log::debug('Meta date fields are present.'); - $this->updateMetaDateFields(); - } - } - - /** - * - */ - private function updateMetaDateFields(): void - { - /** @var TransactionJournalMetaFactory $factory */ - $factory = app(TransactionJournalMetaFactory::class); - - foreach ($this->metaDate as $field) { - if ($this->hasFields([$field])) { - try { - $value = '' === (string)$this->data[$field] ? null : new Carbon($this->data[$field]); - } catch (Exception $e) { - Log::debug(sprintf('%s is not a valid date value: %s', $this->data[$field], $e->getMessage())); - - return; - } - Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value)); - $set = [ - 'journal' => $this->transactionJournal, - 'name' => $field, - 'data' => $value, - ]; - $factory->updateOrCreate($set); - } - } - } - - /** - * - */ - private function updateMetaFields(): void - { - /** @var TransactionJournalMetaFactory $factory */ - $factory = app(TransactionJournalMetaFactory::class); - - foreach ($this->metaString as $field) { - if ($this->hasFields([$field])) { - $value = '' === $this->data[$field] ? null : $this->data[$field]; - Log::debug(sprintf('Field "%s" is present ("%s"), try to update it.', $field, $value)); - $set = [ - 'journal' => $this->transactionJournal, - 'name' => $field, - 'data' => $value, - ]; - $factory->updateOrCreate($set); - } - } - } - - /** - * - */ - private function updateNotes(): void - { - // update notes. - if ($this->hasFields(['notes'])) { - $notes = '' === (string)$this->data['notes'] ? null : $this->data['notes']; - $this->storeNotes($this->transactionJournal, $notes); - } - } - - /** - * - */ - private function updateTags(): void - { - if ($this->hasFields(['tags'])) { - Log::debug('Will update tags.'); - $tags = $this->data['tags'] ?? null; - $this->storeTags($this->transactionJournal, $tags); - } - } - - /** - * Updates journal transaction type. - */ - private function updateType(): void - { - Log::debug('Now in updateType()'); - if ($this->hasFields(['type'])) { - $type = 'opening-balance' === $this->data['type'] ? 'opening balance' : $this->data['type']; - Log::debug( - sprintf( - 'Trying to change journal #%d from a %s to a %s.', - $this->transactionJournal->id, $this->transactionJournal->transactionType->type, $type - ) - ); - - /** @var TransactionTypeFactory $typeFactory */ - $typeFactory = app(TransactionTypeFactory::class); - $result = $typeFactory->find($this->data['type']); - if (null !== $result) { - Log::debug('Changed transaction type!'); - $this->transactionJournal->transaction_type_id = $result->id; - $this->transactionJournal->save(); - - return; - } - - return; - } - Log::debug('No type field present.'); - } - - /** - * - */ - private function updateReconciled(): void - { - if (array_key_exists('reconciled', $this->data) && is_bool($this->data['reconciled'])) { - $this->transactionJournal->transactions()->update(['reconciled' => $this->data['reconciled']]); - } - } } diff --git a/app/Services/Internal/Update/RecurrenceUpdateService.php b/app/Services/Internal/Update/RecurrenceUpdateService.php index 775bb79c7d..714b6e0e99 100644 --- a/app/Services/Internal/Update/RecurrenceUpdateService.php +++ b/app/Services/Internal/Update/RecurrenceUpdateService.php @@ -27,6 +27,7 @@ use Exception; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Note; use FireflyIII\Models\Recurrence; +use FireflyIII\Models\RecurrenceRepetition; use FireflyIII\Services\Internal\Support\RecurringTransactionTrait; use FireflyIII\Services\Internal\Support\TransactionTypeTrait; use FireflyIII\User; @@ -56,53 +57,55 @@ class RecurrenceUpdateService */ public function update(Recurrence $recurrence, array $data): Recurrence { - $this->user = $recurrence->user; - $transactionType = $recurrence->transactionType; - if (isset($data['recurrence']['type'])) { - $transactionType = $this->findTransactionType(ucfirst($data['recurrence']['type'])); - } + $this->user = $recurrence->user; // update basic fields first: - $recurrence->transaction_type_id = $transactionType->id; - $recurrence->title = $data['recurrence']['title'] ?? $recurrence->title; - $recurrence->description = $data['recurrence']['description'] ?? $recurrence->description; - $recurrence->first_date = $data['recurrence']['first_date'] ?? $recurrence->first_date; - $recurrence->repeat_until = $data['recurrence']['repeat_until'] ?? $recurrence->repeat_until; - $recurrence->repetitions = $data['recurrence']['nr_of_repetitions'] ?? $recurrence->repetitions; - $recurrence->apply_rules = $data['recurrence']['apply_rules'] ?? $recurrence->apply_rules; - $recurrence->active = $data['recurrence']['active'] ?? $recurrence->active; - // if nr_of_repetitions is set, then drop the "repeat_until" field. - if (0 !== $recurrence->repetitions) { - $recurrence->repeat_until = null; - } - - if (isset($data['recurrence']['repetition_end'])) { - if (in_array($data['recurrence']['repetition_end'], ['forever', 'until_date'])) { - $recurrence->repetitions = 0; + if (array_key_exists('recurrence', $data)) { + $info = $data['recurrence']; + if (array_key_exists('title', $info)) { + $recurrence->title = $info['title']; } - if (in_array($data['recurrence']['repetition_end'], ['forever', 'times'])) { - $recurrence->repeat_until = null; + if (array_key_exists('description', $info)) { + $recurrence->description = $info['description']; + } + if (array_key_exists('first_date', $info)) { + $recurrence->first_date = $info['first_date']; + } + if (array_key_exists('repeat_until', $info)) { + $recurrence->repeat_until = $info['repeat_until']; + $recurrence->repetitions = 0; + } + if (array_key_exists('nr_of_repetitions', $info)) { + if (0 !== (int)$info['nr_of_repetitions']) { + $recurrence->repeat_until = null; + } + $recurrence->repetitions = $info['nr_of_repetitions']; + } + if (array_key_exists('apply_rules', $info)) { + $recurrence->apply_rules = $info['apply_rules']; + } + if (array_key_exists('active', $info)) { + $recurrence->active = $info['active']; + } + // update all meta data: + if (array_key_exists('notes', $info)) { + $this->setNoteText($recurrence, $info['notes']); } } $recurrence->save(); - // update all meta data: - - if (isset($data['recurrence']['notes']) && null !== $data['recurrence']['notes']) { - $this->setNoteText($recurrence, $data['recurrence']['notes']); - } - // update all repetitions - if (null !== $data['repetitions']) { - $this->deleteRepetitions($recurrence); - $this->createRepetitions($recurrence, $data['repetitions'] ?? []); + if (array_key_exists('repetitions', $data)) { + Log::debug('Will update repetitions array'); + // update each repetition or throw error yay + $this->updateRepetitions($recurrence, $data['repetitions'] ?? []); } - // update all transactions (and associated meta-data) - if (null !== $data['transactions']) { - $this->deleteTransactions($recurrence); - $this->createTransactions($recurrence, $data['transactions'] ?? []); - } +// // update all transactions (and associated meta-data) +// if (array_key_exists('transactions', $data)) { +// $this->deleteTransactions($recurrence); +// $this->createTransactions($recurrence, $data['transactions'] ?? []); +// } return $recurrence; } @@ -133,4 +136,76 @@ class RecurrenceUpdateService } } + + /** + * + * @param Recurrence $recurrence + * @param array $repetitions + */ + private function updateRepetitions(Recurrence $recurrence, array $repetitions): void + { + $originalCount = $recurrence->recurrenceRepetitions()->count(); + if (0 === count($repetitions)) { + // wont drop repetition, rather avoid. + return; + } + // user added or removed repetitions, delete all and recreate: + if ($originalCount !== count($repetitions)) { + Log::debug('Del + recreate'); + $this->deleteRepetitions($recurrence); + $this->createRepetitions($recurrence, $repetitions); + + return; + } + // loop all and try to match them: + if ($originalCount === count($repetitions)) { + Log::debug('Loop and find'); + foreach ($repetitions as $current) { + $match = $this->matchRepetition($recurrence, $current); + if (null === $match) { + throw new FireflyException('Cannot match recurring repetition to existing repetition. Not sure what to do. Break.'); + } + $fields = [ + 'type' => 'repetition_type', + 'moment' => 'repetition_moment', + 'skip' => 'repetition_skip', + 'weekend' => 'weekend',]; + foreach ($fields as $field => $column) { + if (array_key_exists($field, $current)) { + $match->$column = $current[$field]; + $match->save(); + } + } + } + } + } + + /** + * @param array $data + * + * @return RecurrenceRepetition|null + */ + private function matchRepetition(Recurrence $recurrence, array $data): ?RecurrenceRepetition + { + $originalCount = $recurrence->recurrenceRepetitions()->count(); + if (1 === $originalCount) { + Log::debug('Return the first one'); + return $recurrence->recurrenceRepetitions()->first(); + } + // find it: + $fields = ['id' => 'id', + 'type' => 'repetition_type', + 'moment' => 'repetition_moment', + 'skip' => 'repetition_skip', + 'weekend' => 'weekend', + ]; + $query = $recurrence->recurrenceRepetitions(); + foreach ($fields as $field => $column) { + if (array_key_exists($field, $data)) { + $query->where($column, $data[$field]); + } + } + + return $query->first(); + } } diff --git a/app/Validation/RecurrenceValidation.php b/app/Validation/RecurrenceValidation.php index 6a067d26e4..9c37f84367 100644 --- a/app/Validation/RecurrenceValidation.php +++ b/app/Validation/RecurrenceValidation.php @@ -154,7 +154,10 @@ trait RecurrenceValidation * @var array $repetition */ foreach ($repetitions as $index => $repetition) { - if(null === $repetition['moment']) { + if (!array_key_exists('moment', $repetition)) { + continue; + } + if (null === $repetition['moment']) { $repetition['moment'] = ''; } $repetition['moment'] = $repetition['moment'] ?? 'invalid'; diff --git a/tests/Api/Autocomplete/AccountControllerTest.php b/tests/Api/Autocomplete/AccountControllerTest.php new file mode 100644 index 0000000000..857436c5b8 --- /dev/null +++ b/tests/Api/Autocomplete/AccountControllerTest.php @@ -0,0 +1,63 @@ +. + */ + +namespace Tests\Api\Autocomplete; + + +use Tests\TestCase; +use Laravel\Passport\Passport; +use Log; + +/** + * Class AccountControllerTest + */ +class AccountControllerTest extends TestCase +{ + /** + * + */ + public function setUp(): void + { + parent::setUp(); + Passport::actingAs($this->user()); + Log::info(sprintf('Now in %s.', get_class($this))); + } + + /** + * + */ + public function testBasic(): void + { + $this->assertTrue(true); + } + + /** + * @covers \FireflyIII\Api\V1\Controllers\Autocomplete\AccountController + */ + public function testAccounts(): void + { + // test API + $response = $this->get(route('api.v1.autocomplete.accounts'), ['Accept' => 'application/json']); + $response->assertStatus(200); + $response->assertHeader('Content-Type', 'application/json'); + } + +} \ No newline at end of file diff --git a/tests/Feature/Console/Commands/Correction/CorrectOpeningBalanceCurrenciesTest.php b/tests/Feature/Console/Commands/Correction/CorrectOpeningBalanceCurrenciesTest.php deleted file mode 100644 index 98dca2cb22..0000000000 --- a/tests/Feature/Console/Commands/Correction/CorrectOpeningBalanceCurrenciesTest.php +++ /dev/null @@ -1,110 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * CorrectOpeningBalanceCurrenciesTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\TransactionJournal; -use Log; -use Tests\TestCase; - -/** - * Class CorrectOpeningBalanceCurrenciesTest - * - * @package Tests\Feature\Console\Commands\Correction - */ -class CorrectOpeningBalanceCurrenciesTest extends TestCase -{ - - /** - * @covers \FireflyIII\Console\Commands\Correction\CorrectOpeningBalanceCurrencies - */ - public function testBasic(): void - { - $this->assertTrue(true); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\CorrectOpeningBalanceCurrencies - */ - public function testHandleOK(): void - { - // run command - $this->artisan('firefly-iii:fix-ob-currencies') - ->expectsOutput('There was nothing to fix in the opening balance transactions.') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\CorrectOpeningBalanceCurrencies - */ - public function testHandleBroken(): void - { - // create opening balance journal for test. Is enough to trigger this test. - TransactionJournal::factory()->openingBalance()->create(); - - // run command - $this->artisan('firefly-iii:fix-ob-currencies') - ->expectsOutput('Corrected 1 opening balance transaction(s).') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\CorrectOpeningBalanceCurrencies - */ - public function testHandleNoAccount(): void - { - Log::debug('Now in testHandleNoAccount'); - // create opening balance journal for test. Is enough to trigger this test. - $journal = TransactionJournal::factory()->brokenOpeningBalance()->create(); - - // run command - $this->artisan('firefly-iii:fix-ob-currencies') - ->expectsOutput(sprintf('Transaction journal #%d has no valid account. Cant fix this line.', $journal->id)) - //->expectsOutput('Cant fix this line.') - ->assertExitCode(0); - - $journal->forceDelete(); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/CreateAccessTokensTest.php b/tests/Feature/Console/Commands/Correction/CreateAccessTokensTest.php deleted file mode 100644 index 63b336279b..0000000000 --- a/tests/Feature/Console/Commands/Correction/CreateAccessTokensTest.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -declare(strict_types=1); - - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Preference; -use Tests\TestCase; - -/** - * Class CreateAccessTokensTest - */ -class CreateAccessTokensTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\CreateAccessTokens - */ - public function testHandle(): void - { - // remove preferences so token will be generated - Preference::where('name', 'access_token')->delete(); - - $this->artisan('firefly-iii:create-access-tokens') - ->expectsOutput(sprintf('Generated access token for user %s', $this->user()->email)) - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\CreateAccessTokens - */ - public function testHandlePrefExists(): void - { - $preference = new Preference; - $preference->data = '123'; - $preference->name = 'access_token'; - $preference->user_id = $this->user()->id; - $preference->save(); - - $this->artisan('firefly-iii:create-access-tokens') - ->expectsOutput('All access tokens OK!') - ->assertExitCode(0); - } -} diff --git a/tests/Feature/Console/Commands/Correction/CreateLinkTypesTest.php b/tests/Feature/Console/Commands/Correction/CreateLinkTypesTest.php deleted file mode 100644 index 119b5dfa6b..0000000000 --- a/tests/Feature/Console/Commands/Correction/CreateLinkTypesTest.php +++ /dev/null @@ -1,72 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\LinkType; -use Log; -use Tests\TestCase; - -/** - * Class CreateLinkTypesTest - */ -class CreateLinkTypesTest extends TestCase -{ - - /** - * @covers \FireflyIII\Console\Commands\Correction\CreateLinkTypes - */ - public function testHandle(): void - { - // delete all other link types: - LinkType::whereNotIn('name', ['Related', 'Refund', 'Paid', 'Reimbursement'])->forceDelete(); - - // delete link type: - LinkType::where('name', 'Reimbursement')->forceDelete(); - $this->assertCount(3, LinkType::get()); - - // run command, expect output: - $this->artisan('firefly-iii:create-link-types') - ->expectsOutput('Created missing link type "Reimbursement"') - ->assertExitCode(0); - - $this->assertCount(4, LinkType::get()); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\CreateLinkTypes - */ - public function testHandleNothing(): void - { - $this->assertCount(4, LinkType::get()); - - // run command, expect output: - $this->artisan('firefly-iii:create-link-types') - ->expectsOutput('All link types OK!') - ->assertExitCode(0); - - $this->assertCount(4, LinkType::get()); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/DeleteEmptyGroupsTest.php b/tests/Feature/Console/Commands/Correction/DeleteEmptyGroupsTest.php deleted file mode 100644 index c188ca47fb..0000000000 --- a/tests/Feature/Console/Commands/Correction/DeleteEmptyGroupsTest.php +++ /dev/null @@ -1,62 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\TransactionGroup; -use Log; -use Tests\TestCase; - -/** - * Class DeleteEmptyGroupsTest - */ -class DeleteEmptyGroupsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteEmptyGroups - */ - public function testHandle(): void - { - // assume there are no empty groups.. - $this->artisan('firefly-iii:delete-empty-groups') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteEmptyGroups - */ - public function testHandleWithGroup(): void - { - // create new group: - $group = TransactionGroup::create(['user_id' => 1]); - - // command should delete it. - $this->artisan('firefly-iii:delete-empty-groups') - ->expectsOutput('Deleted 1 empty transaction group(s).') - ->assertExitCode(0); - - // should not be able to find it: - $this->assertCount(0, TransactionGroup::where('id', $group->id)->whereNull('deleted_at')->get()); - } -} diff --git a/tests/Feature/Console/Commands/Correction/DeleteEmptyJournalsTest.php b/tests/Feature/Console/Commands/Correction/DeleteEmptyJournalsTest.php deleted file mode 100644 index 3c99313209..0000000000 --- a/tests/Feature/Console/Commands/Correction/DeleteEmptyJournalsTest.php +++ /dev/null @@ -1,112 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionJournal; -use Log; -use Tests\TestCase; - -/** - * Class DeleteEmptyJournalsTest - */ -class DeleteEmptyJournalsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteEmptyJournals - */ - public function testHandle(): void - { - // assume there are no empty journals or uneven journals - $this->artisan('firefly-iii:delete-empty-journals') - ->expectsOutput('No uneven transaction journals.') - ->expectsOutput('No empty transaction journals.') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteEmptyJournals - */ - public function testHandleEmptyJournals(): void - { - // create empty journal: - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => 1, - 'description' => 'Hello', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $this->artisan('firefly-iii:delete-empty-journals') - ->expectsOutput('No uneven transaction journals.') - ->expectsOutput(sprintf('Deleted empty transaction journal #%d', $journal->id)) - ->assertExitCode(0); - - // verify its indeed gone - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->get()); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteEmptyJournals - */ - public function testHandleUnevenJournals(): void - { - // create empty journal: - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => 1, - 'description' => 'Hello', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - - // link empty transaction - $transaction = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => 1, - 'amount' => '5', - ] - ); - - - $this->artisan('firefly-iii:delete-empty-journals') - ->expectsOutput(sprintf('Deleted transaction journal #%d because it had an uneven number of transactions.', $journal->id)) - ->expectsOutput('No empty transaction journals.') - ->assertExitCode(0); - - // verify both are gone - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->get()); - $this->assertCount(0, Transaction::where('id', $transaction->id)->whereNull('deleted_at')->get()); - } - - -} diff --git a/tests/Feature/Console/Commands/Correction/DeleteOrphanedTransactionsTest.php b/tests/Feature/Console/Commands/Correction/DeleteOrphanedTransactionsTest.php deleted file mode 100644 index a837a2e93e..0000000000 --- a/tests/Feature/Console/Commands/Correction/DeleteOrphanedTransactionsTest.php +++ /dev/null @@ -1,137 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Account; -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionJournal; -use Log; -use Tests\TestCase; - -/** - * Class DeleteOrphanedTransactionsTest - */ -class DeleteOrphanedTransactionsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteOrphanedTransactions - */ - public function testHandle(): void - { - // assume there are no orphaned transactions. - $this->artisan('firefly-iii:delete-orphaned-transactions') - ->expectsOutput('No orphaned transactions.') - ->expectsOutput('No orphaned accounts.') - ->assertExitCode(0); - } - - /** - * - */ - public function testHandleOrphanedAccounts(): void - { - - // create deleted account: - $account = Account::create( - [ - 'user_id' => 1, - 'name' => 'Some account', - 'account_type_id' => 1, - - ] - ); - $account->delete(); - - // create NOT deleted journal + transaction. - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => 1, - 'description' => 'Hello', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - - $transaction = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $account->id, - 'amount' => '5', - ] - ); - - $this->artisan('firefly-iii:delete-orphaned-transactions') - ->expectsOutput('No orphaned transactions.') - ->expectsOutput(sprintf('Deleted transaction journal #%d because account #%d was already deleted.', - $journal->id, $account->id)) - ->assertExitCode(0); - - // verify bad objects are gone. - $this->assertCount(0, Transaction::where('id', $transaction->id)->whereNull('deleted_at')->get()); - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->get()); - $this->assertCount(0, Account::where('id', $account->id)->whereNull('deleted_at')->get()); - - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteOrphanedTransactions - */ - public function testHandleOrphanedTransactions(): void - { - // create deleted journal: - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => 1, - 'description' => 'Hello', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $journal->delete(); - - // create NOT deleted transaction. - $transaction = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => 1, - 'amount' => '5', - ] - ); - - $this->artisan('firefly-iii:delete-orphaned-transactions') - ->expectsOutput(sprintf('Transaction #%d (part of deleted transaction journal #%d) has been deleted as well.', - $transaction->id, $journal->id)) - ->expectsOutput('No orphaned accounts.') - ->assertExitCode(0); - - // verify objects are gone. - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->get()); - $this->assertCount(0, Transaction::where('id', $transaction->id)->whereNull('deleted_at')->get()); - } -} diff --git a/tests/Feature/Console/Commands/Correction/DeleteZeroAmountTest.php b/tests/Feature/Console/Commands/Correction/DeleteZeroAmountTest.php deleted file mode 100644 index 0642eca92b..0000000000 --- a/tests/Feature/Console/Commands/Correction/DeleteZeroAmountTest.php +++ /dev/null @@ -1,84 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionJournal; -use Log; -use Tests\TestCase; - -/** - * Class DeleteZeroAmountTest - */ -class DeleteZeroAmountTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteZeroAmount - */ - public function testHandle(): void - { - // assume there are no transactions with a zero amount. - $this->artisan('firefly-iii:delete-zero-amount') - ->expectsOutput('No zero-amount transaction journals.') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\DeleteZeroAmount - */ - public function testHandleTransactions(): void - { - $account = $this->getRandomAsset(); - // create NOT deleted journal + transaction. - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => 1, - 'description' => 'Hello', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - - $transaction = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $account->id, - 'amount' => '0', - ] - ); - - - // assume there are no transactions with a zero amount. - $this->artisan('firefly-iii:delete-zero-amount') - ->expectsOutput(sprintf('Deleted transaction journal #%d because the amount is zero (0.00).', $journal->id)) - ->assertExitCode(0); - - // verify objects are gone. - $this->assertCount(0, Transaction::where('id', $transaction->id)->whereNull('deleted_at')->get()); - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNull('deleted_at')->get()); - } -} diff --git a/tests/Feature/Console/Commands/Correction/EnableCurrenciesTest.php b/tests/Feature/Console/Commands/Correction/EnableCurrenciesTest.php deleted file mode 100644 index 4ecbaca911..0000000000 --- a/tests/Feature/Console/Commands/Correction/EnableCurrenciesTest.php +++ /dev/null @@ -1,78 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\BudgetLimit; -use FireflyIII\Models\TransactionCurrency; -use Tests\TestCase; - -/** - * Class EnableCurrenciesTest - */ -class EnableCurrenciesTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\EnableCurrencies - */ - public function testHandleEnabled(): void - { - $count = TransactionCurrency::where('enabled', 1)->count(); - - $this->artisan('firefly-iii:enable-currencies') - ->expectsOutput('All currencies are correctly enabled or disabled.') - ->assertExitCode(0); - - - $this->assertCount($count, TransactionCurrency::where('enabled', 1)->get()); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\EnableCurrencies - */ - public function testHandleDisabled(): void - { - // find a disabled currency, update a budget limit with it. - $currency = TransactionCurrency::where('enabled', 0)->first(); - $budget = $this->getRandomBudget(); - $budgetLimit = new BudgetLimit; - $budgetLimit->transaction_currency_id = $currency->id; - $budgetLimit->budget_id = $budget->id; - $budgetLimit->start_date = '2020-01-01'; - $budgetLimit->end_date = '2020-01-02'; - $budgetLimit->amount = '4'; - $budgetLimit->save(); - - // assume the current database is intact. - $count = TransactionCurrency::where('enabled', 1)->count(); - $this->artisan('firefly-iii:enable-currencies') - ->expectsOutput(sprintf('%d were (was) still disabled. This has been corrected.', 1)) - ->assertExitCode(0); - - // assume its been enabled. - $this->assertCount($count + 1, TransactionCurrency::where('enabled', 1)->get()); - $budgetLimit->forceDelete(); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/FixAccountOrderTest.php b/tests/Feature/Console/Commands/Correction/FixAccountOrderTest.php deleted file mode 100644 index caa9519afb..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixAccountOrderTest.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * FixAccountOrderTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use DB; -use FireflyIII\Models\Account; -use Tests\TestCase; - -class FixAccountOrderTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\FixAccountOrder - */ - public function testHandle(): void - { - - // reset all asset accounts accounts: - Account::select()->update(['order' => 0]); - - $this->artisan('firefly-iii:fix-account-order') - ->assertExitCode(0); - - $this->assertCount(0, Account::where('order', '=',0)->get()); - - } - -} diff --git a/tests/Feature/Console/Commands/Correction/FixAccountTypesTest.php b/tests/Feature/Console/Commands/Correction/FixAccountTypesTest.php deleted file mode 100644 index d825bddb49..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixAccountTypesTest.php +++ /dev/null @@ -1,364 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Account; -use FireflyIII\Models\AccountType; -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; -use Tests\TestCase; - -/** - * Class FixAccountTypesTest - */ -class FixAccountTypesTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\FixAccountTypes - */ - public function testHandleUneven(): void - { - $source = $this->getRandomDebt(); - $type = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $type->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, - 'amount' => '-10', - ] - ); - - // assume there's nothing to fix. - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput(sprintf('Cannot inspect transaction journal #%d because it has 1 transaction(s) instead of 2.', $journal->id)) - ->assertExitCode(0); - $one->forceDelete(); - $journal->forceDelete(); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\FixAccountTypes - */ - public function testHandle(): void - { - // assume there's nothing to fix. - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput('All account types are OK!') - ->assertExitCode(0); - } - - /** - * Try to fix a withdrawal that goes from a loan to another loan. - * - * @covers \FireflyIII\Console\Commands\Correction\FixAccountTypes - */ - public function testHandleWithdrawalLoanLoan(): void - { - $source = $this->getRandomLoan(); - $destination = $this->getRandomLoan($source->id); - $type = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $type->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $destination->id, - 'amount' => '10', - ] - ); - - - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput(sprintf('The source account of %s #%d cannot be of type "%s".', $type->type, $journal->id, 'Loan')) - ->expectsOutput(sprintf('The destination account of %s #%d cannot be of type "%s".', $type->type, $journal->id, 'Loan')) - ->expectsOutput('Acted on 1 transaction(s)!') - ->assertExitCode(0); - - // since system cant handle this problem, dont look for changed transactions. - $one->forceDelete(); - $two->forceDelete(); - $journal->forceDelete(); - } - - /** - * Transferring from an asset to a loan should be a withdrawal, not a transfer - */ - public function testHandleTransferAssetLoan(): void - { - $source = $this->getRandomAsset(); - $destination = $this->getRandomLoan(); - $type = TransactionType::where('type', TransactionType::TRANSFER)->first(); - $withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $type->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $destination->id, - 'amount' => '10', - ] - ); - - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput(sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id)) - ->expectsOutput('Acted on 1 transaction(s)!') - ->assertExitCode(0); - - // verify the change has been made. - $this->assertCount(1, TransactionJournal::where('id', $journal->id)->where('transaction_type_id', $withdrawal->id)->get()); - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->where('transaction_type_id', $type->id)->get()); - - $one->forceDelete(); - $two->forceDelete(); - $journal->forceDelete(); - } - - /** - * Transferring from a loan to an asset should be a deposit, not a transfer - */ - public function testHandleTransferLoanAsset(): void - { - $source = $this->getRandomLoan(); - $destination = $this->getRandomAsset(); - $type = TransactionType::where('type', TransactionType::TRANSFER)->first(); - $deposit = TransactionType::where('type', TransactionType::DEPOSIT)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $type->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $destination->id, - 'amount' => '10', - ] - ); - - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput(sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id)) - ->expectsOutput('Acted on 1 transaction(s)!') - ->assertExitCode(0); - - // verify the change has been made. - $this->assertCount(1, TransactionJournal::where('id', $journal->id)->where('transaction_type_id', $deposit->id)->get()); - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->where('transaction_type_id', $type->id)->get()); - - $one->forceDelete(); - $two->forceDelete(); - $journal->forceDelete(); - } - - /** - * Withdrawal with a revenue account as a destination must be converted. - */ - public function testHandleWithdrawalAssetRevenue(): void - { - $source = $this->getRandomAsset(); - $destination = $this->getRandomRevenue(); // is revenue account. - $withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $withdrawal->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $destination->id, // revenue cannot be destination. - 'amount' => '10', - ] - ); - - // create expense account with the same name: - $expense = AccountType::where('type', AccountType::EXPENSE)->first(); - $newDestination = Account::create( - [ - 'name' => $destination->name, - 'account_type_id' => $expense->id, - 'user_id' => 1, - ] - ); - - // asset we find bad destination. - $this->assertCount(0, Transaction::where('id', $two->id)->where('account_id', $newDestination->id)->get()); - $this->assertCount(1, Transaction::where('id', $two->id)->where('account_id', $destination->id)->get()); - - // Transaction journal #137, destination account changed from #1 ("Checking Account") to #29 ("Land lord"). - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput( - sprintf( - 'Transaction journal #%d, destination account changed from #%d ("%s") to #%d ("%s").', - $journal->id, - $destination->id, $destination->name, - $newDestination->id, $newDestination->name - ) - ) - ->expectsOutput('Acted on 1 transaction(s)!') - ->assertExitCode(0); - - // verify the change has been made - $this->assertCount(1, Transaction::where('id', $two->id)->where('account_id', $newDestination->id)->get()); - $this->assertCount(0, Transaction::where('id', $two->id)->where('account_id', $destination->id)->get()); - - $one->forceDelete(); - $two->forceDelete(); - $journal->forceDelete(); - } - - /** - * Deposit with an expense account as a source instead of a revenue account must be converted. - */ - public function testHandleDepositAssetExpense(): void - { - $source = $this->getRandomExpense(); // expense account - //$newSource = $this->getRandomRevenue(); - $destination = $this->getRandomAsset(); - - $deposit = TransactionType::where('type', TransactionType::DEPOSIT)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $deposit->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $source->id, // expense account cannot be source. - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $destination->id, - 'amount' => '10', - ] - ); - // create revenue account with the same name: - $revenue = AccountType::where('type', AccountType::REVENUE)->first(); - $newSource = Account::create( - [ - 'name' => $source->name, - 'account_type_id' => $revenue->id, - 'user_id' => 1, - ] - ); - - $this->assertCount(0, Transaction::where('id', $one->id)->where('account_id', $newSource->id)->get()); - $this->assertCount(1, Transaction::where('id', $one->id)->where('account_id', $source->id)->get()); - - - // Transaction journal #137, destination account changed from #1 ("Checking Account") to #29 ("Land lord"). - $this->artisan('firefly-iii:fix-account-types') - ->expectsOutput( - sprintf( - 'Transaction journal #%d, source account changed from #%d ("%s") to #%d ("%s").', - $journal->id, - $destination->id, $destination->name, - $newSource->id, $newSource->name - ) - ) - ->expectsOutput('Acted on 1 transaction(s)!') - ->assertExitCode(0); - - $this->assertCount(1, Transaction::where('id', $one->id)->where('account_id', $newSource->id)->get()); - $this->assertCount(0, Transaction::where('id', $one->id)->where('account_id', $source->id)->get()); - - $one->forceDelete(); - $two->forceDelete(); - $journal->forceDelete(); - } -} diff --git a/tests/Feature/Console/Commands/Correction/FixGroupAccountsTest.php b/tests/Feature/Console/Commands/Correction/FixGroupAccountsTest.php deleted file mode 100644 index 08c670bd96..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixGroupAccountsTest.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * FixGroupAccountsTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use Tests\TestCase; - -/** - * Class FixGroupAccountsTest - */ -class FixGroupAccountsTest extends TestCase -{ - - /** - * @covers \FireflyIII\Console\Commands\Correction\FixGroupAccounts - */ - public function testHandle(): void - { - // basic group with multiple journals, should trigger event. - $this->artisan('firefly-iii:unify-group-accounts') - ->expectsOutput('Updated inconsistent transaction groups.') - ->assertExitCode(0); - - // This just triggers the events. No real test. - } - - -} diff --git a/tests/Feature/Console/Commands/Correction/FixLongDescriptionsTest.php b/tests/Feature/Console/Commands/Correction/FixLongDescriptionsTest.php deleted file mode 100644 index 3263ed8ad5..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixLongDescriptionsTest.php +++ /dev/null @@ -1,95 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * FixLongDescriptionsTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use Tests\TestCase; - -/** - * Class FixLongDescriptionsTest - */ -class FixLongDescriptionsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\FixLongDescriptions - */ - public function testHandle(): void - { - $journal = $this->getRandomWithdrawal(); - $original = $journal->description; - $journal->description = str_repeat('ABCDEF123456x', 200); - $journal->save(); - - - $this->artisan('firefly-iii:fix-long-descriptions') - ->expectsOutput(sprintf('Truncated description of transaction journal #%d', $journal->id)) - ->expectsOutput('Verified all transaction group and journal title lengths.') - ->assertExitCode(0); - - $journal->description = $original; - $journal->save(); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\FixLongDescriptions - */ - public function testHandleGroup(): void - { - $journal = $this->getRandomWithdrawal(); - $group = $journal->transactionGroup; - $original = $group->title; - $group->title = str_repeat('ABCDEF123456x', 200); - $group->save(); - - - $this->artisan('firefly-iii:fix-long-descriptions') - ->expectsOutput(sprintf('Truncated description of transaction group #%d', $group->id)) - ->expectsOutput('Verified all transaction group and journal title lengths.') - ->assertExitCode(0); - - $group->title = $original; - $group->save(); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/FixPiggiesTest.php b/tests/Feature/Console/Commands/Correction/FixPiggiesTest.php deleted file mode 100644 index 7b59548792..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixPiggiesTest.php +++ /dev/null @@ -1,123 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\PiggyBank; -use FireflyIII\Models\PiggyBankEvent; -use Log; -use Tests\TestCase; - -/** - * Class FixPiggiesTest - */ -class FixPiggiesTest extends TestCase -{ - /** - * Null event. - * - * @covers \FireflyIII\Console\Commands\Correction\FixPiggies - */ - public function testHandleNull(): void - { - /** @var PiggyBank $piggy */ - $piggy = $this->user()->piggyBanks()->inRandomOrder()->first(); - - // create event to trigger console commands. - $event = PiggyBankEvent::create( - [ - 'piggy_bank_id' => $piggy->id, - 'date' => '2019-01-01', - 'amount' => 5, - ] - ); - - // assume there's nothing to fix. - $this->artisan('firefly-iii:fix-piggies') - ->expectsOutput('All piggy bank events are correct.') - ->assertExitCode(0); - $event->forceDelete(); - } - - /** - * Withdrawal instead of transfer - * - * @covers \FireflyIII\Console\Commands\Correction\FixPiggies - */ - public function testHandleBadJournal(): void - { - /** @var PiggyBank $piggy */ - $piggy = $this->user()->piggyBanks()->inRandomOrder()->first(); - $withdrawal = $this->getRandomWithdrawal(); - // create event to trigger console commands. - $event = PiggyBankEvent::create( - [ - 'piggy_bank_id' => $piggy->id, - 'date' => '2019-01-01', - 'amount' => 5, - 'transaction_journal_id' => $withdrawal->id, - ] - ); - - // assume there's nothing to fix. - $this->artisan('firefly-iii:fix-piggies') - ->expectsOutput(sprintf('Piggy bank #%d was referenced by an invalid event. This has been fixed.', $piggy->id)) - ->expectsOutput('Fixed 1 piggy bank event(s).') - ->assertExitCode(0); - - // verify update - $this->assertCount(0, PiggyBankEvent::where('id', $event->id)->where('transaction_journal_id', $withdrawal->id)->get()); - } - - /** - * Withdrawal instead of transfer - * - * @covers \FireflyIII\Console\Commands\Correction\FixPiggies - */ - public function testHandleDeletedJournal(): void - { - /** @var PiggyBank $piggy */ - $piggy = $this->user()->piggyBanks()->inRandomOrder()->first(); - $transfer = $this->getRandomTransfer(); - $event = PiggyBankEvent::create( - [ - 'piggy_bank_id' => $piggy->id, - 'date' => '2019-01-01', - 'amount' => 5, - 'transaction_journal_id' => $transfer->id, - ] - ); - $transfer->deleted_at = '2019-01-01 12:00:00'; - $transfer->save(); - $transfer->refresh(); - - $this->artisan('firefly-iii:fix-piggies') - ->expectsOutput('Fixed 1 piggy bank event(s).') - ->assertExitCode(0); - - // verify update - $this->assertCount(0, PiggyBankEvent::where('id', $event->id)->where('transaction_journal_id', $transfer->id)->get()); - $event->forceDelete(); - } -} diff --git a/tests/Feature/Console/Commands/Correction/FixRecurringTransactionsTest.php b/tests/Feature/Console/Commands/Correction/FixRecurringTransactionsTest.php deleted file mode 100644 index a84b8791e0..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixRecurringTransactionsTest.php +++ /dev/null @@ -1,70 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * FixRecurringTransactionsTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Recurrence; -use Tests\TestCase; - -/** - * Class FixRecurringTransactionsTest - */ -class FixRecurringTransactionsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\FixRecurringTransactions - */ - public function testHandle(): void - { - // test DB contains a broken recurring transaction. - $recurring = Recurrence::whereTitle('broken_recurrence')->first(); - - - $this->artisan('firefly-iii:fix-recurring-transactions') - ->expectsOutput(sprintf('Recurring transaction #%d should be a "%s" but is a "%s" and will be corrected.', - $recurring->id, 'Withdrawal','Transfer', - )) - ->assertExitCode(0); - } -} diff --git a/tests/Feature/Console/Commands/Correction/FixTransactionTypesTest.php b/tests/Feature/Console/Commands/Correction/FixTransactionTypesTest.php deleted file mode 100644 index 24d02606cf..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixTransactionTypesTest.php +++ /dev/null @@ -1,65 +0,0 @@ -. - */ - -declare(strict_types=1); -/* - * FixTransactionTypesTest.php - * Copyright (c) 2020 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 . - */ - -namespace Tests\Feature\Console\Commands\Correction; - - -use Tests\TestCase; - -/** - * Class FixTransactionTypesTest - */ -class FixTransactionTypesTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\FixTransactionTypes - */ - public function testHandle(): void - { - $this->artisan('firefly-iii:fix-transaction-types') - //->expectsOutput() - ->assertExitCode(0); - } - - -} diff --git a/tests/Feature/Console/Commands/Correction/FixUnevenAmountTest.php b/tests/Feature/Console/Commands/Correction/FixUnevenAmountTest.php deleted file mode 100644 index cab85a0cb2..0000000000 --- a/tests/Feature/Console/Commands/Correction/FixUnevenAmountTest.php +++ /dev/null @@ -1,95 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\Transaction; -use FireflyIII\Models\TransactionJournal; -use FireflyIII\Models\TransactionType; -use Log; -use Tests\TestCase; - -/** - * Class FixUnevenAmountTest - */ -class FixUnevenAmountTest extends TestCase -{ - - /** - * @covers \FireflyIII\Console\Commands\Correction\FixUnevenAmount - */ - public function testHandle(): void - { - // assume there's nothing to fix. - $this->artisan('firefly-iii:fix-uneven-amount') - ->expectsOutput('Amount integrity OK!') - ->assertExitCode(0); - - // dont verify anything - } - - /** - * Create uneven journal - * @covers \FireflyIII\Console\Commands\Correction\FixUnevenAmount - */ - public function testHandleUneven(): void - { - $asset = $this->getRandomAsset(); - $expense = $this->getRandomExpense(); - $withdrawal = TransactionType::where('type', TransactionType::WITHDRAWAL)->first(); - $journal = TransactionJournal::create( - [ - 'user_id' => 1, - 'transaction_currency_id' => 1, - 'transaction_type_id' => $withdrawal->id, - 'description' => 'Test', - 'tag_count' => 0, - 'date' => '2019-01-01', - ] - ); - $one = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $asset->id, - 'amount' => '-10', - ] - ); - $two = Transaction::create( - [ - 'transaction_journal_id' => $journal->id, - 'account_id' => $expense->id, - 'amount' => '12', - ] - ); - - $this->artisan('firefly-iii:fix-uneven-amount') - ->expectsOutput(sprintf('Corrected amount in transaction journal #%d', $journal->id)) - ->assertExitCode(0); - - // verify change. - $this->assertCount(1, Transaction::where('id', $one->id)->where('amount', '-10')->get()); - $this->assertCount(1, Transaction::where('id', $two->id)->where('amount', '10')->get()); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/RemoveBillsTest.php b/tests/Feature/Console/Commands/Correction/RemoveBillsTest.php deleted file mode 100644 index 510bda424d..0000000000 --- a/tests/Feature/Console/Commands/Correction/RemoveBillsTest.php +++ /dev/null @@ -1,69 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\TransactionJournal; -use Log; -use Tests\TestCase; - -/** - * Class RemoveBillsTest - */ -class RemoveBillsTest extends TestCase -{ - - - /** - * @covers \FireflyIII\Console\Commands\Correction\RemoveBills - */ - public function testHandle(): void - { - // assume there's nothing to fix. - $this->artisan('firefly-iii:remove-bills') - ->expectsOutput('All transaction journals have correct bill information.') - ->assertExitCode(0); - - // dont verify anything - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\RemoveBills - */ - public function testHandleWithdrawal(): void - { - $bill = $this->getRandomBill(); - $journal = $this->getRandomDeposit(); - - $journal->bill_id = $bill->id; - $journal->save(); - - $this->artisan('firefly-iii:remove-bills') - ->expectsOutput(sprintf('Transaction journal #%d should not be linked to bill #%d.', $journal->id, $bill->id)) - ->assertExitCode(0); - - // verify change - $this->assertCount(0, TransactionJournal::where('id', $journal->id)->whereNotNull('bill_id')->get()); - } -} diff --git a/tests/Feature/Console/Commands/Correction/RenameMetaFieldsTest.php b/tests/Feature/Console/Commands/Correction/RenameMetaFieldsTest.php deleted file mode 100644 index 444dd506a6..0000000000 --- a/tests/Feature/Console/Commands/Correction/RenameMetaFieldsTest.php +++ /dev/null @@ -1,70 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use FireflyIII\Models\TransactionJournalMeta; -use Log; -use Tests\TestCase; - -/** - * Class RenameMetaFieldsTest - */ -class RenameMetaFieldsTest extends TestCase -{ - - /** - * @covers \FireflyIII\Console\Commands\Correction\RenameMetaFields - */ - public function testHandle(): void - { - $this->artisan('firefly-iii:rename-meta-fields') - ->expectsOutput('All meta fields are correct.') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\RenameMetaFields - */ - public function testHandleFixed(): void - { - $withdrawal = $this->getRandomWithdrawal(); - $entry = TransactionJournalMeta::create( - [ - 'transaction_journal_id' => $withdrawal->id, - 'name' => 'importHashV2', - 'data' => 'Fake data', - - ] - ); - - $this->artisan('firefly-iii:rename-meta-fields') - ->expectsOutput('Renamed 1 meta field(s).') - ->assertExitCode(0); - - // verify update - $this->assertCount(1, TransactionJournalMeta::where('id', $entry->id)->where('name', 'import_hash_v2')->get()); - } - -} diff --git a/tests/Feature/Console/Commands/Correction/TransferBudgetsTest.php b/tests/Feature/Console/Commands/Correction/TransferBudgetsTest.php deleted file mode 100644 index e3621b8620..0000000000 --- a/tests/Feature/Console/Commands/Correction/TransferBudgetsTest.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -declare(strict_types=1); - -namespace Tests\Feature\Console\Commands\Correction; - - -use Log; -use Tests\TestCase; - -/** - * Class TransferBudgetsTest - */ -class TransferBudgetsTest extends TestCase -{ - /** - * @covers \FireflyIII\Console\Commands\Correction\TransferBudgets - */ - public function testHandle(): void - { - $this->artisan('firefly-iii:fix-transfer-budgets') - ->expectsOutput('No invalid budget/journal entries.') - ->assertExitCode(0); - } - - /** - * @covers \FireflyIII\Console\Commands\Correction\TransferBudgets - */ - public function testHandleBudget(): void - { - $deposit = $this->getRandomDeposit(); - $budget = $this->getRandomBudget(); - - $deposit->budgets()->save($budget); - - $this->artisan('firefly-iii:fix-transfer-budgets') - ->expectsOutput(sprintf('Transaction journal #%d is a %s, so has no longer a budget.', $deposit->id, $deposit->transactionType->type)) - ->expectsOutput('Corrected 1 invalid budget/journal entries (entry).') - ->assertExitCode(0); - - // verify change - $this->assertCount(0, $deposit->budgets()->get()); - } - -}