diff --git a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php index cf29aa037a..5a757dd35f 100644 --- a/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php +++ b/app/Api/V1/Controllers/Autocomplete/PiggyBankController.php @@ -68,12 +68,11 @@ class PiggyBankController extends Controller { $data = $request->getData(); $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); - $defaultCurrency = app('amount')->getDefaultCurrency(); $response = []; /** @var PiggyBank $piggy */ foreach ($piggies as $piggy) { - $currency = $this->accountRepository->getAccountCurrency($piggy->account) ?? $defaultCurrency; + $currency = $piggy->transactionCurrency; $objectGroup = $piggy->objectGroups()->first(); $response[] = [ 'id' => (string)$piggy->id, @@ -99,12 +98,11 @@ class PiggyBankController extends Controller { $data = $request->getData(); $piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit')); - $defaultCurrency = app('amount')->getDefaultCurrency(); $response = []; /** @var PiggyBank $piggy */ foreach ($piggies as $piggy) { - $currency = $this->accountRepository->getAccountCurrency($piggy->account) ?? $defaultCurrency; + $currency = $piggy->transactionCurrency; $currentAmount = $this->piggyRepository->getRepetition($piggy)->current_amount ?? '0'; $objectGroup = $piggy->objectGroups()->first(); $response[] = [ diff --git a/app/Api/V1/Controllers/Data/PurgeController.php b/app/Api/V1/Controllers/Data/PurgeController.php index 8d076b62cf..d80b60315b 100644 --- a/app/Api/V1/Controllers/Data/PurgeController.php +++ b/app/Api/V1/Controllers/Data/PurgeController.php @@ -36,6 +36,7 @@ use FireflyIII\Models\RuleGroup; use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionJournal; +use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\User; use Illuminate\Http\JsonResponse; @@ -63,14 +64,17 @@ class PurgeController extends Controller Bill::whereUserId($user->id)->onlyTrashed()->forceDelete(); // piggies - $set = PiggyBank::leftJoin('accounts', 'accounts.id', 'piggy_banks.account_id') - ->where('accounts.user_id', $user->id)->onlyTrashed()->get(['piggy_banks.*']) - ; - - /** @var PiggyBank $piggy */ - foreach ($set as $piggy) { - $piggy->forceDelete(); - } + $repository = app(PiggyBankRepositoryInterface::class); + $repository->setUser($user); + $repository->purgeAll(); +// $set = PiggyBank::leftJoin('accounts', 'accounts.id', 'piggy_banks.account_id') +// ->where('accounts.user_id', $user->id)->onlyTrashed()->get(['piggy_banks.*']) +// ; +// +// /** @var PiggyBank $piggy */ +// foreach ($set as $piggy) { +// $piggy->forceDelete(); +// } // rule group RuleGroup::whereUserId($user->id)->onlyTrashed()->forceDelete(); diff --git a/app/Api/V1/Controllers/Models/Account/ListController.php b/app/Api/V1/Controllers/Models/Account/ListController.php index c85456f901..b2d4e39d90 100644 --- a/app/Api/V1/Controllers/Models/Account/ListController.php +++ b/app/Api/V1/Controllers/Models/Account/ListController.php @@ -111,7 +111,7 @@ class ListController extends Controller // types to get, page size: $pageSize = $this->parameters->get('limit'); - // get list of budgets. Count it and split it. + // get list of piggy banks. Count it and split it. $collection = $this->repository->getPiggyBanks($account); $count = $collection->count(); $piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php index 3c3ac1672b..8fda63be8e 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php @@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\PiggyBank; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; +use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer; use Illuminate\Http\JsonResponse; @@ -118,4 +119,36 @@ class ListController extends Controller return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); } + + /** + * This endpoint is documented at: + * https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/piggy_banks/listAccountByPiggyBank + * + * List single resource. + * + * @throws FireflyException + */ + public function accounts(PiggyBank $piggyBank): JsonResponse + { + // types to get, page size: + $pageSize = $this->parameters->get('limit'); + $manager = $this->getManager(); + + $collection = $piggyBank->accounts; + $count = $collection->count(); + $events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.piggy-banks.accounts', [$piggyBank->id]).$this->buildParams()); + + /** @var AccountTransformer $transformer */ + $transformer = app(AccountTransformer::class); + $transformer->setParameters($this->parameters); + + $resource = new FractalCollection($events, $transformer, 'accounts'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); + } } diff --git a/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php b/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php index 8adc656a65..d73abc7b8c 100644 --- a/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php +++ b/app/Api/V1/Requests/Models/PiggyBank/StoreRequest.php @@ -24,10 +24,13 @@ declare(strict_types=1); namespace FireflyIII\Api\V1\Requests\Models\PiggyBank; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Rules\IsValidPositiveAmount; use FireflyIII\Support\Request\ChecksLogin; use FireflyIII\Support\Request\ConvertsDataTypes; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\Validator; /** * Class StoreRequest @@ -42,19 +45,20 @@ class StoreRequest extends FormRequest */ public function getAll(): array { - $fields = [ + $fields = [ 'order' => ['order', 'convertInteger'], ]; - $data = $this->getAllData($fields); - $data['name'] = $this->convertString('name'); - $data['account_id'] = $this->convertInteger('account_id'); - $data['targetamount'] = $this->convertString('target_amount'); - $data['current_amount'] = $this->convertString('current_amount'); - $data['startdate'] = $this->getCarbonDate('start_date'); - $data['targetdate'] = $this->getCarbonDate('target_date'); - $data['notes'] = $this->stringWithNewlines('notes'); - $data['object_group_id'] = $this->convertInteger('object_group_id'); - $data['object_group_title'] = $this->convertString('object_group_title'); + $data = $this->getAllData($fields); + $data['name'] = $this->convertString('name'); + $data['accounts'] = $this->parseAccounts($this->get('accounts')); + $data['target_amount'] = $this->convertString('target_amount'); + $data['start_date'] = $this->getCarbonDate('start_date'); + $data['target_date'] = $this->getCarbonDate('target_date'); + $data['notes'] = $this->stringWithNewlines('notes'); + $data['object_group_id'] = $this->convertInteger('object_group_id'); + $data['transaction_currency_id'] = $this->convertInteger('transaction_currency_id'); + $data['transaction_currency_code'] = $this->convertString('transaction_currency_code'); + $data['object_group_title'] = $this->convertString('object_group_title'); return $data; } @@ -65,15 +69,67 @@ class StoreRequest extends FormRequest public function rules(): array { return [ - 'name' => 'required|min:1|max:255|uniquePiggyBankForUser', - 'current_amount' => ['nullable', new IsValidPositiveAmount()], - 'account_id' => 'required|numeric|belongsToUser:accounts,id', - 'object_group_id' => 'numeric|belongsToUser:object_groups,id', - 'object_group_title' => ['min:1', 'max:255'], - 'target_amount' => ['required', new IsValidPositiveAmount()], - 'start_date' => 'date|nullable', - 'target_date' => 'date|nullable|after:start_date', - 'notes' => 'max:65000', + 'name' => 'required|min:1|max:255|uniquePiggyBankForUser', + 'accounts' => 'required', + 'accounts.*' => 'array|required', + 'accounts.*.account_id' => 'required|numeric|belongsToUser:accounts,id', + 'accounts.*.current_amount' => ['numeric', new IsValidPositiveAmount()], + 'object_group_id' => 'numeric|belongsToUser:object_groups,id', + 'object_group_title' => ['min:1', 'max:255'], + 'target_amount' => ['required', new IsValidPositiveAmount()], + 'start_date' => 'date|nullable', + 'transaction_currency_id' => 'exists:transaction_currencies,id', + 'transaction_currency_code' => 'exists:transaction_currencies,code', + 'target_date' => 'date|nullable|after:start_date', + 'notes' => 'max:65000', ]; } + + /** + * Can only store money on liabilities and asset accouns. + */ + public function withValidator(Validator $validator): void + { + $validator->after( + function (Validator $validator): void { + // validate start before end only if both are there. + $data = $validator->getData(); + if (array_key_exists('accounts', $data) && is_array($data['accounts'])) { + $repository = app(AccountRepositoryInterface::class); + $types = config('firefly.piggy_bank_account_types'); + foreach ($data['accounts'] as $index => $array) { + $accountId = (int) ($array['account_id'] ?? 0); + $account = $repository->find($accountId); + if (null !== $account) { + $type = $account->accountType->type; + if (!in_array($type, $types, true)) { + $validator->errors()->add(sprintf('accounts.%d', $index), trans('validation.invalid_account_type')); + } + } + } + } + } + ); + if ($validator->fails()) { + Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray()); + } + } + + private function parseAccounts(mixed $array): array + { + if (!is_array($array)) { + return []; + } + $return = []; + foreach ($array as $entry) { + if (!is_array($entry)) { + continue; + } + $return[] = [ + 'account_id' => $this->integerFromValue((string)($entry['account_id'] ?? '0')), + 'current_amount' => $this->clearString($entry['current_amount'] ?? '0'), + ]; + } + return $return; + } } diff --git a/app/Factory/PiggyBankFactory.php b/app/Factory/PiggyBankFactory.php index 505c92d0da..df9b54bc46 100644 --- a/app/Factory/PiggyBankFactory.php +++ b/app/Factory/PiggyBankFactory.php @@ -23,8 +23,14 @@ declare(strict_types=1); namespace FireflyIII\Factory; +use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\PiggyBank; +use FireflyIII\Models\TransactionCurrency; +use FireflyIII\Repositories\Account\AccountRepositoryInterface; +use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface; +use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\User; +use Illuminate\Database\QueryException; /** * Class PiggyBankFactory @@ -32,6 +38,72 @@ use FireflyIII\User; class PiggyBankFactory { private User $user; + private CurrencyRepositoryInterface $currencyRepository; + private AccountRepositoryInterface $accountRepository; + private PiggyBankRepositoryInterface $piggyBankRepository; + + /** + * Store a piggy bank or come back with an exception. + * + * @param array $data + * + * @return PiggyBank + */ + public function store(array $data): PiggyBank { + $this->currencyRepository = app(CurrencyRepositoryInterface::class); + $this->accountRepository = app(AccountRepositoryInterface::class); + $this->piggyBankRepository = app(PiggyBankRepositoryInterface::class); + $this->currencyRepository->setUser($this->user); + $this->accountRepository->setUser($this->user); + $this->piggyBankRepository->setUser($this->user); + $piggyBankData =$data; + + // unset some fields + unset($piggyBankData['object_group_title'],$piggyBankData['transaction_currency_code'],$piggyBankData['transaction_currency_id'],$piggyBankData['accounts'], $piggyBankData['object_group_id'], $piggyBankData['notes']); + + // validate amount: + if (array_key_exists('target_amount', $piggyBankData) && '' === (string)$piggyBankData['target_amount']) { + $piggyBankData['target_amount'] = '0'; + } + + $piggyBankData['start_date_tz'] = $piggyBankData['start_date']?->format('e'); + $piggyBankData['target_date_tz'] = $piggyBankData['target_date']?->format('e'); + $piggyBankData['account_id'] = null; + $piggyBankData['transaction_currency_id'] = $this->getCurrency($data)->id; + $piggyBankData['order'] = 131337; + + try { + /** @var PiggyBank $piggyBank */ + $piggyBank = PiggyBank::create($piggyBankData); + } catch (QueryException $e) { + app('log')->error(sprintf('Could not store piggy bank: %s', $e->getMessage()), $piggyBankData); + + throw new FireflyException('400005: Could not store new piggy bank.', 0, $e); + } + $piggyBank = $this->setOrder($piggyBank, $data); + $this->linkToAccountIds($piggyBank, $data['accounts']); + $this->piggyBankRepository->updateNote($piggyBank, $data['notes']); + + $objectGroupTitle = $data['object_group_title'] ?? ''; + if ('' !== $objectGroupTitle) { + $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); + if (null !== $objectGroup) { + $piggyBank->objectGroups()->sync([$objectGroup->id]); + $piggyBank->save(); + } + } + // try also with ID + $objectGroupId = (int)($data['object_group_id'] ?? 0); + if (0 !== $objectGroupId) { + $objectGroup = $this->findObjectGroupById($objectGroupId); + if (null !== $objectGroup) { + $piggyBank->objectGroups()->sync([$objectGroup->id]); + $piggyBank->save(); + } + } + + return $piggyBank; + } public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank { @@ -70,4 +142,61 @@ class PiggyBankFactory { $this->user = $user; } + + private function getCurrency(array $data): TransactionCurrency { + // currency: + $defaultCurrency = app('amount')->getDefaultCurrency(); + $currency = null; + if (array_key_exists('transaction_currency_code', $data)) { + $currency = $this->currencyRepository->findByCode((string)($data['transaction_currency_code'] ?? '')); + } + if (array_key_exists('transaction_currency_id', $data)) { + $currency = $this->currencyRepository->find((int)($data['transaction_currency_id'] ?? 0)); + } + $currency ??= $defaultCurrency; + return $currency; + } + + private function setOrder(PiggyBank $piggyBank, array $data): PiggyBank { + $this->resetOrder(); + $order = $this->getMaxOrder() + 1; + if (array_key_exists('order', $data)) { + $order = $data['order']; + } + $piggyBank->order = $order; + $piggyBank->save(); + return $piggyBank; + + } + + private function resetOrder(): void + { + $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); + $current = 1; + foreach ($set as $piggyBank) { + if ($piggyBank->order !== $current) { + app('log')->debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); + $piggyBank->order = $current; + $piggyBank->save(); + } + ++$current; + } + } + + + private function getMaxOrder(): int + { + return (int)$this->user->piggyBanks()->max('piggy_banks.order'); + } + + private function linkToAccountIds(PiggyBank $piggyBank, array $accounts): void { + /** @var array $info */ + foreach($accounts as $info) { + $account = $this->accountRepository->find((int)($info['account_id'] ?? 0)); + if(null === $account) { + continue; + } + $piggyBank->accounts()->syncWithoutDetaching([$account->id, ['current_amount' => $info['current_amount'] ?? '0']]); + } + } } diff --git a/app/Http/Controllers/PiggyBank/IndexController.php b/app/Http/Controllers/PiggyBank/IndexController.php index 9c3578550e..9c08ebdf25 100644 --- a/app/Http/Controllers/PiggyBank/IndexController.php +++ b/app/Http/Controllers/PiggyBank/IndexController.php @@ -79,7 +79,7 @@ class IndexController extends Controller public function index() { $this->cleanupObjectGroups(); - $this->piggyRepos->resetOrder(); + //$this->piggyRepos->resetOrder(); $collection = $this->piggyRepos->getPiggyBanks(); $accounts = []; diff --git a/app/Models/PiggyBank.php b/app/Models/PiggyBank.php index 0edfa05b9e..911566e628 100644 --- a/app/Models/PiggyBank.php +++ b/app/Models/PiggyBank.php @@ -55,7 +55,7 @@ class PiggyBank extends Model 'target_amount' => 'string', ]; - protected $fillable = ['name', 'account_id', 'order', 'target_amount', 'start_date', 'start_date_tz', 'target_date', 'target_date_tz', 'active']; + protected $fillable = ['name', 'account_id', 'order', 'target_amount', 'start_date', 'start_date_tz', 'target_date', 'target_date_tz', 'active','transaction_currency_id']; /** * Route binder. Converts the key in the URL to the specified object (or throw 404). @@ -67,9 +67,9 @@ class PiggyBank extends Model if (auth()->check()) { $piggyBankId = (int)$value; $piggyBank = self::where('piggy_banks.id', $piggyBankId) - ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id') - ->where('accounts.user_id', auth()->user()->id)->first(['piggy_banks.*']) - ; + ->leftJoin('account_piggy_bank','account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') + ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') + ->where('accounts.user_id', auth()->user()->id)->first(['piggy_banks.*']); if (null !== $piggyBank) { return $piggyBank; } diff --git a/app/Repositories/Currency/CurrencyRepository.php b/app/Repositories/Currency/CurrencyRepository.php index 5ca4924769..97cb7ba79f 100644 --- a/app/Repositories/Currency/CurrencyRepository.php +++ b/app/Repositories/Currency/CurrencyRepository.php @@ -105,4 +105,9 @@ class CurrencyRepository implements CurrencyRepositoryInterface $this->user = $user; } } + + #[\Override] public function find(int $currencyId): ?TransactionCurrency + { + return TransactionCurrency::find($currencyId); + } } diff --git a/app/Repositories/Currency/CurrencyRepositoryInterface.php b/app/Repositories/Currency/CurrencyRepositoryInterface.php index e714977abb..b5fb7d7acb 100644 --- a/app/Repositories/Currency/CurrencyRepositoryInterface.php +++ b/app/Repositories/Currency/CurrencyRepositoryInterface.php @@ -42,6 +42,8 @@ interface CurrencyRepositoryInterface */ public function findByCode(string $currencyCode): ?TransactionCurrency; + public function find(int $currencyId): ?TransactionCurrency; + /** * Returns the complete set of transactions but needs * no user object. diff --git a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php index c5f9293c2e..998fed9b23 100644 --- a/app/Repositories/PiggyBank/ModifiesPiggyBanks.php +++ b/app/Repositories/PiggyBank/ModifiesPiggyBanks.php @@ -26,11 +26,14 @@ namespace FireflyIII\Repositories\PiggyBank; use FireflyIII\Events\Model\PiggyBank\ChangedAmount; use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Factory\PiggyBankFactory; use FireflyIII\Models\Note; use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBankRepetition; +use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups; +use FireflyIII\Support\Facades\Amount; use Illuminate\Database\QueryException; /** @@ -178,82 +181,11 @@ trait ModifiesPiggyBanks */ public function store(array $data): PiggyBank { - $order = $this->getMaxOrder() + 1; - if (array_key_exists('order', $data)) { - $order = $data['order']; - } - $data['order'] = 31337; // very high when creating. - $piggyData = $data; - // unset fields just in case. - unset($piggyData['object_group_title'], $piggyData['object_group_id'], $piggyData['notes'], $piggyData['current_amount']); - - // validate amount: - if (array_key_exists('targetamount', $piggyData) && '' === (string)$piggyData['targetamount']) { - $piggyData['targetamount'] = '0'; - } - - $piggyData['startdate_tz'] = $piggyData['startdate']?->format('e'); - $piggyData['targetdate_tz'] = $piggyData['targetdate']?->format('e'); - - try { - /** @var PiggyBank $piggyBank */ - $piggyBank = PiggyBank::create($piggyData); - } catch (QueryException $e) { - app('log')->error(sprintf('Could not store piggy bank: %s', $e->getMessage()), $piggyData); - - throw new FireflyException('400005: Could not store new piggy bank.', 0, $e); - } - - // reset order then set order: - $this->resetOrder(); - $this->setOrder($piggyBank, $order); - - $this->updateNote($piggyBank, $data['notes']); - - // repetition is auto created. - $repetition = $this->getRepetition($piggyBank); - if (null !== $repetition && array_key_exists('current_amount', $data) && '' !== $data['current_amount']) { - $repetition->current_amount = $data['current_amount']; - $repetition->save(); - } - - $objectGroupTitle = $data['object_group_title'] ?? ''; - if ('' !== $objectGroupTitle) { - $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); - if (null !== $objectGroup) { - $piggyBank->objectGroups()->sync([$objectGroup->id]); - $piggyBank->save(); - } - } - // try also with ID - $objectGroupId = (int)($data['object_group_id'] ?? 0); - if (0 !== $objectGroupId) { - $objectGroup = $this->findObjectGroupById($objectGroupId); - if (null !== $objectGroup) { - $piggyBank->objectGroups()->sync([$objectGroup->id]); - $piggyBank->save(); - } - } - - return $piggyBank; + $factory = new PiggyBankFactory(); + $factory->setUser($this->user); + return $factory->store($data); } - /** - * Correct order of piggies in case of issues. - */ - public function resetOrder(): void - { - $set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']); - $current = 1; - foreach ($set as $piggyBank) { - if ($piggyBank->order !== $current) { - app('log')->debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current)); - $piggyBank->order = $current; - $piggyBank->save(); - } - ++$current; - } - } public function setOrder(PiggyBank $piggyBank, int $newOrder): bool { @@ -282,13 +214,12 @@ trait ModifiesPiggyBanks return true; } - private function updateNote(PiggyBank $piggyBank, string $note): bool + public function updateNote(PiggyBank $piggyBank, string $note): void { if ('' === $note) { $dbNote = $piggyBank->notes()->first(); $dbNote?->delete(); - - return true; + return ; } $dbNote = $piggyBank->notes()->first(); if (null === $dbNote) { @@ -297,8 +228,6 @@ trait ModifiesPiggyBanks } $dbNote->text = trim($note); $dbNote->save(); - - return true; } public function update(PiggyBank $piggyBank, array $data): PiggyBank diff --git a/app/Repositories/PiggyBank/PiggyBankRepository.php b/app/Repositories/PiggyBank/PiggyBankRepository.php index b31571b043..1e9658d290 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepository.php +++ b/app/Repositories/PiggyBank/PiggyBankRepository.php @@ -240,10 +240,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface } } - public function getMaxOrder(): int - { - return (int)$this->user->piggyBanks()->max('piggy_banks.order'); - } /** * Return note for piggy bank. @@ -351,4 +347,9 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface return $search->take($limit)->get(); } + + #[\Override] public function purgeAll(): void + { + throw new FireflyException('TODO Not implemented'); + } } diff --git a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php index 7c1e12becc..dfe534f4cf 100644 --- a/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php +++ b/app/Repositories/PiggyBank/PiggyBankRepositoryInterface.php @@ -52,6 +52,8 @@ interface PiggyBankRepositoryInterface public function destroyAll(): void; + public function purgeAll(): void; + public function find(int $piggyBankId): ?PiggyBank; /** @@ -78,10 +80,7 @@ interface PiggyBankRepositoryInterface */ public function getExactAmount(PiggyBank $piggyBank, PiggyBankRepetition $repetition, TransactionJournal $journal): string; - /** - * Highest order of all piggy banks. - */ - public function getMaxOrder(): int; + public function updateNote(PiggyBank $piggyBank, string $note): void; /** * Return note for piggy bank. @@ -114,10 +113,10 @@ interface PiggyBankRepositoryInterface public function removeObjectGroup(PiggyBank $piggyBank): PiggyBank; - /** - * Correct order of piggies in case of issues. - */ - public function resetOrder(): void; +// /** +// * Correct order of piggies in case of issues. +// */ +// public function resetOrder(): void; /** * Search for piggy banks. @@ -133,7 +132,7 @@ interface PiggyBankRepositoryInterface */ public function setOrder(PiggyBank $piggyBank, int $newOrder): bool; - public function setUser(null|Authenticatable|User $user): void; + public function setUser(null | Authenticatable | User $user): void; /** * Store new piggy bank. diff --git a/app/Validation/FireflyValidator.php b/app/Validation/FireflyValidator.php index 95553306ff..136bc2f9a5 100644 --- a/app/Validation/FireflyValidator.php +++ b/app/Validation/FireflyValidator.php @@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; use FireflyIII\Models\AccountMeta; use FireflyIII\Models\AccountType; +use FireflyIII\Models\PiggyBank; use FireflyIII\Models\TransactionType; use FireflyIII\Models\Webhook; use FireflyIII\Repositories\Account\AccountRepositoryInterface; @@ -812,15 +813,15 @@ class FireflyValidator extends Validator public function validateUniquePiggyBankForUser($attribute, $value, $parameters): bool { $exclude = $parameters[0] ?? null; - $query = \DB::table('piggy_banks')->whereNull('piggy_banks.deleted_at') - ->leftJoin('accounts', 'accounts.id', '=', 'piggy_banks.account_id')->where('accounts.user_id', auth()->user()->id) - ; + $query = PiggyBank + ::leftJoin('account_piggy_bank','account_piggy_bank.piggy_bank_id', '=', 'piggy_banks.id') + ->leftJoin('accounts', 'accounts.id', '=', 'account_piggy_bank.account_id') + ->where('accounts.user_id', auth()->user()->id); if (null !== $exclude) { $query->where('piggy_banks.id', '!=', (int) $exclude); } $query->where('piggy_banks.name', $value); - - return null === $query->first(['piggy_banks.*']); + return 0 === $query->get(['piggy_banks.*'])->count(); } /** diff --git a/config/firefly.php b/config/firefly.php index 2b651de7d9..c13ef5ecbe 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -913,4 +913,7 @@ return [ // preselected account lists possibilities: 'preselected_accounts' => ['all', 'assets', 'liabilities'], + + // allowed to store a piggy bank in: + 'piggy_bank_account_types' => [AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value], ]; diff --git a/resources/lang/en_US/validation.php b/resources/lang/en_US/validation.php index bdf68a07fd..9f6dc2fe54 100644 --- a/resources/lang/en_US/validation.php +++ b/resources/lang/en_US/validation.php @@ -25,6 +25,7 @@ declare(strict_types=1); return [ + 'invalid_account_type' => 'A piggy bank can only be linked to asset accounts and liabilities', 'filter_must_be_in' => 'Filter ":filter" must be one of: :values', 'filter_not_string' => 'Filter ":filter" is expected to be a string of text', 'bad_api_filter' => 'This API endpoint does not support ":filter" as a filter.', diff --git a/routes/api.php b/routes/api.php index 750450b257..ec16affdd9 100644 --- a/routes/api.php +++ b/routes/api.php @@ -615,6 +615,7 @@ Route::group( Route::get('{piggyBank}/events', ['uses' => 'ListController@piggyBankEvents', 'as' => 'events']); Route::get('{piggyBank}/attachments', ['uses' => 'ListController@attachments', 'as' => 'attachments']); + Route::get('{piggyBank}/accounts', ['uses' => 'ListController@accounts', 'as' => 'accounts']); } );