Expand piggy bank events.

This commit is contained in:
James Cole
2025-08-05 19:49:13 +02:00
parent 1921a8050b
commit c8c552602e
12 changed files with 209 additions and 39 deletions

View File

@@ -125,7 +125,7 @@ class ListController extends Controller
$transformer = app(PiggyBankTransformer::class); $transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Category\StoreRequest; use FireflyIII\Api\V1\Requests\Models\Category\StoreRequest;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment;
use FireflyIII\Transformers\CategoryTransformer; use FireflyIII\Transformers\CategoryTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -72,6 +74,15 @@ class StoreController extends Controller
$transformer = app(CategoryTransformer::class); $transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters); $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'); $resource = new Item($category, $transformer, 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\Models\Category\UpdateRequest; use FireflyIII\Api\V1\Requests\Models\Category\UpdateRequest;
use FireflyIII\Models\Category; use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment;
use FireflyIII\Transformers\CategoryTransformer; use FireflyIII\Transformers\CategoryTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item; use League\Fractal\Resource\Item;
@@ -71,6 +73,15 @@ class UpdateController extends Controller
$transformer = app(CategoryTransformer::class); $transformer = app(CategoryTransformer::class);
$transformer->setParameters($this->parameters); $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'); $resource = new Item($category, $transformer, 'categories');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -132,7 +132,7 @@ class ListController extends Controller
$transformer = app(PiggyBankTransformer::class); $transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank; use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface; use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment; use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment;
use FireflyIII\Transformers\AccountTransformer; use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer;
@@ -148,6 +149,13 @@ class ListController extends Controller
$count = $collection->count(); $count = $collection->count();
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $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: // make paginator:
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.piggy-banks.events', [$piggyBank->id]).$this->buildParams()); $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 = app(PiggyBankEventTransformer::class);
$transformer->setParameters($this->parameters); $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)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);

View File

@@ -85,7 +85,7 @@ class ShowController extends Controller
$transformer = app(PiggyBankTransformer::class); $transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters); $transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks'); $resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE); 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 = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters); $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); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
} }

View File

@@ -76,7 +76,7 @@ class UpdateController extends Controller
$transformer = app(PiggyBankTransformer::class); $transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters); $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); return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
} }

View File

@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup; use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface; use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface;
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment;
use FireflyIII\Transformers\AttachmentTransformer; use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\Transformers\PiggyBankEventTransformer; use FireflyIII\Transformers\PiggyBankEventTransformer;
use FireflyIII\Transformers\TransactionLinkTransformer; use FireflyIII\Transformers\TransactionLinkTransformer;
@@ -113,6 +114,14 @@ class ListController extends Controller
} }
$count = $collection->count(); $count = $collection->count();
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); $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: // make paginator:
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page')); $paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.transactions.piggy-bank-events', [$transactionGroup->id]).$this->buildParams()); $paginator->setPath(route('api.v1.transactions.piggy-bank-events', [$transactionGroup->id]).$this->buildParams());

View File

@@ -0,0 +1,129 @@
<?php
namespace FireflyIII\Support\JsonApi\Enrichments;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\UserGroup;
use FireflyIII\Support\Facades\Amount;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class PiggyBankEventEnrichment implements EnrichmentInterface
{
private User $user;
private UserGroup $userGroup;
private Collection $collection;
private array $ids = [];
private array $journalIds = [];
private array $groupIds = [];
private array $accountIds = [];
private array $piggybankIds = [];
private array $accountCurrencies = [];
private array $currencies = [];
//private bool $convertToPrimary = false;
//private TransactionCurrency $primaryCurrency;
public function __construct()
{
//$this->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;
});
}
}

View File

@@ -59,9 +59,8 @@ class CategoryTransformer extends AbstractTransformer
// category never has currency settings. // category never has currency settings.
'object_has_currency_setting' => false, 'object_has_currency_setting' => false,
'primary_currency_id' => (string)$this->primaryCurrency->id, 'primary_currency_id' => (string)$this->primaryCurrency->id,
'primary_currency_name' => $this->primaryCurrency->name,
'primary_currency_code' => $this->primaryCurrency->code, 'primary_currency_code' => $this->primaryCurrency->code,
'primary_currency_symbol' => $this->primaryCurrency->symbol, 'primary_currency_symbol' => $this->primaryCurrency->symbol,
'primary_currency_decimal_places' => (int)$this->primaryCurrency->decimal_places, 'primary_currency_decimal_places' => (int)$this->primaryCurrency->decimal_places,
@@ -74,7 +73,7 @@ class CategoryTransformer extends AbstractTransformer
'links' => [ 'links' => [
[ [
'rel' => 'self', 'rel' => 'self',
'uri' => '/categories/'.$category->id, 'uri' => '/categories/' . $category->id,
], ],
], ],
]; ];

View File

@@ -26,8 +26,7 @@ namespace FireflyIII\Transformers;
use FireflyIII\Exceptions\FireflyException; use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBankEvent; use FireflyIII\Models\PiggyBankEvent;
use FireflyIII\Repositories\Account\AccountRepositoryInterface; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Support\Facades\Amount; use FireflyIII\Support\Facades\Amount;
use FireflyIII\Support\Facades\Steam; use FireflyIII\Support\Facades\Steam;
@@ -36,16 +35,16 @@ use FireflyIII\Support\Facades\Steam;
*/ */
class PiggyBankEventTransformer extends AbstractTransformer class PiggyBankEventTransformer extends AbstractTransformer
{ {
private readonly PiggyBankRepositoryInterface $piggyRepos; private TransactionCurrency $primaryCurrency;
private readonly AccountRepositoryInterface $repository; private bool $convertToPrimary = false;
/** /**
* PiggyBankEventTransformer constructor. * PiggyBankEventTransformer constructor.
*/ */
public function __construct() public function __construct()
{ {
$this->repository = app(AccountRepositoryInterface::class); $this->primaryCurrency = Amount::getPrimaryCurrency();
$this->piggyRepos = app(PiggyBankRepositoryInterface::class); $this->convertToPrimary = Amount::convertToPrimary();
} }
/** /**
@@ -55,39 +54,43 @@ class PiggyBankEventTransformer extends AbstractTransformer
*/ */
public function transform(PiggyBankEvent $event): array public function transform(PiggyBankEvent $event): array
{ {
// get account linked to piggy bank $currency = $event->meta['currency'] ?? $this->primaryCurrency;
$account = $event->piggyBank->accounts()->first(); $amount = Steam::bcround($event->amount, $currency->decimal_places);
$primaryAmount = null;
// set up repositories. if ($this->convertToPrimary && $currency->id === $this->primaryCurrency->id) {
$this->repository->setUser($account->user); $primaryAmount = $amount;
$this->piggyRepos->setUser($account->user); }
if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) {
// get associated currency or fall back to the default: $primaryAmount = Steam::bcround($event->native_amount, $this->primaryCurrency->decimal_places);
$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;
} }
return [ return [
'id' => (string) $event->id, 'id' => (string)$event->id,
'created_at' => $event->created_at?->toAtomString(), 'created_at' => $event->created_at?->toAtomString(),
'updated_at' => $event->updated_at?->toAtomString(), 'updated_at' => $event->updated_at?->toAtomString(),
'amount' => Steam::bcround($event->amount, $currency->decimal_places), 'amount' => $amount,
'currency_id' => (string) $currency->id, '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_code' => $currency->code,
'currency_symbol' => $currency->symbol, 'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places, 'currency_decimal_places' => $currency->decimal_places,
'transaction_journal_id' => null !== $journalId ? (string) $journalId : null,
'transaction_group_id' => null !== $groupId ? (string) $groupId : null, 'primary_currency_id' => (string)$this->primaryCurrency->id,
'links' => [ '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', 'rel' => 'self',
'uri' => '/piggy_bank_events/'.$event->id, 'uri' => sprintf('/piggy-banks/%d/events/%s', $event->piggy_bank_id, $event->id),
], ],
], ],
]; ];

View File

@@ -122,7 +122,7 @@ class PiggyBankTransformer extends AbstractTransformer
'links' => [ 'links' => [
[ [
'rel' => 'self', 'rel' => 'self',
'uri' => '/piggy_banks/'.$piggyBank->id, 'uri' => '/piggy-banks/'.$piggyBank->id,
], ],
], ],
]; ];