From c8c552602e299bd8fa88e3e5976269ed29bd4d28 Mon Sep 17 00:00:00 2001 From: James Cole Date: Tue, 5 Aug 2025 19:49:13 +0200 Subject: [PATCH] Expand piggy bank events. --- .../Models/Account/ListController.php | 2 +- .../Models/Category/StoreController.php | 11 ++ .../Models/Category/UpdateController.php | 11 ++ .../Models/ObjectGroup/ListController.php | 2 +- .../Models/PiggyBank/ListController.php | 10 +- .../Models/PiggyBank/ShowController.php | 4 +- .../Models/PiggyBank/UpdateController.php | 2 +- .../Models/Transaction/ListController.php | 9 ++ .../Enrichments/PiggyBankEventEnrichment.php | 129 ++++++++++++++++++ app/Transformers/CategoryTransformer.php | 5 +- .../PiggyBankEventTransformer.php | 61 +++++---- app/Transformers/PiggyBankTransformer.php | 2 +- 12 files changed, 209 insertions(+), 39 deletions(-) create mode 100644 app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php diff --git a/app/Api/V1/Controllers/Models/Account/ListController.php b/app/Api/V1/Controllers/Models/Account/ListController.php index 777698361b..aca662f3e6 100644 --- a/app/Api/V1/Controllers/Models/Account/ListController.php +++ b/app/Api/V1/Controllers/Models/Account/ListController.php @@ -125,7 +125,7 @@ class ListController extends Controller $transformer = app(PiggyBankTransformer::class); $transformer->setParameters($this->parameters); - $resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); + $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks'); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/Category/StoreController.php b/app/Api/V1/Controllers/Models/Category/StoreController.php index 0ed614e0fb..99d53fcb5d 100644 --- a/app/Api/V1/Controllers/Models/Category/StoreController.php +++ b/app/Api/V1/Controllers/Models/Category/StoreController.php @@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Requests\Models\Category\StoreRequest; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment; use FireflyIII\Transformers\CategoryTransformer; +use FireflyIII\User; use Illuminate\Http\JsonResponse; use League\Fractal\Resource\Item; @@ -72,6 +74,15 @@ class StoreController extends Controller $transformer = app(CategoryTransformer::class); $transformer->setParameters($this->parameters); + // enrich + /** @var User $admin */ + $admin = auth()->user(); + $enrichment = new CategoryEnrichment(); + $enrichment->setUser($admin); + $enrichment->setStart($this->parameters->get('start')); + $enrichment->setEnd($this->parameters->get('end')); + $category = $enrichment->enrichSingle($category); + $resource = new Item($category, $transformer, 'categories'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/Category/UpdateController.php b/app/Api/V1/Controllers/Models/Category/UpdateController.php index 8035d7f821..bcb82e927a 100644 --- a/app/Api/V1/Controllers/Models/Category/UpdateController.php +++ b/app/Api/V1/Controllers/Models/Category/UpdateController.php @@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller; use FireflyIII\Api\V1\Requests\Models\Category\UpdateRequest; use FireflyIII\Models\Category; use FireflyIII\Repositories\Category\CategoryRepositoryInterface; +use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment; use FireflyIII\Transformers\CategoryTransformer; +use FireflyIII\User; use Illuminate\Http\JsonResponse; use League\Fractal\Resource\Item; @@ -71,6 +73,15 @@ class UpdateController extends Controller $transformer = app(CategoryTransformer::class); $transformer->setParameters($this->parameters); + // enrich + /** @var User $admin */ + $admin = auth()->user(); + $enrichment = new CategoryEnrichment(); + $enrichment->setUser($admin); + $enrichment->setStart($this->parameters->get('start')); + $enrichment->setEnd($this->parameters->get('end')); + $category = $enrichment->enrichSingle($category); + $resource = new Item($category, $transformer, 'categories'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php index cdda960026..73cd0ab303 100644 --- a/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php +++ b/app/Api/V1/Controllers/Models/ObjectGroup/ListController.php @@ -132,7 +132,7 @@ class ListController extends Controller $transformer = app(PiggyBankTransformer::class); $transformer->setParameters($this->parameters); - $resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); + $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks'); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php index 5e7fe7decb..4b934470af 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ListController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ListController.php @@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\PiggyBank; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment; +use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment; use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer; @@ -148,6 +149,13 @@ class ListController extends Controller $count = $collection->count(); $events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + // enrich + /** @var User $admin */ + $admin = auth()->user(); + $enrichment = new PiggyBankEventEnrichment(); + $enrichment->setUser($admin); + $events = $enrichment->enrich($events); + // make paginator: $paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); $paginator->setPath(route('api.v1.piggy-banks.events', [$piggyBank->id]).$this->buildParams()); @@ -156,7 +164,7 @@ class ListController extends Controller $transformer = app(PiggyBankEventTransformer::class); $transformer->setParameters($this->parameters); - $resource = new FractalCollection($events, $transformer, 'piggy_bank_events'); + $resource = new FractalCollection($events, $transformer, sprintf('piggy-banks/%d/events', $piggyBank->id)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); diff --git a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php index 442b47cb38..2a1cfd36ad 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/ShowController.php @@ -85,7 +85,7 @@ class ShowController extends Controller $transformer = app(PiggyBankTransformer::class); $transformer->setParameters($this->parameters); - $resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); + $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks'); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); @@ -105,7 +105,7 @@ class ShowController extends Controller $transformer = app(PiggyBankTransformer::class); $transformer->setParameters($this->parameters); - $resource = new Item($piggyBank, $transformer, 'piggy_banks'); + $resource = new Item($piggyBank, $transformer, 'piggy-banks'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); } diff --git a/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php b/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php index 25d2d1b187..09f4defad1 100644 --- a/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php +++ b/app/Api/V1/Controllers/Models/PiggyBank/UpdateController.php @@ -76,7 +76,7 @@ class UpdateController extends Controller $transformer = app(PiggyBankTransformer::class); $transformer->setParameters($this->parameters); - $resource = new Item($piggyBank, $transformer, 'piggy_banks'); + $resource = new Item($piggyBank, $transformer, 'piggy-banks'); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); } diff --git a/app/Api/V1/Controllers/Models/Transaction/ListController.php b/app/Api/V1/Controllers/Models/Transaction/ListController.php index f5aa1c81f4..39ef1a2c4e 100644 --- a/app/Api/V1/Controllers/Models/Transaction/ListController.php +++ b/app/Api/V1/Controllers/Models/Transaction/ListController.php @@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionJournal; use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface; +use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment; use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\TransactionLinkTransformer; @@ -113,6 +114,14 @@ class ListController extends Controller } $count = $collection->count(); $events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // enrich + /** @var User $admin */ + $admin = auth()->user(); + $enrichment = new PiggyBankEventEnrichment(); + $enrichment->setUser($admin); + $events = $enrichment->enrich($events); + // make paginator: $paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); $paginator->setPath(route('api.v1.transactions.piggy-bank-events', [$transactionGroup->id]).$this->buildParams()); diff --git a/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php b/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php new file mode 100644 index 0000000000..d92cf8f14b --- /dev/null +++ b/app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php @@ -0,0 +1,129 @@ +convertToPrimary = Amount::convertToPrimary(); + //$this->primaryCurrency = Amount::getPrimaryCurrency(); + } + + public function enrich(Collection $collection): Collection + { + $this->collection = $collection; + $this->collectIds(); + $this->appendCollectedData(); + + return $this->collection; + } + + public function enrichSingle(Model|array $model): array|Model + { + Log::debug(__METHOD__); + $collection = new Collection([$model]); + $collection = $this->enrich($collection); + + return $collection->first(); + } + + public function setUser(User $user): void + { + $this->user = $user; + $this->setUserGroup($user->userGroup); + } + + public function setUserGroup(UserGroup $userGroup): void + { + $this->userGroup = $userGroup; + } + + private function collectIds(): void + { + /** @var PiggyBankEvent $event */ + foreach ($this->collection as $event) { + $this->ids[] = (int)$event->id; + $this->journalIds[(int)$event->id] = (int)$event->transaction_journal_id; + $this->piggybankIds[(int)$event->id] = (int)$event->piggy_bank_id; + } + $this->ids = array_unique($this->ids); + // collect groups with journal info. + $set = TransactionJournal::whereIn('id', $this->journalIds)->get(['id', 'transaction_group_id']); + /** @var TransactionJournal $item */ + foreach ($set as $item) { + $this->groupIds[(int)$item->id] = (int)$item->transaction_group_id; + } + + // collect account info. + $set = DB::table('account_piggy_bank')->whereIn('piggy_bank_id', $this->piggybankIds)->get(['piggy_bank_id', 'account_id']); + foreach ($set as $item) { + $id = (int)$item->piggy_bank_id; + if (!array_key_exists($id, $this->accountIds)) { + $this->accountIds[$id] = (int)$item->account_id; + } + } + + // get account currency preference for ALL. + $set = AccountMeta::whereIn('account_id', array_values($this->accountIds))->where('name', 'currency_id')->get(); + /** @var AccountMeta $item */ + foreach ($set as $item) { + $accountId = (int)$item->account_id; + $currencyId = (int)$item->data; + if (!array_key_exists($currencyId, $this->currencies)) { + $this->currencies[$currencyId] = TransactionCurrency::find($currencyId); + } + $this->accountCurrencies[$accountId] = $this->currencies[$currencyId]; + } + } + + private function appendCollectedData(): void + { + $this->collection = $this->collection->map(function (PiggyBankEvent $item) { + $id = (int)$item->id; + $piggyId = (int)$item->piggy_bank_id; + $journalId = (int)$item->transaction_journal_id; + $currency = null; + if (array_key_exists($piggyId, $this->accountIds)) { + $accountId = $this->accountIds[$piggyId]; + if (array_key_exists($accountId, $this->accountCurrencies)) { + $currency = $this->accountCurrencies[$accountId]; + } + } + $meta = [ + 'transaction_group_id' => array_key_exists($journalId, $this->groupIds) ? (string)$this->groupIds[$journalId] : null, + 'currency' => $currency, + ]; + $item->meta = $meta; + + return $item; + }); + + } +} diff --git a/app/Transformers/CategoryTransformer.php b/app/Transformers/CategoryTransformer.php index 5f6dd0d141..1f8ffdbaad 100644 --- a/app/Transformers/CategoryTransformer.php +++ b/app/Transformers/CategoryTransformer.php @@ -59,9 +59,8 @@ class CategoryTransformer extends AbstractTransformer // category never has currency settings. 'object_has_currency_setting' => false, - - 'primary_currency_id' => (string)$this->primaryCurrency->id, + 'primary_currency_name' => $this->primaryCurrency->name, 'primary_currency_code' => $this->primaryCurrency->code, 'primary_currency_symbol' => $this->primaryCurrency->symbol, 'primary_currency_decimal_places' => (int)$this->primaryCurrency->decimal_places, @@ -74,7 +73,7 @@ class CategoryTransformer extends AbstractTransformer 'links' => [ [ 'rel' => 'self', - 'uri' => '/categories/'.$category->id, + 'uri' => '/categories/' . $category->id, ], ], ]; diff --git a/app/Transformers/PiggyBankEventTransformer.php b/app/Transformers/PiggyBankEventTransformer.php index d69c03645f..7bdd9fd1fb 100644 --- a/app/Transformers/PiggyBankEventTransformer.php +++ b/app/Transformers/PiggyBankEventTransformer.php @@ -26,8 +26,7 @@ namespace FireflyIII\Transformers; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\PiggyBankEvent; -use FireflyIII\Repositories\Account\AccountRepositoryInterface; -use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; +use FireflyIII\Models\TransactionCurrency; use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Steam; @@ -36,16 +35,16 @@ use FireflyIII\Support\Facades\Steam; */ class PiggyBankEventTransformer extends AbstractTransformer { - private readonly PiggyBankRepositoryInterface $piggyRepos; - private readonly AccountRepositoryInterface $repository; + private TransactionCurrency $primaryCurrency; + private bool $convertToPrimary = false; /** * PiggyBankEventTransformer constructor. */ public function __construct() { - $this->repository = app(AccountRepositoryInterface::class); - $this->piggyRepos = app(PiggyBankRepositoryInterface::class); + $this->primaryCurrency = Amount::getPrimaryCurrency(); + $this->convertToPrimary = Amount::convertToPrimary(); } /** @@ -55,39 +54,43 @@ class PiggyBankEventTransformer extends AbstractTransformer */ public function transform(PiggyBankEvent $event): array { - // get account linked to piggy bank - $account = $event->piggyBank->accounts()->first(); - - // set up repositories. - $this->repository->setUser($account->user); - $this->piggyRepos->setUser($account->user); - - // get associated currency or fall back to the default: - $currency = $this->repository->getAccountCurrency($account) ?? Amount::getPrimaryCurrencyByUserGroup($account->user->userGroup); - - // get associated journal and transaction, if any: - $journalId = $event->transaction_journal_id; - $groupId = null; - if (0 !== (int) $journalId) { - $groupId = (int) $event->transactionJournal->transaction_group_id; - $journalId = (int) $journalId; + $currency = $event->meta['currency'] ?? $this->primaryCurrency; + $amount = Steam::bcround($event->amount, $currency->decimal_places); + $primaryAmount = null; + if ($this->convertToPrimary && $currency->id === $this->primaryCurrency->id) { + $primaryAmount = $amount; + } + if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) { + $primaryAmount = Steam::bcround($event->native_amount, $this->primaryCurrency->decimal_places); } return [ - 'id' => (string) $event->id, + 'id' => (string)$event->id, 'created_at' => $event->created_at?->toAtomString(), 'updated_at' => $event->updated_at?->toAtomString(), - 'amount' => Steam::bcround($event->amount, $currency->decimal_places), - 'currency_id' => (string) $currency->id, + 'amount' => $amount, + 'pc_amount' => $primaryAmount, + + // currencies according to 6.3.0 + 'has_currency_setting' => true, + 'currency_id' => (string)$currency->id, + 'currency_name' => $currency->name, 'currency_code' => $currency->code, 'currency_symbol' => $currency->symbol, 'currency_decimal_places' => $currency->decimal_places, - 'transaction_journal_id' => null !== $journalId ? (string) $journalId : null, - 'transaction_group_id' => null !== $groupId ? (string) $groupId : null, - 'links' => [ + + 'primary_currency_id' => (string)$this->primaryCurrency->id, + 'primary_currency_name' => $this->primaryCurrency->name, + 'primary_currency_code' => $this->primaryCurrency->code, + 'primary_currency_symbol' => $this->primaryCurrency->symbol, + 'primary_currency_decimal_places' => $this->primaryCurrency->decimal_places, + + 'transaction_journal_id' => null !== $event->transaction_journal_id ? (string)$event->transaction_journal_id : null, + 'transaction_group_id' => $event->meta['transaction_group_id'], + 'links' => [ [ 'rel' => 'self', - 'uri' => '/piggy_bank_events/'.$event->id, + 'uri' => sprintf('/piggy-banks/%d/events/%s', $event->piggy_bank_id, $event->id), ], ], ]; diff --git a/app/Transformers/PiggyBankTransformer.php b/app/Transformers/PiggyBankTransformer.php index d497b04e2c..84c9c64186 100644 --- a/app/Transformers/PiggyBankTransformer.php +++ b/app/Transformers/PiggyBankTransformer.php @@ -122,7 +122,7 @@ class PiggyBankTransformer extends AbstractTransformer 'links' => [ [ 'rel' => 'self', - 'uri' => '/piggy_banks/'.$piggyBank->id, + 'uri' => '/piggy-banks/'.$piggyBank->id, ], ], ];